2 * Copyright (C) 2013-2015 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 "FTLLowerDFGToLLVM.h"
31 #include "CodeBlockWithJITType.h"
32 #include "DFGAbstractInterpreterInlines.h"
33 #include "DFGInPlaceAbstractState.h"
34 #include "DFGOSRAvailabilityAnalysisPhase.h"
35 #include "DFGOSRExitFuzz.h"
36 #include "DirectArguments.h"
37 #include "FTLAbstractHeapRepository.h"
38 #include "FTLAvailableRecovery.h"
39 #include "FTLForOSREntryJITCode.h"
40 #include "FTLFormattedValue.h"
41 #include "FTLInlineCacheSize.h"
42 #include "FTLLoweredNodeValue.h"
43 #include "FTLOperations.h"
44 #include "FTLOutput.h"
45 #include "FTLThunks.h"
46 #include "FTLWeightedTarget.h"
47 #include "JSCInlines.h"
48 #include "JSLexicalEnvironment.h"
49 #include "OperandsInlines.h"
50 #include "ScopedArguments.h"
51 #include "ScopedArgumentsTable.h"
52 #include "VirtualRegister.h"
55 #include <llvm/InitializeLLVM.h>
56 #include <unordered_set>
57 #include <wtf/ProcessID.h>
59 #if ENABLE(FTL_NATIVE_CALL_INLINING)
60 #include "BundlePath.h"
63 namespace JSC { namespace FTL {
69 std::atomic<int> compileCounter;
72 NO_RETURN_DUE_TO_CRASH static void ftlUnreachable()
77 NO_RETURN_DUE_TO_CRASH static void ftlUnreachable(
78 CodeBlock* codeBlock, BlockIndex blockIndex, unsigned nodeIndex)
80 dataLog("Crashing in thought-to-be-unreachable FTL-generated code for ", pointerDump(codeBlock), " at basic block #", blockIndex);
81 if (nodeIndex != UINT_MAX)
82 dataLog(", node @", nodeIndex);
88 // Using this instead of typeCheck() helps to reduce the load on LLVM, by creating
89 // significantly less dead code.
90 #define FTL_TYPE_CHECK(lowValue, highValue, typesPassedThrough, failCondition) do { \
91 FormattedValue _ftc_lowValue = (lowValue); \
92 Edge _ftc_highValue = (highValue); \
93 SpeculatedType _ftc_typesPassedThrough = (typesPassedThrough); \
94 if (!m_interpreter.needsTypeCheck(_ftc_highValue, _ftc_typesPassedThrough)) \
96 typeCheck(_ftc_lowValue, _ftc_highValue, _ftc_typesPassedThrough, (failCondition)); \
99 class LowerDFGToLLVM {
101 LowerDFGToLLVM(State& state)
102 : m_graph(state.graph)
104 , m_heaps(state.context)
105 , m_out(state.context)
106 , m_state(state.graph)
107 , m_interpreter(state.graph, m_state)
109 , m_tbaaKind(mdKindID(state.context, "tbaa"))
110 , m_tbaaStructKind(mdKindID(state.context, "tbaa.struct"))
117 if (verboseCompilationEnabled()) {
119 "jsBody_", ++compileCounter, "_", codeBlock()->inferredName(),
120 "_", codeBlock()->hash());
124 m_graph.m_dominators.computeIfNecessary(m_graph);
127 moduleCreateWithNameInContext(name.data(), m_ftlState.context);
129 m_ftlState.function = addFunction(
130 m_ftlState.module, name.data(), functionType(m_out.int64));
131 setFunctionCallingConv(m_ftlState.function, LLVMCCallConv);
132 if (isX86() && Options::llvmDisallowAVX()) {
133 // AVX makes V8/raytrace 80% slower. It makes Kraken/audio-oscillator 4.5x
134 // slower. It should be disabled.
135 addTargetDependentFunctionAttr(m_ftlState.function, "target-features", "-avx");
138 if (verboseCompilationEnabled())
139 dataLog("Function ready, beginning lowering.\n");
141 m_out.initialize(m_ftlState.module, m_ftlState.function, m_heaps);
143 m_prologue = FTL_NEW_BLOCK(m_out, ("Prologue"));
144 LBasicBlock stackOverflow = FTL_NEW_BLOCK(m_out, ("Stack overflow"));
145 m_handleExceptions = FTL_NEW_BLOCK(m_out, ("Handle Exceptions"));
147 LBasicBlock checkArguments = FTL_NEW_BLOCK(m_out, ("Check arguments"));
149 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
150 m_highBlock = m_graph.block(blockIndex);
153 m_blocks.add(m_highBlock, FTL_NEW_BLOCK(m_out, ("Block ", *m_highBlock)));
156 m_out.appendTo(m_prologue, stackOverflow);
157 createPhiVariables();
159 auto preOrder = m_graph.blocksInPreOrder();
161 int maxNumberOfArguments = -1;
162 for (BasicBlock* block : preOrder) {
163 for (unsigned nodeIndex = block->size(); nodeIndex--; ) {
164 Node* node = block->at(nodeIndex);
165 switch (node->op()) {
167 case NativeConstruct: {
168 int numArgs = node->numChildren();
169 if (numArgs > maxNumberOfArguments)
170 maxNumberOfArguments = numArgs;
179 if (maxNumberOfArguments >= 0) {
180 m_execState = m_out.alloca(arrayType(m_out.int64, JSStack::CallFrameHeaderSize + maxNumberOfArguments));
181 m_execStorage = m_out.ptrToInt(m_execState, m_out.intPtr);
184 LValue capturedAlloca = m_out.alloca(arrayType(m_out.int64, m_graph.m_nextMachineLocal));
186 m_captured = m_out.add(
187 m_out.ptrToInt(capturedAlloca, m_out.intPtr),
188 m_out.constIntPtr(m_graph.m_nextMachineLocal * sizeof(Register)));
190 m_ftlState.capturedStackmapID = m_stackmapIDs++;
192 m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.capturedStackmapID),
193 m_out.int32Zero, capturedAlloca);
195 // If we have any CallVarargs then we nee to have a spill slot for it.
196 bool hasVarargs = false;
197 for (BasicBlock* block : preOrder) {
198 for (Node* node : *block) {
199 switch (node->op()) {
201 case CallForwardVarargs:
202 case ConstructVarargs:
203 case ConstructForwardVarargs:
212 LValue varargsSpillSlots = m_out.alloca(
213 arrayType(m_out.int64, JSCallVarargs::numSpillSlotsNeeded()));
214 m_ftlState.varargsSpillSlotsStackmapID = m_stackmapIDs++;
216 m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.varargsSpillSlotsStackmapID),
217 m_out.int32Zero, varargsSpillSlots);
220 // We should not create any alloca's after this point, since they will cease to
221 // be mem2reg candidates.
223 m_callFrame = m_out.ptrToInt(
224 m_out.call(m_out.frameAddressIntrinsic(), m_out.int32Zero), m_out.intPtr);
225 m_tagTypeNumber = m_out.constInt64(TagTypeNumber);
226 m_tagMask = m_out.constInt64(TagMask);
228 m_out.storePtr(m_out.constIntPtr(codeBlock()), addressFor(JSStack::CodeBlock));
231 didOverflowStack(), rarely(stackOverflow), usually(checkArguments));
233 m_out.appendTo(stackOverflow, m_handleExceptions);
234 m_out.call(m_out.operation(operationThrowStackOverflowError), m_callFrame, m_out.constIntPtr(codeBlock()));
235 m_ftlState.handleStackOverflowExceptionStackmapID = m_stackmapIDs++;
237 m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.handleStackOverflowExceptionStackmapID),
238 m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
241 m_out.appendTo(m_handleExceptions, checkArguments);
242 m_ftlState.handleExceptionStackmapID = m_stackmapIDs++;
244 m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.handleExceptionStackmapID),
245 m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
248 m_out.appendTo(checkArguments, lowBlock(m_graph.block(0)));
249 availabilityMap().clear();
250 availabilityMap().m_locals = Operands<Availability>(codeBlock()->numParameters(), 0);
251 for (unsigned i = codeBlock()->numParameters(); i--;) {
252 availabilityMap().m_locals.argument(i) =
253 Availability(FlushedAt(FlushedJSValue, virtualRegisterForArgument(i)));
255 m_codeOriginForExitTarget = CodeOrigin(0);
256 m_codeOriginForExitProfile = CodeOrigin(0);
258 for (unsigned i = codeBlock()->numParameters(); i--;) {
259 Node* node = m_graph.m_arguments[i];
260 VirtualRegister operand = virtualRegisterForArgument(i);
262 LValue jsValue = m_out.load64(addressFor(operand));
265 DFG_ASSERT(m_graph, node, operand == node->stackAccessData()->machineLocal);
267 // This is a hack, but it's an effective one. It allows us to do CSE on the
268 // primordial load of arguments. This assumes that the GetLocal that got put in
269 // place of the original SetArgument doesn't have any effects before it. This
271 m_loadedArgumentValues.add(node, jsValue);
274 switch (m_graph.m_argumentFormats[i]) {
276 speculate(BadType, jsValueValue(jsValue), node, isNotInt32(jsValue));
279 speculate(BadType, jsValueValue(jsValue), node, isNotBoolean(jsValue));
282 speculate(BadType, jsValueValue(jsValue), node, isNotCell(jsValue));
287 DFG_CRASH(m_graph, node, "Bad flush format for argument");
291 m_out.jump(lowBlock(m_graph.block(0)));
293 for (BasicBlock* block : preOrder)
296 if (Options::dumpLLVMIR())
297 dumpModule(m_ftlState.module);
299 if (verboseCompilationEnabled())
300 m_ftlState.dumpState("after lowering");
301 if (validationEnabled())
302 verifyModule(m_ftlState.module);
307 void createPhiVariables()
309 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
310 BasicBlock* block = m_graph.block(blockIndex);
313 for (unsigned nodeIndex = block->size(); nodeIndex--;) {
314 Node* node = block->at(nodeIndex);
315 if (node->op() != Phi)
318 switch (node->flags() & NodeResultMask) {
319 case NodeResultDouble:
320 type = m_out.doubleType;
322 case NodeResultInt32:
325 case NodeResultInt52:
328 case NodeResultBoolean:
329 type = m_out.boolean;
335 DFG_CRASH(m_graph, node, "Bad Phi node result type");
338 m_phis.add(node, buildAlloca(m_out.m_builder, type));
343 void compileBlock(BasicBlock* block)
348 if (verboseCompilationEnabled())
349 dataLog("Compiling block ", *block, "\n");
353 LBasicBlock lowBlock = m_blocks.get(m_highBlock);
356 for (BlockIndex nextBlockIndex = m_highBlock->index + 1; nextBlockIndex < m_graph.numBlocks(); ++nextBlockIndex) {
357 m_nextHighBlock = m_graph.block(nextBlockIndex);
361 m_nextLowBlock = m_nextHighBlock ? m_blocks.get(m_nextHighBlock) : 0;
363 // All of this effort to find the next block gives us the ability to keep the
364 // generated IR in roughly program order. This ought not affect the performance
365 // of the generated code (since we expect LLVM to reorder things) but it will
366 // make IR dumps easier to read.
367 m_out.appendTo(lowBlock, m_nextLowBlock);
369 if (Options::ftlCrashes())
372 if (!m_highBlock->cfaHasVisited) {
373 if (verboseCompilationEnabled())
374 dataLog("Bailing because CFA didn't reach.\n");
375 crash(m_highBlock->index, UINT_MAX);
379 m_availabilityCalculator.beginBlock(m_highBlock);
382 m_state.beginBasicBlock(m_highBlock);
384 for (m_nodeIndex = 0; m_nodeIndex < m_highBlock->size(); ++m_nodeIndex) {
385 if (!compileNode(m_nodeIndex))
390 void safelyInvalidateAfterTermination()
392 if (verboseCompilationEnabled())
393 dataLog("Bailing.\n");
396 // Invalidate dominated blocks. Under normal circumstances we would expect
397 // them to be invalidated already. But you can have the CFA become more
398 // precise over time because the structures of objects change on the main
399 // thread. Failing to do this would result in weird crashes due to a value
400 // being used but not defined. Race conditions FTW!
401 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
402 BasicBlock* target = m_graph.block(blockIndex);
405 if (m_graph.m_dominators.dominates(m_highBlock, target)) {
406 if (verboseCompilationEnabled())
407 dataLog("Block ", *target, " will bail also.\n");
408 target->cfaHasVisited = false;
413 bool compileNode(unsigned nodeIndex)
415 if (!m_state.isValid()) {
416 safelyInvalidateAfterTermination();
420 m_node = m_highBlock->at(nodeIndex);
421 m_codeOriginForExitProfile = m_node->origin.semantic;
422 m_codeOriginForExitTarget = m_node->origin.forExit;
424 if (verboseCompilationEnabled())
425 dataLog("Lowering ", m_node, "\n");
427 m_availableRecoveries.resize(0);
429 m_interpreter.startExecuting();
431 switch (m_node->op()) {
441 compileDoubleConstant();
444 compileInt52Constant();
450 compileDoubleAsInt32();
459 compileValueToInt32();
461 case BooleanToNumber:
462 compileBooleanToNumber();
464 case ExtractOSREntryLocal:
465 compileExtractOSREntryLocal();
484 compileArithAddOrSub();
500 compileArithMinOrMax();
524 compileArithFRound();
527 compileArithNegate();
548 compileUInt32ToNumber();
551 compileCheckStructure();
557 compileCheckNotEmpty();
560 compileCheckBadCell();
563 compileGetExecutable();
565 case ArrayifyToStructure:
566 compileArrayifyToStructure();
569 compilePutStructure();
582 compileGetButterfly();
584 case ConstantStoragePointer:
585 compileConstantStoragePointer();
587 case GetIndexedPropertyStorage:
588 compileGetIndexedPropertyStorage();
594 compileGetArrayLength();
597 compileCheckInBounds();
602 case GetMyArgumentByVal:
603 compileGetMyArgumentByVal();
616 case CreateActivation:
617 compileCreateActivation();
620 compileNewFunction();
622 case CreateDirectArguments:
623 compileCreateDirectArguments();
625 case CreateScopedArguments:
626 compileCreateScopedArguments();
628 case CreateClonedArguments:
629 compileCreateClonedArguments();
638 compileNewArrayBuffer();
640 case NewArrayWithSize:
641 compileNewArrayWithSize();
643 case GetTypedArrayByteOffset:
644 compileGetTypedArrayByteOffset();
646 case AllocatePropertyStorage:
647 compileAllocatePropertyStorage();
649 case ReallocatePropertyStorage:
650 compileReallocatePropertyStorage();
653 case CallStringConstructor:
654 compileToStringOrCallStringConstructor();
657 compileToPrimitive();
663 compileStringCharAt();
665 case StringCharCodeAt:
666 compileStringCharCodeAt();
669 case GetGetterSetterByOffset:
670 compileGetByOffset();
678 case MultiGetByOffset:
679 compileMultiGetByOffset();
682 compilePutByOffset();
684 case MultiPutByOffset:
685 compileMultiPutByOffset();
688 compileGetGlobalVar();
691 compilePutGlobalVar();
694 compileNotifyWrite();
699 case GetArgumentCount:
700 compileGetArgumentCount();
709 compileGetClosureVar();
712 compilePutClosureVar();
714 case GetFromArguments:
715 compileGetFromArguments();
718 compilePutToArguments();
723 case CompareEqConstant:
724 compileCompareEqConstant();
726 case CompareStrictEq:
727 compileCompareStrictEq();
730 compileCompareLess();
733 compileCompareLessEq();
736 compileCompareGreater();
738 case CompareGreaterEq:
739 compileCompareGreaterEq();
746 compileCallOrConstruct();
749 case CallForwardVarargs:
750 case ConstructVarargs:
751 case ConstructForwardVarargs:
752 compileCallOrConstructVarargs();
755 compileLoadVarargs();
758 compileForwardVarargs();
760 #if ENABLE(FTL_NATIVE_CALL_INLINING)
762 case NativeConstruct:
763 compileNativeCallOrConstruct();
779 compileForceOSRExit();
782 case ThrowReferenceError:
785 case InvalidationPoint:
786 compileInvalidationPoint();
789 compileIsUndefined();
804 compileIsObjectOrNull();
812 case CheckHasInstance:
813 compileCheckHasInstance();
819 compileCountExecution();
822 compileStoreBarrier();
824 case HasIndexedProperty:
825 compileHasIndexedProperty();
827 case HasGenericProperty:
828 compileHasGenericProperty();
830 case HasStructureProperty:
831 compileHasStructureProperty();
834 compileGetDirectPname();
836 case GetEnumerableLength:
837 compileGetEnumerableLength();
839 case GetPropertyEnumerator:
840 compileGetPropertyEnumerator();
842 case GetEnumeratorStructurePname:
843 compileGetEnumeratorStructurePname();
845 case GetEnumeratorGenericPname:
846 compileGetEnumeratorGenericPname();
849 compileToIndexString();
851 case CheckStructureImmediate:
852 compileCheckStructureImmediate();
854 case MaterializeNewObject:
855 compileMaterializeNewObject();
857 case MaterializeCreateActivation:
858 compileMaterializeCreateActivation();
865 case PhantomNewObject:
866 case PhantomNewFunction:
867 case PhantomCreateActivation:
868 case PhantomDirectArguments:
869 case PhantomClonedArguments:
875 DFG_CRASH(m_graph, m_node, "Unrecognized node in FTL backend");
879 if (m_node->isTerminal())
882 if (!m_state.isValid()) {
883 safelyInvalidateAfterTermination();
887 m_availabilityCalculator.executeNode(m_node);
888 m_interpreter.executeEffects(nodeIndex);
893 void compileUpsilon()
895 LValue destination = m_phis.get(m_node->phi());
897 switch (m_node->child1().useKind()) {
899 m_out.set(lowDouble(m_node->child1()), destination);
902 m_out.set(lowInt32(m_node->child1()), destination);
905 m_out.set(lowInt52(m_node->child1()), destination);
908 m_out.set(lowBoolean(m_node->child1()), destination);
911 m_out.set(lowCell(m_node->child1()), destination);
914 m_out.set(lowJSValue(m_node->child1()), destination);
917 DFG_CRASH(m_graph, m_node, "Bad use kind");
924 LValue source = m_phis.get(m_node);
926 switch (m_node->flags() & NodeResultMask) {
927 case NodeResultDouble:
928 setDouble(m_out.get(source));
930 case NodeResultInt32:
931 setInt32(m_out.get(source));
933 case NodeResultInt52:
934 setInt52(m_out.get(source));
936 case NodeResultBoolean:
937 setBoolean(m_out.get(source));
940 setJSValue(m_out.get(source));
943 DFG_CRASH(m_graph, m_node, "Bad use kind");
948 void compileDoubleConstant()
950 setDouble(m_out.constDouble(m_node->asNumber()));
953 void compileInt52Constant()
955 int64_t value = m_node->asMachineInt();
957 setInt52(m_out.constInt64(value << JSValue::int52ShiftAmount));
958 setStrictInt52(m_out.constInt64(value));
961 void compileDoubleRep()
963 switch (m_node->child1().useKind()) {
964 case RealNumberUse: {
965 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
967 LValue doubleValue = unboxDouble(value);
969 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("DoubleRep RealNumberUse int case"));
970 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("DoubleRep continuation"));
972 ValueFromBlock fastResult = m_out.anchor(doubleValue);
974 m_out.doubleEqual(doubleValue, doubleValue),
975 usually(continuation), rarely(intCase));
977 LBasicBlock lastNext = m_out.appendTo(intCase, continuation);
980 jsValueValue(value), m_node->child1(), SpecBytecodeRealNumber,
981 isNotInt32(value, provenType(m_node->child1()) & ~SpecFullDouble));
982 ValueFromBlock slowResult = m_out.anchor(m_out.intToDouble(unboxInt32(value)));
983 m_out.jump(continuation);
985 m_out.appendTo(continuation, lastNext);
987 setDouble(m_out.phi(m_out.doubleType, fastResult, slowResult));
993 bool shouldConvertNonNumber = m_node->child1().useKind() == NotCellUse;
995 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
997 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing int case"));
998 LBasicBlock doubleTesting = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing double case"));
999 LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing double case"));
1000 LBasicBlock nonDoubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing undefined case"));
1001 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing continuation"));
1004 isNotInt32(value, provenType(m_node->child1())),
1005 unsure(doubleTesting), unsure(intCase));
1007 LBasicBlock lastNext = m_out.appendTo(intCase, doubleTesting);
1009 ValueFromBlock intToDouble = m_out.anchor(
1010 m_out.intToDouble(unboxInt32(value)));
1011 m_out.jump(continuation);
1013 m_out.appendTo(doubleTesting, doubleCase);
1014 LValue valueIsNumber = isNumber(value, provenType(m_node->child1()));
1015 m_out.branch(valueIsNumber, usually(doubleCase), rarely(nonDoubleCase));
1017 m_out.appendTo(doubleCase, nonDoubleCase);
1018 ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(value));
1019 m_out.jump(continuation);
1021 if (shouldConvertNonNumber) {
1022 LBasicBlock undefinedCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble converting undefined case"));
1023 LBasicBlock testNullCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing null case"));
1024 LBasicBlock nullCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble converting null case"));
1025 LBasicBlock testBooleanTrueCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing boolean true case"));
1026 LBasicBlock convertBooleanTrueCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble convert boolean true case"));
1027 LBasicBlock convertBooleanFalseCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble convert boolean false case"));
1029 m_out.appendTo(nonDoubleCase, undefinedCase);
1030 LValue valueIsUndefined = m_out.equal(value, m_out.constInt64(ValueUndefined));
1031 m_out.branch(valueIsUndefined, unsure(undefinedCase), unsure(testNullCase));
1033 m_out.appendTo(undefinedCase, testNullCase);
1034 ValueFromBlock convertedUndefined = m_out.anchor(m_out.constDouble(PNaN));
1035 m_out.jump(continuation);
1037 m_out.appendTo(testNullCase, nullCase);
1038 LValue valueIsNull = m_out.equal(value, m_out.constInt64(ValueNull));
1039 m_out.branch(valueIsNull, unsure(nullCase), unsure(testBooleanTrueCase));
1041 m_out.appendTo(nullCase, testBooleanTrueCase);
1042 ValueFromBlock convertedNull = m_out.anchor(m_out.constDouble(0));
1043 m_out.jump(continuation);
1045 m_out.appendTo(testBooleanTrueCase, convertBooleanTrueCase);
1046 LValue valueIsBooleanTrue = m_out.equal(value, m_out.constInt64(ValueTrue));
1047 m_out.branch(valueIsBooleanTrue, unsure(convertBooleanTrueCase), unsure(convertBooleanFalseCase));
1049 m_out.appendTo(convertBooleanTrueCase, convertBooleanFalseCase);
1050 ValueFromBlock convertedTrue = m_out.anchor(m_out.constDouble(1));
1051 m_out.jump(continuation);
1053 m_out.appendTo(convertBooleanFalseCase, continuation);
1055 LValue valueIsNotBooleanFalse = m_out.notEqual(value, m_out.constInt64(ValueFalse));
1056 FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), ~SpecCell, valueIsNotBooleanFalse);
1057 ValueFromBlock convertedFalse = m_out.anchor(m_out.constDouble(0));
1058 m_out.jump(continuation);
1060 m_out.appendTo(continuation, lastNext);
1061 setDouble(m_out.phi(m_out.doubleType, intToDouble, unboxedDouble, convertedUndefined, convertedNull, convertedTrue, convertedFalse));
1064 m_out.appendTo(nonDoubleCase, continuation);
1065 FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), SpecBytecodeNumber, m_out.booleanTrue);
1066 m_out.unreachable();
1068 m_out.appendTo(continuation, lastNext);
1070 setDouble(m_out.phi(m_out.doubleType, intToDouble, unboxedDouble));
1075 setDouble(strictInt52ToDouble(lowStrictInt52(m_node->child1())));
1080 DFG_CRASH(m_graph, m_node, "Bad use kind");
1084 void compileDoubleAsInt32()
1086 LValue integerValue = convertDoubleToInt32(lowDouble(m_node->child1()), shouldCheckNegativeZero(m_node->arithMode()));
1087 setInt32(integerValue);
1090 void compileValueRep()
1092 switch (m_node->child1().useKind()) {
1093 case DoubleRepUse: {
1094 LValue value = lowDouble(m_node->child1());
1096 if (m_interpreter.needsTypeCheck(m_node->child1(), ~SpecDoubleImpureNaN)) {
1097 value = m_out.select(
1098 m_out.doubleEqual(value, value), value, m_out.constDouble(PNaN));
1101 setJSValue(boxDouble(value));
1106 setJSValue(strictInt52ToJSValue(lowStrictInt52(m_node->child1())));
1111 DFG_CRASH(m_graph, m_node, "Bad use kind");
1115 void compileInt52Rep()
1117 switch (m_node->child1().useKind()) {
1119 setStrictInt52(m_out.signExt(lowInt32(m_node->child1()), m_out.int64));
1124 jsValueToStrictInt52(
1125 m_node->child1(), lowJSValue(m_node->child1(), ManualOperandSpeculation)));
1128 case DoubleRepMachineIntUse:
1130 doubleToStrictInt52(
1131 m_node->child1(), lowDouble(m_node->child1())));
1135 RELEASE_ASSERT_NOT_REACHED();
1139 void compileValueToInt32()
1141 switch (m_node->child1().useKind()) {
1143 setInt32(m_out.castToInt32(lowStrictInt52(m_node->child1())));
1147 setInt32(doubleToInt32(lowDouble(m_node->child1())));
1152 LoweredNodeValue value = m_int32Values.get(m_node->child1().node());
1153 if (isValid(value)) {
1154 setInt32(value.value());
1158 value = m_jsValueValues.get(m_node->child1().node());
1159 if (isValid(value)) {
1160 setInt32(numberOrNotCellToInt32(m_node->child1(), value.value()));
1164 // We'll basically just get here for constants. But it's good to have this
1165 // catch-all since we often add new representations into the mix.
1167 numberOrNotCellToInt32(
1169 lowJSValue(m_node->child1(), ManualOperandSpeculation)));
1174 DFG_CRASH(m_graph, m_node, "Bad use kind");
1179 void compileBooleanToNumber()
1181 switch (m_node->child1().useKind()) {
1183 setInt32(m_out.zeroExt(lowBoolean(m_node->child1()), m_out.int32));
1188 LValue value = lowJSValue(m_node->child1());
1190 if (!m_interpreter.needsTypeCheck(m_node->child1(), SpecBoolInt32 | SpecBoolean)) {
1191 setInt32(m_out.bitAnd(m_out.castToInt32(value), m_out.int32One));
1195 LBasicBlock booleanCase = FTL_NEW_BLOCK(m_out, ("BooleanToNumber boolean case"));
1196 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("BooleanToNumber continuation"));
1198 ValueFromBlock notBooleanResult = m_out.anchor(value);
1200 isBoolean(value, provenType(m_node->child1())),
1201 unsure(booleanCase), unsure(continuation));
1203 LBasicBlock lastNext = m_out.appendTo(booleanCase, continuation);
1204 ValueFromBlock booleanResult = m_out.anchor(m_out.bitOr(
1205 m_out.zeroExt(unboxBoolean(value), m_out.int64), m_tagTypeNumber));
1206 m_out.jump(continuation);
1208 m_out.appendTo(continuation, lastNext);
1209 setJSValue(m_out.phi(m_out.int64, booleanResult, notBooleanResult));
1214 RELEASE_ASSERT_NOT_REACHED();
1219 void compileExtractOSREntryLocal()
1221 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(
1222 m_ftlState.jitCode->ftlForOSREntry()->entryBuffer()->dataBuffer());
1223 setJSValue(m_out.load64(m_out.absolute(buffer + m_node->unlinkedLocal().toLocal())));
1226 void compileGetStack()
1228 // GetLocals arise only for captured variables and arguments. For arguments, we might have
1229 // already loaded it.
1230 if (LValue value = m_loadedArgumentValues.get(m_node)) {
1235 StackAccessData* data = m_node->stackAccessData();
1236 AbstractValue& value = m_state.variables().operand(data->local);
1238 DFG_ASSERT(m_graph, m_node, isConcrete(data->format));
1239 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.
1241 if (isInt32Speculation(value.m_type))
1242 setInt32(m_out.load32(payloadFor(data->machineLocal)));
1244 setJSValue(m_out.load64(addressFor(data->machineLocal)));
1247 void compilePutStack()
1249 StackAccessData* data = m_node->stackAccessData();
1250 switch (data->format) {
1251 case FlushedJSValue: {
1252 LValue value = lowJSValue(m_node->child1());
1253 m_out.store64(value, addressFor(data->machineLocal));
1257 case FlushedDouble: {
1258 LValue value = lowDouble(m_node->child1());
1259 m_out.storeDouble(value, addressFor(data->machineLocal));
1263 case FlushedInt32: {
1264 LValue value = lowInt32(m_node->child1());
1265 m_out.store32(value, payloadFor(data->machineLocal));
1269 case FlushedInt52: {
1270 LValue value = lowInt52(m_node->child1());
1271 m_out.store64(value, addressFor(data->machineLocal));
1276 LValue value = lowCell(m_node->child1());
1277 m_out.store64(value, addressFor(data->machineLocal));
1281 case FlushedBoolean: {
1282 speculateBoolean(m_node->child1());
1284 lowJSValue(m_node->child1(), ManualOperandSpeculation),
1285 addressFor(data->machineLocal));
1290 DFG_CRASH(m_graph, m_node, "Bad flush format");
1297 DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, speculate);
1300 void compileToThis()
1302 LValue value = lowJSValue(m_node->child1());
1304 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("ToThis is cell case"));
1305 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ToThis slow case"));
1306 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToThis continuation"));
1309 isCell(value, provenType(m_node->child1())), usually(isCellCase), rarely(slowCase));
1311 LBasicBlock lastNext = m_out.appendTo(isCellCase, slowCase);
1312 ValueFromBlock fastResult = m_out.anchor(value);
1313 m_out.branch(isType(value, FinalObjectType), usually(continuation), rarely(slowCase));
1315 m_out.appendTo(slowCase, continuation);
1316 J_JITOperation_EJ function;
1317 if (m_graph.isStrictModeFor(m_node->origin.semantic))
1318 function = operationToThisStrict;
1320 function = operationToThis;
1321 ValueFromBlock slowResult = m_out.anchor(
1322 vmCall(m_out.operation(function), m_callFrame, value));
1323 m_out.jump(continuation);
1325 m_out.appendTo(continuation, lastNext);
1326 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
1329 void compileValueAdd()
1331 J_JITOperation_EJJ operation;
1332 if (!(provenType(m_node->child1()) & SpecFullNumber)
1333 && !(provenType(m_node->child2()) & SpecFullNumber))
1334 operation = operationValueAddNotNumber;
1336 operation = operationValueAdd;
1338 m_out.operation(operation), m_callFrame,
1339 lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));
1342 void compileArithAddOrSub()
1344 bool isSub = m_node->op() == ArithSub;
1345 switch (m_node->binaryUseKind()) {
1347 LValue left = lowInt32(m_node->child1());
1348 LValue right = lowInt32(m_node->child2());
1350 if (!shouldCheckOverflow(m_node->arithMode())) {
1351 setInt32(isSub ? m_out.sub(left, right) : m_out.add(left, right));
1357 result = m_out.addWithOverflow32(left, right);
1359 if (doesKill(m_node->child2())) {
1360 addAvailableRecovery(
1361 m_node->child2(), SubRecovery,
1362 m_out.extractValue(result, 0), left, ValueFormatInt32);
1363 } else if (doesKill(m_node->child1())) {
1364 addAvailableRecovery(
1365 m_node->child1(), SubRecovery,
1366 m_out.extractValue(result, 0), right, ValueFormatInt32);
1369 result = m_out.subWithOverflow32(left, right);
1371 if (doesKill(m_node->child2())) {
1372 // result = left - right
1373 // result - left = -right
1374 // right = left - result
1375 addAvailableRecovery(
1376 m_node->child2(), SubRecovery,
1377 left, m_out.extractValue(result, 0), ValueFormatInt32);
1378 } else if (doesKill(m_node->child1())) {
1379 // result = left - right
1380 // result + right = left
1381 addAvailableRecovery(
1382 m_node->child1(), AddRecovery,
1383 m_out.extractValue(result, 0), right, ValueFormatInt32);
1387 speculate(Overflow, noValue(), 0, m_out.extractValue(result, 1));
1388 setInt32(m_out.extractValue(result, 0));
1393 if (!abstractValue(m_node->child1()).couldBeType(SpecInt52)
1394 && !abstractValue(m_node->child2()).couldBeType(SpecInt52)) {
1396 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1397 LValue right = lowInt52(m_node->child2(), kind);
1398 setInt52(isSub ? m_out.sub(left, right) : m_out.add(left, right), kind);
1402 LValue left = lowInt52(m_node->child1());
1403 LValue right = lowInt52(m_node->child2());
1407 result = m_out.addWithOverflow64(left, right);
1409 if (doesKill(m_node->child2())) {
1410 addAvailableRecovery(
1411 m_node->child2(), SubRecovery,
1412 m_out.extractValue(result, 0), left, ValueFormatInt52);
1413 } else if (doesKill(m_node->child1())) {
1414 addAvailableRecovery(
1415 m_node->child1(), SubRecovery,
1416 m_out.extractValue(result, 0), right, ValueFormatInt52);
1419 result = m_out.subWithOverflow64(left, right);
1421 if (doesKill(m_node->child2())) {
1422 // result = left - right
1423 // result - left = -right
1424 // right = left - result
1425 addAvailableRecovery(
1426 m_node->child2(), SubRecovery,
1427 left, m_out.extractValue(result, 0), ValueFormatInt52);
1428 } else if (doesKill(m_node->child1())) {
1429 // result = left - right
1430 // result + right = left
1431 addAvailableRecovery(
1432 m_node->child1(), AddRecovery,
1433 m_out.extractValue(result, 0), right, ValueFormatInt52);
1437 speculate(Int52Overflow, noValue(), 0, m_out.extractValue(result, 1));
1438 setInt52(m_out.extractValue(result, 0));
1442 case DoubleRepUse: {
1443 LValue C1 = lowDouble(m_node->child1());
1444 LValue C2 = lowDouble(m_node->child2());
1446 setDouble(isSub ? m_out.doubleSub(C1, C2) : m_out.doubleAdd(C1, C2));
1451 DFG_CRASH(m_graph, m_node, "Bad use kind");
1456 void compileArithClz32()
1458 LValue operand = lowInt32(m_node->child1());
1459 LValue isZeroUndef = m_out.booleanFalse;
1460 setInt32(m_out.ctlz32(operand, isZeroUndef));
1463 void compileArithMul()
1465 switch (m_node->binaryUseKind()) {
1467 LValue left = lowInt32(m_node->child1());
1468 LValue right = lowInt32(m_node->child2());
1472 if (!shouldCheckOverflow(m_node->arithMode()))
1473 result = m_out.mul(left, right);
1475 LValue overflowResult = m_out.mulWithOverflow32(left, right);
1476 speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1477 result = m_out.extractValue(overflowResult, 0);
1480 if (shouldCheckNegativeZero(m_node->arithMode())) {
1481 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
1482 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation"));
1485 m_out.notZero32(result), usually(continuation), rarely(slowCase));
1487 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
1488 LValue cond = m_out.bitOr(m_out.lessThan(left, m_out.int32Zero), m_out.lessThan(right, m_out.int32Zero));
1489 speculate(NegativeZero, noValue(), 0, cond);
1490 m_out.jump(continuation);
1491 m_out.appendTo(continuation, lastNext);
1500 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1501 LValue right = lowInt52(m_node->child2(), opposite(kind));
1503 LValue overflowResult = m_out.mulWithOverflow64(left, right);
1504 speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1505 LValue result = m_out.extractValue(overflowResult, 0);
1507 if (shouldCheckNegativeZero(m_node->arithMode())) {
1508 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
1509 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation"));
1512 m_out.notZero64(result), usually(continuation), rarely(slowCase));
1514 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
1515 LValue cond = m_out.bitOr(m_out.lessThan(left, m_out.int64Zero), m_out.lessThan(right, m_out.int64Zero));
1516 speculate(NegativeZero, noValue(), 0, cond);
1517 m_out.jump(continuation);
1518 m_out.appendTo(continuation, lastNext);
1525 case DoubleRepUse: {
1527 m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1532 DFG_CRASH(m_graph, m_node, "Bad use kind");
1537 void compileArithDiv()
1539 switch (m_node->binaryUseKind()) {
1541 LValue numerator = lowInt32(m_node->child1());
1542 LValue denominator = lowInt32(m_node->child2());
1544 LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithDiv unsafe denominator"));
1545 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithDiv continuation"));
1546 LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithDiv done"));
1548 Vector<ValueFromBlock, 3> results;
1550 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
1553 m_out.above(adjustedDenominator, m_out.int32One),
1554 usually(continuation), rarely(unsafeDenominator));
1556 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
1558 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
1560 if (shouldCheckOverflow(m_node->arithMode())) {
1561 LValue cond = m_out.bitOr(m_out.isZero32(denominator), m_out.equal(numerator, neg2ToThe31));
1562 speculate(Overflow, noValue(), 0, cond);
1563 m_out.jump(continuation);
1565 // This is the case where we convert the result to an int after we're done. So,
1566 // if the denominator is zero, then the result should be zero.
1567 // If the denominator is not zero (i.e. it's -1 because we're guarded by the
1568 // check above) and the numerator is -2^31 then the result should be -2^31.
1570 LBasicBlock divByZero = FTL_NEW_BLOCK(m_out, ("ArithDiv divide by zero"));
1571 LBasicBlock notDivByZero = FTL_NEW_BLOCK(m_out, ("ArithDiv not divide by zero"));
1572 LBasicBlock neg2ToThe31ByNeg1 = FTL_NEW_BLOCK(m_out, ("ArithDiv -2^31/-1"));
1575 m_out.isZero32(denominator), rarely(divByZero), usually(notDivByZero));
1577 m_out.appendTo(divByZero, notDivByZero);
1578 results.append(m_out.anchor(m_out.int32Zero));
1581 m_out.appendTo(notDivByZero, neg2ToThe31ByNeg1);
1583 m_out.equal(numerator, neg2ToThe31),
1584 rarely(neg2ToThe31ByNeg1), usually(continuation));
1586 m_out.appendTo(neg2ToThe31ByNeg1, continuation);
1587 results.append(m_out.anchor(neg2ToThe31));
1591 m_out.appendTo(continuation, done);
1593 if (shouldCheckNegativeZero(m_node->arithMode())) {
1594 LBasicBlock zeroNumerator = FTL_NEW_BLOCK(m_out, ("ArithDiv zero numerator"));
1595 LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithDiv numerator continuation"));
1598 m_out.isZero32(numerator),
1599 rarely(zeroNumerator), usually(numeratorContinuation));
1601 LBasicBlock innerLastNext = m_out.appendTo(zeroNumerator, numeratorContinuation);
1604 NegativeZero, noValue(), 0, m_out.lessThan(denominator, m_out.int32Zero));
1606 m_out.jump(numeratorContinuation);
1608 m_out.appendTo(numeratorContinuation, innerLastNext);
1611 LValue result = m_out.div(numerator, denominator);
1613 if (shouldCheckOverflow(m_node->arithMode())) {
1615 Overflow, noValue(), 0,
1616 m_out.notEqual(m_out.mul(result, denominator), numerator));
1619 results.append(m_out.anchor(result));
1622 m_out.appendTo(done, lastNext);
1624 setInt32(m_out.phi(m_out.int32, results));
1628 case DoubleRepUse: {
1629 setDouble(m_out.doubleDiv(
1630 lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1635 DFG_CRASH(m_graph, m_node, "Bad use kind");
1640 void compileArithMod()
1642 switch (m_node->binaryUseKind()) {
1644 LValue numerator = lowInt32(m_node->child1());
1645 LValue denominator = lowInt32(m_node->child2());
1647 LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithMod unsafe denominator"));
1648 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMod continuation"));
1649 LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithMod done"));
1651 Vector<ValueFromBlock, 3> results;
1653 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
1656 m_out.above(adjustedDenominator, m_out.int32One),
1657 usually(continuation), rarely(unsafeDenominator));
1659 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
1661 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
1663 // FIXME: -2^31 / -1 will actually yield negative zero, so we could have a
1664 // separate case for that. But it probably doesn't matter so much.
1665 if (shouldCheckOverflow(m_node->arithMode())) {
1666 LValue cond = m_out.bitOr(m_out.isZero32(denominator), m_out.equal(numerator, neg2ToThe31));
1667 speculate(Overflow, noValue(), 0, cond);
1668 m_out.jump(continuation);
1670 // This is the case where we convert the result to an int after we're done. So,
1671 // if the denominator is zero, then the result should be result should be zero.
1672 // If the denominator is not zero (i.e. it's -1 because we're guarded by the
1673 // check above) and the numerator is -2^31 then the result should be -2^31.
1675 LBasicBlock modByZero = FTL_NEW_BLOCK(m_out, ("ArithMod modulo by zero"));
1676 LBasicBlock notModByZero = FTL_NEW_BLOCK(m_out, ("ArithMod not modulo by zero"));
1677 LBasicBlock neg2ToThe31ByNeg1 = FTL_NEW_BLOCK(m_out, ("ArithMod -2^31/-1"));
1680 m_out.isZero32(denominator), rarely(modByZero), usually(notModByZero));
1682 m_out.appendTo(modByZero, notModByZero);
1683 results.append(m_out.anchor(m_out.int32Zero));
1686 m_out.appendTo(notModByZero, neg2ToThe31ByNeg1);
1688 m_out.equal(numerator, neg2ToThe31),
1689 rarely(neg2ToThe31ByNeg1), usually(continuation));
1691 m_out.appendTo(neg2ToThe31ByNeg1, continuation);
1692 results.append(m_out.anchor(m_out.int32Zero));
1696 m_out.appendTo(continuation, done);
1698 LValue remainder = m_out.rem(numerator, denominator);
1700 if (shouldCheckNegativeZero(m_node->arithMode())) {
1701 LBasicBlock negativeNumerator = FTL_NEW_BLOCK(m_out, ("ArithMod negative numerator"));
1702 LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithMod numerator continuation"));
1705 m_out.lessThan(numerator, m_out.int32Zero),
1706 unsure(negativeNumerator), unsure(numeratorContinuation));
1708 LBasicBlock innerLastNext = m_out.appendTo(negativeNumerator, numeratorContinuation);
1710 speculate(NegativeZero, noValue(), 0, m_out.isZero32(remainder));
1712 m_out.jump(numeratorContinuation);
1714 m_out.appendTo(numeratorContinuation, innerLastNext);
1717 results.append(m_out.anchor(remainder));
1720 m_out.appendTo(done, lastNext);
1722 setInt32(m_out.phi(m_out.int32, results));
1726 case DoubleRepUse: {
1728 m_out.doubleRem(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1733 DFG_CRASH(m_graph, m_node, "Bad use kind");
1738 void compileArithMinOrMax()
1740 switch (m_node->binaryUseKind()) {
1742 LValue left = lowInt32(m_node->child1());
1743 LValue right = lowInt32(m_node->child2());
1747 m_node->op() == ArithMin
1748 ? m_out.lessThan(left, right)
1749 : m_out.lessThan(right, left),
1754 case DoubleRepUse: {
1755 LValue left = lowDouble(m_node->child1());
1756 LValue right = lowDouble(m_node->child2());
1758 LBasicBlock notLessThan = FTL_NEW_BLOCK(m_out, ("ArithMin/ArithMax not less than"));
1759 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMin/ArithMax continuation"));
1761 Vector<ValueFromBlock, 2> results;
1763 results.append(m_out.anchor(left));
1765 m_node->op() == ArithMin
1766 ? m_out.doubleLessThan(left, right)
1767 : m_out.doubleGreaterThan(left, right),
1768 unsure(continuation), unsure(notLessThan));
1770 LBasicBlock lastNext = m_out.appendTo(notLessThan, continuation);
1771 results.append(m_out.anchor(m_out.select(
1772 m_node->op() == ArithMin
1773 ? m_out.doubleGreaterThanOrEqual(left, right)
1774 : m_out.doubleLessThanOrEqual(left, right),
1775 right, m_out.constDouble(PNaN))));
1776 m_out.jump(continuation);
1778 m_out.appendTo(continuation, lastNext);
1779 setDouble(m_out.phi(m_out.doubleType, results));
1784 DFG_CRASH(m_graph, m_node, "Bad use kind");
1789 void compileArithAbs()
1791 switch (m_node->child1().useKind()) {
1793 LValue value = lowInt32(m_node->child1());
1795 LValue mask = m_out.aShr(value, m_out.constInt32(31));
1796 LValue result = m_out.bitXor(mask, m_out.add(mask, value));
1798 speculate(Overflow, noValue(), 0, m_out.equal(result, m_out.constInt32(1 << 31)));
1804 case DoubleRepUse: {
1805 setDouble(m_out.doubleAbs(lowDouble(m_node->child1())));
1810 DFG_CRASH(m_graph, m_node, "Bad use kind");
1815 void compileArithSin() { setDouble(m_out.doubleSin(lowDouble(m_node->child1()))); }
1817 void compileArithCos() { setDouble(m_out.doubleCos(lowDouble(m_node->child1()))); }
1819 void compileArithPow()
1821 // FIXME: investigate llvm.powi to better understand its performance characteristics.
1822 // It might be better to have the inline loop in DFG too.
1823 if (m_node->child2().useKind() == Int32Use)
1824 setDouble(m_out.doublePowi(lowDouble(m_node->child1()), lowInt32(m_node->child2())));
1826 LValue base = lowDouble(m_node->child1());
1827 LValue exponent = lowDouble(m_node->child2());
1829 LBasicBlock integerExponentIsSmallBlock = FTL_NEW_BLOCK(m_out, ("ArithPow test integer exponent is small."));
1830 LBasicBlock integerExponentPowBlock = FTL_NEW_BLOCK(m_out, ("ArithPow pow(double, (int)double)."));
1831 LBasicBlock doubleExponentPowBlockEntry = FTL_NEW_BLOCK(m_out, ("ArithPow pow(double, double)."));
1832 LBasicBlock nanExceptionExponentIsInfinity = FTL_NEW_BLOCK(m_out, ("ArithPow NaN Exception, check exponent is infinity."));
1833 LBasicBlock nanExceptionBaseIsOne = FTL_NEW_BLOCK(m_out, ("ArithPow NaN Exception, check base is one."));
1834 LBasicBlock powBlock = FTL_NEW_BLOCK(m_out, ("ArithPow regular pow"));
1835 LBasicBlock nanExceptionResultIsNaN = FTL_NEW_BLOCK(m_out, ("ArithPow NaN Exception, result is NaN."));
1836 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithPow continuation"));
1838 LValue integerExponent = m_out.fpToInt32(exponent);
1839 LValue integerExponentConvertedToDouble = m_out.intToDouble(integerExponent);
1840 LValue exponentIsInteger = m_out.doubleEqual(exponent, integerExponentConvertedToDouble);
1841 m_out.branch(exponentIsInteger, unsure(integerExponentIsSmallBlock), unsure(doubleExponentPowBlockEntry));
1843 LBasicBlock lastNext = m_out.appendTo(integerExponentIsSmallBlock, integerExponentPowBlock);
1844 LValue integerExponentBelow1000 = m_out.below(integerExponent, m_out.constInt32(1000));
1845 m_out.branch(integerExponentBelow1000, usually(integerExponentPowBlock), rarely(doubleExponentPowBlockEntry));
1847 m_out.appendTo(integerExponentPowBlock, doubleExponentPowBlockEntry);
1848 ValueFromBlock powDoubleIntResult = m_out.anchor(m_out.doublePowi(base, integerExponent));
1849 m_out.jump(continuation);
1851 // If y is NaN, the result is NaN.
1852 m_out.appendTo(doubleExponentPowBlockEntry, nanExceptionExponentIsInfinity);
1853 LValue exponentIsNaN;
1854 if (provenType(m_node->child2()) & SpecDoubleNaN)
1855 exponentIsNaN = m_out.doubleNotEqualOrUnordered(exponent, exponent);
1857 exponentIsNaN = m_out.booleanFalse;
1858 m_out.branch(exponentIsNaN, rarely(nanExceptionResultIsNaN), usually(nanExceptionExponentIsInfinity));
1860 // If abs(x) is 1 and y is +infinity, the result is NaN.
1861 // If abs(x) is 1 and y is -infinity, the result is NaN.
1862 m_out.appendTo(nanExceptionExponentIsInfinity, nanExceptionBaseIsOne);
1863 LValue absoluteExponent = m_out.doubleAbs(exponent);
1864 LValue absoluteExponentIsInfinity = m_out.doubleEqual(absoluteExponent, m_out.constDouble(std::numeric_limits<double>::infinity()));
1865 m_out.branch(absoluteExponentIsInfinity, rarely(nanExceptionBaseIsOne), usually(powBlock));
1867 m_out.appendTo(nanExceptionBaseIsOne, powBlock);
1868 LValue absoluteBase = m_out.doubleAbs(base);
1869 LValue absoluteBaseIsOne = m_out.doubleEqual(absoluteBase, m_out.constDouble(1));
1870 m_out.branch(absoluteBaseIsOne, unsure(nanExceptionResultIsNaN), unsure(powBlock));
1872 m_out.appendTo(powBlock, nanExceptionResultIsNaN);
1873 ValueFromBlock powResult = m_out.anchor(m_out.doublePow(base, exponent));
1874 m_out.jump(continuation);
1876 m_out.appendTo(nanExceptionResultIsNaN, continuation);
1877 ValueFromBlock pureNan = m_out.anchor(m_out.constDouble(PNaN));
1878 m_out.jump(continuation);
1880 m_out.appendTo(continuation, lastNext);
1881 setDouble(m_out.phi(m_out.doubleType, powDoubleIntResult, powResult, pureNan));
1885 void compileArithRound()
1887 LBasicBlock realPartIsMoreThanHalf = FTL_NEW_BLOCK(m_out, ("ArithRound should round down"));
1888 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithRound continuation"));
1890 LValue value = lowDouble(m_node->child1());
1891 LValue integerValue = m_out.ceil64(value);
1892 ValueFromBlock integerValueResult = m_out.anchor(integerValue);
1894 LValue realPart = m_out.doubleSub(integerValue, value);
1896 m_out.branch(m_out.doubleGreaterThanOrUnordered(realPart, m_out.constDouble(0.5)), unsure(realPartIsMoreThanHalf), unsure(continuation));
1898 LBasicBlock lastNext = m_out.appendTo(realPartIsMoreThanHalf, continuation);
1899 LValue integerValueRoundedDown = m_out.doubleSub(integerValue, m_out.constDouble(1));
1900 ValueFromBlock integerValueRoundedDownResult = m_out.anchor(integerValueRoundedDown);
1901 m_out.jump(continuation);
1902 m_out.appendTo(continuation, lastNext);
1904 LValue result = m_out.phi(m_out.doubleType, integerValueResult, integerValueRoundedDownResult);
1906 if (producesInteger(m_node->arithRoundingMode())) {
1907 LValue integerValue = convertDoubleToInt32(result, shouldCheckNegativeZero(m_node->arithRoundingMode()));
1908 setInt32(integerValue);
1913 void compileArithSqrt() { setDouble(m_out.doubleSqrt(lowDouble(m_node->child1()))); }
1915 void compileArithLog() { setDouble(m_out.doubleLog(lowDouble(m_node->child1()))); }
1917 void compileArithFRound()
1919 LValue floatValue = m_out.fpCast(lowDouble(m_node->child1()), m_out.floatType);
1920 setDouble(m_out.fpCast(floatValue, m_out.doubleType));
1923 void compileArithNegate()
1925 switch (m_node->child1().useKind()) {
1927 LValue value = lowInt32(m_node->child1());
1930 if (!shouldCheckOverflow(m_node->arithMode()))
1931 result = m_out.neg(value);
1932 else if (!shouldCheckNegativeZero(m_node->arithMode())) {
1933 // We don't have a negate-with-overflow intrinsic. Hopefully this
1934 // does the trick, though.
1935 LValue overflowResult = m_out.subWithOverflow32(m_out.int32Zero, value);
1936 speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1937 result = m_out.extractValue(overflowResult, 0);
1939 speculate(Overflow, noValue(), 0, m_out.testIsZero32(value, m_out.constInt32(0x7fffffff)));
1940 result = m_out.neg(value);
1948 if (!abstractValue(m_node->child1()).couldBeType(SpecInt52)) {
1950 LValue value = lowWhicheverInt52(m_node->child1(), kind);
1951 LValue result = m_out.neg(value);
1952 if (shouldCheckNegativeZero(m_node->arithMode()))
1953 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
1954 setInt52(result, kind);
1958 LValue value = lowInt52(m_node->child1());
1959 LValue overflowResult = m_out.subWithOverflow64(m_out.int64Zero, value);
1960 speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1961 LValue result = m_out.extractValue(overflowResult, 0);
1962 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
1967 case DoubleRepUse: {
1968 setDouble(m_out.doubleNeg(lowDouble(m_node->child1())));
1973 DFG_CRASH(m_graph, m_node, "Bad use kind");
1978 void compileBitAnd()
1980 setInt32(m_out.bitAnd(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1985 setInt32(m_out.bitOr(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1988 void compileBitXor()
1990 setInt32(m_out.bitXor(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1993 void compileBitRShift()
1995 setInt32(m_out.aShr(
1996 lowInt32(m_node->child1()),
1997 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2000 void compileBitLShift()
2003 lowInt32(m_node->child1()),
2004 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2007 void compileBitURShift()
2009 setInt32(m_out.lShr(
2010 lowInt32(m_node->child1()),
2011 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2014 void compileUInt32ToNumber()
2016 LValue value = lowInt32(m_node->child1());
2018 if (doesOverflow(m_node->arithMode())) {
2019 setDouble(m_out.unsignedToDouble(value));
2023 speculate(Overflow, noValue(), 0, m_out.lessThan(value, m_out.int32Zero));
2027 void compileCheckStructure()
2029 LValue cell = lowCell(m_node->child1());
2032 if (m_node->child1()->hasConstant())
2033 exitKind = BadConstantCache;
2035 exitKind = BadCache;
2037 LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
2040 structureID, jsValueValue(cell), exitKind, m_node->structureSet(),
2041 [this] (Structure* structure) {
2042 return weakStructureID(structure);
2046 void compileCheckCell()
2048 LValue cell = lowCell(m_node->child1());
2051 BadCell, jsValueValue(cell), m_node->child1().node(),
2052 m_out.notEqual(cell, weakPointer(m_node->cellOperand()->cell())));
2055 void compileCheckBadCell()
2060 void compileCheckNotEmpty()
2062 speculate(TDZFailure, noValue(), nullptr, m_out.isZero64(lowJSValue(m_node->child1())));
2065 void compileGetExecutable()
2067 LValue cell = lowCell(m_node->child1());
2068 speculateFunction(m_node->child1(), cell);
2069 setJSValue(m_out.loadPtr(cell, m_heaps.JSFunction_executable));
2072 void compileArrayifyToStructure()
2074 LValue cell = lowCell(m_node->child1());
2075 LValue property = !!m_node->child2() ? lowInt32(m_node->child2()) : 0;
2077 LBasicBlock unexpectedStructure = FTL_NEW_BLOCK(m_out, ("ArrayifyToStructure unexpected structure"));
2078 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArrayifyToStructure continuation"));
2080 LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
2083 m_out.notEqual(structureID, weakStructureID(m_node->structure())),
2084 rarely(unexpectedStructure), usually(continuation));
2086 LBasicBlock lastNext = m_out.appendTo(unexpectedStructure, continuation);
2089 switch (m_node->arrayMode().type()) {
2092 case Array::Contiguous:
2094 Uncountable, noValue(), 0,
2095 m_out.aboveOrEqual(property, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)));
2102 switch (m_node->arrayMode().type()) {
2104 vmCall(m_out.operation(operationEnsureInt32), m_callFrame, cell);
2107 vmCall(m_out.operation(operationEnsureDouble), m_callFrame, cell);
2109 case Array::Contiguous:
2110 vmCall(m_out.operation(operationEnsureContiguous), m_callFrame, cell);
2112 case Array::ArrayStorage:
2113 case Array::SlowPutArrayStorage:
2114 vmCall(m_out.operation(operationEnsureArrayStorage), m_callFrame, cell);
2117 DFG_CRASH(m_graph, m_node, "Bad array type");
2121 structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
2123 BadIndexingType, jsValueValue(cell), 0,
2124 m_out.notEqual(structureID, weakStructureID(m_node->structure())));
2125 m_out.jump(continuation);
2127 m_out.appendTo(continuation, lastNext);
2130 void compilePutStructure()
2132 m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node);
2134 Structure* oldStructure = m_node->transition()->previous;
2135 Structure* newStructure = m_node->transition()->next;
2136 ASSERT_UNUSED(oldStructure, oldStructure->indexingType() == newStructure->indexingType());
2137 ASSERT(oldStructure->typeInfo().inlineTypeFlags() == newStructure->typeInfo().inlineTypeFlags());
2138 ASSERT(oldStructure->typeInfo().type() == newStructure->typeInfo().type());
2140 LValue cell = lowCell(m_node->child1());
2142 weakStructureID(newStructure),
2143 cell, m_heaps.JSCell_structureID);
2146 void compileGetById()
2148 // Pretty much the only reason why we don't also support GetByIdFlush is because:
2149 // https://bugs.webkit.org/show_bug.cgi?id=125711
2151 switch (m_node->child1().useKind()) {
2153 setJSValue(getById(lowCell(m_node->child1())));
2158 // This is pretty weird, since we duplicate the slow path both here and in the
2159 // code generated by the IC. We should investigate making this less bad.
2160 // https://bugs.webkit.org/show_bug.cgi?id=127830
2161 LValue value = lowJSValue(m_node->child1());
2163 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("GetById untyped cell case"));
2164 LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("GetById untyped not cell case"));
2165 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetById untyped continuation"));
2168 isCell(value, provenType(m_node->child1())), unsure(cellCase), unsure(notCellCase));
2170 LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase);
2171 ValueFromBlock cellResult = m_out.anchor(getById(value));
2172 m_out.jump(continuation);
2174 m_out.appendTo(notCellCase, continuation);
2175 ValueFromBlock notCellResult = m_out.anchor(vmCall(
2176 m_out.operation(operationGetByIdGeneric),
2178 m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()])));
2179 m_out.jump(continuation);
2181 m_out.appendTo(continuation, lastNext);
2182 setJSValue(m_out.phi(m_out.int64, cellResult, notCellResult));
2187 DFG_CRASH(m_graph, m_node, "Bad use kind");
2192 void compilePutById()
2194 // See above; CellUse is easier so we do only that for now.
2195 ASSERT(m_node->child1().useKind() == CellUse);
2197 LValue base = lowCell(m_node->child1());
2198 LValue value = lowJSValue(m_node->child2());
2199 auto uid = m_graph.identifiers()[m_node->identifierNumber()];
2201 // Arguments: id, bytes, target, numArgs, args...
2202 unsigned stackmapID = m_stackmapIDs++;
2204 if (verboseCompilationEnabled())
2205 dataLog(" Emitting PutById patchpoint with stackmap #", stackmapID, "\n");
2207 LValue call = m_out.call(
2208 m_out.patchpointVoidIntrinsic(),
2209 m_out.constInt64(stackmapID), m_out.constInt32(sizeOfPutById()),
2210 constNull(m_out.ref8), m_out.constInt32(2), base, value);
2211 setInstructionCallingConvention(call, LLVMAnyRegCallConv);
2213 m_ftlState.putByIds.append(PutByIdDescriptor(
2214 stackmapID, m_node->origin.semantic, uid,
2215 m_graph.executableFor(m_node->origin.semantic)->ecmaMode(),
2216 m_node->op() == PutByIdDirect ? Direct : NotDirect));
2219 void compileGetButterfly()
2221 setStorage(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSObject_butterfly));
2224 void compileConstantStoragePointer()
2226 setStorage(m_out.constIntPtr(m_node->storagePointer()));
2229 void compileGetIndexedPropertyStorage()
2231 LValue cell = lowCell(m_node->child1());
2233 if (m_node->arrayMode().type() == Array::String) {
2234 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("GetIndexedPropertyStorage String slow case"));
2235 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetIndexedPropertyStorage String continuation"));
2237 ValueFromBlock fastResult = m_out.anchor(
2238 m_out.loadPtr(cell, m_heaps.JSString_value));
2241 m_out.notNull(fastResult.value()), usually(continuation), rarely(slowPath));
2243 LBasicBlock lastNext = m_out.appendTo(slowPath, continuation);
2245 ValueFromBlock slowResult = m_out.anchor(
2246 vmCall(m_out.operation(operationResolveRope), m_callFrame, cell));
2248 m_out.jump(continuation);
2250 m_out.appendTo(continuation, lastNext);
2252 setStorage(m_out.loadPtr(m_out.phi(m_out.intPtr, fastResult, slowResult), m_heaps.StringImpl_data));
2256 setStorage(m_out.loadPtr(cell, m_heaps.JSArrayBufferView_vector));
2259 void compileCheckArray()
2261 Edge edge = m_node->child1();
2262 LValue cell = lowCell(edge);
2264 if (m_node->arrayMode().alreadyChecked(m_graph, m_node, abstractValue(edge)))
2268 BadIndexingType, jsValueValue(cell), 0,
2269 m_out.bitNot(isArrayType(cell, m_node->arrayMode())));
2272 void compileGetTypedArrayByteOffset()
2274 LValue basePtr = lowCell(m_node->child1());
2276 LBasicBlock simpleCase = FTL_NEW_BLOCK(m_out, ("wasteless typed array"));
2277 LBasicBlock wastefulCase = FTL_NEW_BLOCK(m_out, ("wasteful typed array"));
2278 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("continuation branch"));
2280 LValue mode = m_out.load32(basePtr, m_heaps.JSArrayBufferView_mode);
2282 m_out.notEqual(mode, m_out.constInt32(WastefulTypedArray)),
2283 unsure(simpleCase), unsure(wastefulCase));
2285 // begin simple case
2286 LBasicBlock lastNext = m_out.appendTo(simpleCase, wastefulCase);
2288 ValueFromBlock simpleOut = m_out.anchor(m_out.constIntPtr(0));
2290 m_out.jump(continuation);
2292 // begin wasteful case
2293 m_out.appendTo(wastefulCase, continuation);
2295 LValue vectorPtr = m_out.loadPtr(basePtr, m_heaps.JSArrayBufferView_vector);
2296 LValue butterflyPtr = m_out.loadPtr(basePtr, m_heaps.JSObject_butterfly);
2297 LValue arrayBufferPtr = m_out.loadPtr(butterflyPtr, m_heaps.Butterfly_arrayBuffer);
2298 LValue dataPtr = m_out.loadPtr(arrayBufferPtr, m_heaps.ArrayBuffer_data);
2300 ValueFromBlock wastefulOut = m_out.anchor(m_out.sub(vectorPtr, dataPtr));
2302 m_out.jump(continuation);
2303 m_out.appendTo(continuation, lastNext);
2306 setInt32(m_out.castToInt32(m_out.phi(m_out.intPtr, simpleOut, wastefulOut)));
2309 void compileGetArrayLength()
2311 switch (m_node->arrayMode().type()) {
2314 case Array::Contiguous: {
2315 setInt32(m_out.load32NonNegative(lowStorage(m_node->child2()), m_heaps.Butterfly_publicLength));
2319 case Array::String: {
2320 LValue string = lowCell(m_node->child1());
2321 setInt32(m_out.load32NonNegative(string, m_heaps.JSString_length));
2325 case Array::DirectArguments: {
2326 LValue arguments = lowCell(m_node->child1());
2328 ExoticObjectMode, noValue(), nullptr,
2329 m_out.notNull(m_out.loadPtr(arguments, m_heaps.DirectArguments_overrides)));
2330 setInt32(m_out.load32NonNegative(arguments, m_heaps.DirectArguments_length));
2334 case Array::ScopedArguments: {
2335 LValue arguments = lowCell(m_node->child1());
2337 ExoticObjectMode, noValue(), nullptr,
2338 m_out.notZero8(m_out.load8(arguments, m_heaps.ScopedArguments_overrodeThings)));
2339 setInt32(m_out.load32NonNegative(arguments, m_heaps.ScopedArguments_totalLength));
2344 if (isTypedView(m_node->arrayMode().typedArrayType())) {
2346 m_out.load32NonNegative(lowCell(m_node->child1()), m_heaps.JSArrayBufferView_length));
2350 DFG_CRASH(m_graph, m_node, "Bad array type");
2355 void compileCheckInBounds()
2358 OutOfBounds, noValue(), 0,
2359 m_out.aboveOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
2362 void compileGetByVal()
2364 switch (m_node->arrayMode().type()) {
2366 case Array::Contiguous: {
2367 LValue index = lowInt32(m_node->child2());
2368 LValue storage = lowStorage(m_node->child3());
2370 IndexedAbstractHeap& heap = m_node->arrayMode().type() == Array::Int32 ?
2371 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties;
2373 if (m_node->arrayMode().isInBounds()) {
2374 LValue result = m_out.load64(baseIndex(heap, storage, index, m_node->child2()));
2375 LValue isHole = m_out.isZero64(result);
2376 if (m_node->arrayMode().isSaneChain()) {
2378 m_graph, m_node, m_node->arrayMode().type() == Array::Contiguous);
2379 result = m_out.select(
2380 isHole, m_out.constInt64(JSValue::encode(jsUndefined())), result);
2382 speculate(LoadFromHole, noValue(), 0, isHole);
2387 LValue base = lowCell(m_node->child1());
2389 LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous fast case"));
2390 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous slow case"));
2391 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous continuation"));
2395 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
2396 rarely(slowCase), usually(fastCase));
2398 LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
2400 ValueFromBlock fastResult = m_out.anchor(
2401 m_out.load64(baseIndex(heap, storage, index, m_node->child2())));
2403 m_out.isZero64(fastResult.value()), rarely(slowCase), usually(continuation));
2405 m_out.appendTo(slowCase, continuation);
2406 ValueFromBlock slowResult = m_out.anchor(
2407 vmCall(m_out.operation(operationGetByValArrayInt), m_callFrame, base, index));
2408 m_out.jump(continuation);
2410 m_out.appendTo(continuation, lastNext);
2411 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
2415 case Array::Double: {
2416 LValue index = lowInt32(m_node->child2());
2417 LValue storage = lowStorage(m_node->child3());
2419 IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties;
2421 if (m_node->arrayMode().isInBounds()) {
2422 LValue result = m_out.loadDouble(
2423 baseIndex(heap, storage, index, m_node->child2()));
2425 if (!m_node->arrayMode().isSaneChain()) {
2427 LoadFromHole, noValue(), 0,
2428 m_out.doubleNotEqualOrUnordered(result, result));
2434 LValue base = lowCell(m_node->child1());
2436 LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetByVal double in bounds"));
2437 LBasicBlock boxPath = FTL_NEW_BLOCK(m_out, ("GetByVal double boxing"));
2438 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetByVal double slow case"));
2439 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal double continuation"));
2443 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
2444 rarely(slowCase), usually(inBounds));
2446 LBasicBlock lastNext = m_out.appendTo(inBounds, boxPath);
2447 LValue doubleValue = m_out.loadDouble(
2448 baseIndex(heap, storage, index, m_node->child2()));
2450 m_out.doubleNotEqualOrUnordered(doubleValue, doubleValue),
2451 rarely(slowCase), usually(boxPath));
2453 m_out.appendTo(boxPath, slowCase);
2454 ValueFromBlock fastResult = m_out.anchor(boxDouble(doubleValue));
2455 m_out.jump(continuation);
2457 m_out.appendTo(slowCase, continuation);
2458 ValueFromBlock slowResult = m_out.anchor(
2459 vmCall(m_out.operation(operationGetByValArrayInt), m_callFrame, base, index));
2460 m_out.jump(continuation);
2462 m_out.appendTo(continuation, lastNext);
2463 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
2467 case Array::DirectArguments: {
2468 LValue base = lowCell(m_node->child1());
2469 LValue index = lowInt32(m_node->child2());
2472 ExoticObjectMode, noValue(), nullptr,
2473 m_out.notNull(m_out.loadPtr(base, m_heaps.DirectArguments_overrides)));
2475 ExoticObjectMode, noValue(), nullptr,
2478 m_out.load32NonNegative(base, m_heaps.DirectArguments_length)));
2480 TypedPointer address = m_out.baseIndex(
2481 m_heaps.DirectArguments_storage, base, m_out.zeroExtPtr(index));
2482 setJSValue(m_out.load64(address));
2486 case Array::ScopedArguments: {
2487 LValue base = lowCell(m_node->child1());
2488 LValue index = lowInt32(m_node->child2());
2491 ExoticObjectMode, noValue(), nullptr,
2494 m_out.load32NonNegative(base, m_heaps.ScopedArguments_totalLength)));
2496 LValue table = m_out.loadPtr(base, m_heaps.ScopedArguments_table);
2497 LValue namedLength = m_out.load32(table, m_heaps.ScopedArgumentsTable_length);
2499 LBasicBlock namedCase = FTL_NEW_BLOCK(m_out, ("GetByVal ScopedArguments named case"));
2500 LBasicBlock overflowCase = FTL_NEW_BLOCK(m_out, ("GetByVal ScopedArguments overflow case"));
2501 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal ScopedArguments continuation"));
2504 m_out.aboveOrEqual(index, namedLength), unsure(overflowCase), unsure(namedCase));
2506 LBasicBlock lastNext = m_out.appendTo(namedCase, overflowCase);
2508 LValue scope = m_out.loadPtr(base, m_heaps.ScopedArguments_scope);
2509 LValue arguments = m_out.loadPtr(table, m_heaps.ScopedArgumentsTable_arguments);
2511 TypedPointer address = m_out.baseIndex(
2512 m_heaps.scopedArgumentsTableArguments, arguments, m_out.zeroExtPtr(index));
2513 LValue scopeOffset = m_out.load32(address);
2516 ExoticObjectMode, noValue(), nullptr,
2517 m_out.equal(scopeOffset, m_out.constInt32(ScopeOffset::invalidOffset)));
2519 address = m_out.baseIndex(
2520 m_heaps.JSEnvironmentRecord_variables, scope, m_out.zeroExtPtr(scopeOffset));
2521 ValueFromBlock namedResult = m_out.anchor(m_out.load64(address));
2522 m_out.jump(continuation);
2524 m_out.appendTo(overflowCase, continuation);
2526 address = m_out.baseIndex(
2527 m_heaps.ScopedArguments_overflowStorage, base,
2528 m_out.zeroExtPtr(m_out.sub(index, namedLength)));
2529 LValue overflowValue = m_out.load64(address);
2530 speculate(ExoticObjectMode, noValue(), nullptr, m_out.isZero64(overflowValue));
2531 ValueFromBlock overflowResult = m_out.anchor(overflowValue);
2532 m_out.jump(continuation);
2534 m_out.appendTo(continuation, lastNext);
2535 setJSValue(m_out.phi(m_out.int64, namedResult, overflowResult));
2539 case Array::Generic: {
2541 m_out.operation(operationGetByVal), m_callFrame,
2542 lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));
2546 case Array::String: {
2547 compileStringCharAt();
2552 LValue index = lowInt32(m_node->child2());
2553 LValue storage = lowStorage(m_node->child3());
2555 TypedArrayType type = m_node->arrayMode().typedArrayType();
2557 if (isTypedView(type)) {
2558 TypedPointer pointer = TypedPointer(
2559 m_heaps.typedArrayProperties,
2563 m_out.zeroExtPtr(index),
2564 m_out.constIntPtr(logElementSize(type)))));
2568 switch (elementSize(type)) {
2570 result = m_out.load8(pointer);
2573 result = m_out.load16(pointer);
2576 result = m_out.load32(pointer);
2579 DFG_CRASH(m_graph, m_node, "Bad element size");
2582 if (elementSize(type) < 4) {
2584 result = m_out.signExt(result, m_out.int32);
2586 result = m_out.zeroExt(result, m_out.int32);
2591 if (isSigned(type)) {
2596 if (m_node->shouldSpeculateInt32()) {
2598 Overflow, noValue(), 0, m_out.lessThan(result, m_out.int32Zero));
2603 if (m_node->shouldSpeculateMachineInt()) {
2604 setStrictInt52(m_out.zeroExt(result, m_out.int64));
2608 setDouble(m_out.unsignedToFP(result, m_out.doubleType));
2612 ASSERT(isFloat(type));
2617 result = m_out.fpCast(m_out.loadFloat(pointer), m_out.doubleType);
2620 result = m_out.loadDouble(pointer);
2623 DFG_CRASH(m_graph, m_node, "Bad typed array type");
2630 DFG_CRASH(m_graph, m_node, "Bad array type");
2635 void compileGetMyArgumentByVal()
2637 InlineCallFrame* inlineCallFrame = m_node->child1()->origin.semantic.inlineCallFrame;
2639 LValue index = lowInt32(m_node->child2());
2642 if (inlineCallFrame && !inlineCallFrame->isVarargs())
2643 limit = m_out.constInt32(inlineCallFrame->arguments.size() - 1);
2645 VirtualRegister argumentCountRegister;
2646 if (!inlineCallFrame)
2647 argumentCountRegister = VirtualRegister(JSStack::ArgumentCount);
2649 argumentCountRegister = inlineCallFrame->argumentCountRegister;
2650 limit = m_out.sub(m_out.load32(payloadFor(argumentCountRegister)), m_out.int32One);
2653 speculate(ExoticObjectMode, noValue(), 0, m_out.aboveOrEqual(index, limit));
2656 if (inlineCallFrame) {
2657 if (inlineCallFrame->arguments.size() <= 1) {
2658 // We should have already exited due to the bounds check, above. Just tell the
2659 // compiler that anything dominated by this instruction is not reachable, so
2660 // that we don't waste time generating such code. This will also plant some
2661 // kind of crashing instruction so that if by some fluke the bounds check didn't
2662 // work, we'll crash in an easy-to-see way.
2663 didAlreadyTerminate();
2666 base = addressFor(inlineCallFrame->arguments[1].virtualRegister());
2668 base = addressFor(virtualRegisterForArgument(1));
2670 LValue pointer = m_out.baseIndex(
2671 base.value(), m_out.zeroExt(index, m_out.intPtr), ScaleEight);
2672 setJSValue(m_out.load64(TypedPointer(m_heaps.variables.atAnyIndex(), pointer)));
2675 void compilePutByVal()
2677 Edge child1 = m_graph.varArgChild(m_node, 0);
2678 Edge child2 = m_graph.varArgChild(m_node, 1);
2679 Edge child3 = m_graph.varArgChild(m_node, 2);
2680 Edge child4 = m_graph.varArgChild(m_node, 3);
2681 Edge child5 = m_graph.varArgChild(m_node, 4);
2683 switch (m_node->arrayMode().type()) {
2684 case Array::Generic: {
2685 V_JITOperation_EJJJ operation;
2686 if (m_node->op() == PutByValDirect) {
2687 if (m_graph.isStrictModeFor(m_node->origin.semantic))
2688 operation = operationPutByValDirectStrict;
2690 operation = operationPutByValDirectNonStrict;
2692 if (m_graph.isStrictModeFor(m_node->origin.semantic))
2693 operation = operationPutByValStrict;
2695 operation = operationPutByValNonStrict;
2699 m_out.operation(operation), m_callFrame,
2700 lowJSValue(child1), lowJSValue(child2), lowJSValue(child3));
2708 LValue base = lowCell(child1);
2709 LValue index = lowInt32(child2);
2710 LValue storage = lowStorage(child4);
2712 switch (m_node->arrayMode().type()) {
2715 case Array::Contiguous: {
2716 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal continuation"));
2717 LBasicBlock outerLastNext = m_out.appendTo(m_out.m_block, continuation);
2719 switch (m_node->arrayMode().type()) {
2721 case Array::Contiguous: {
2722 LValue value = lowJSValue(child3, ManualOperandSpeculation);
2724 if (m_node->arrayMode().type() == Array::Int32)
2725 FTL_TYPE_CHECK(jsValueValue(value), child3, SpecInt32, isNotInt32(value));
2727 TypedPointer elementPointer = m_out.baseIndex(
2728 m_node->arrayMode().type() == Array::Int32 ?
2729 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties,
2730 storage, m_out.zeroExtPtr(index), provenValue(child2));
2732 if (m_node->op() == PutByValAlias) {
2733 m_out.store64(value, elementPointer);
2737 contiguousPutByValOutOfBounds(
2738 codeBlock()->isStrictMode()
2739 ? operationPutByValBeyondArrayBoundsStrict
2740 : operationPutByValBeyondArrayBoundsNonStrict,
2741 base, storage, index, value, continuation);
2743 m_out.store64(value, elementPointer);
2747 case Array::Double: {
2748 LValue value = lowDouble(child3);
2751 doubleValue(value), child3, SpecDoubleReal,
2752 m_out.doubleNotEqualOrUnordered(value, value));
2754 TypedPointer elementPointer = m_out.baseIndex(
2755 m_heaps.indexedDoubleProperties, storage, m_out.zeroExtPtr(index),
2756 provenValue(child2));
2758 if (m_node->op() == PutByValAlias) {
2759 m_out.storeDouble(value, elementPointer);
2763 contiguousPutByValOutOfBounds(
2764 codeBlock()->isStrictMode()
2765 ? operationPutDoubleByValBeyondArrayBoundsStrict
2766 : operationPutDoubleByValBeyondArrayBoundsNonStrict,
2767 base, storage, index, value, continuation);
2769 m_out.storeDouble(value, elementPointer);
2774 DFG_CRASH(m_graph, m_node, "Bad array type");
2777 m_out.jump(continuation);
2778 m_out.appendTo(continuation, outerLastNext);
2783 TypedArrayType type = m_node->arrayMode().typedArrayType();
2785 if (isTypedView(type)) {
2786 TypedPointer pointer = TypedPointer(
2787 m_heaps.typedArrayProperties,
2791 m_out.zeroExt(index, m_out.intPtr),
2792 m_out.constIntPtr(logElementSize(type)))));
2795 LValue valueToStore;
2799 switch (child3.useKind()) {
2802 if (child3.useKind() == Int32Use)
2803 intValue = lowInt32(child3);
2805 intValue = m_out.castToInt32(lowStrictInt52(child3));
2807 if (isClamped(type)) {
2808 ASSERT(elementSize(type) == 1);
2810 LBasicBlock atLeastZero = FTL_NEW_BLOCK(m_out, ("PutByVal int clamp atLeastZero"));
2811 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal int clamp continuation"));
2813 Vector<ValueFromBlock, 2> intValues;
2814 intValues.append(m_out.anchor(m_out.int32Zero));
2816 m_out.lessThan(intValue, m_out.int32Zero),
2817 unsure(continuation), unsure(atLeastZero));
2819 LBasicBlock lastNext = m_out.appendTo(atLeastZero, continuation);
2821 intValues.append(m_out.anchor(m_out.select(
2822 m_out.greaterThan(intValue, m_out.constInt32(255)),
2823 m_out.constInt32(255),
2825 m_out.jump(continuation);
2827 m_out.appendTo(continuation, lastNext);
2828 intValue = m_out.phi(m_out.int32, intValues);
2833 case DoubleRepUse: {
2834 LValue doubleValue = lowDouble(child3);
2836 if (isClamped(type)) {
2837 ASSERT(elementSize(type) == 1);
2839 LBasicBlock atLeastZero = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp atLeastZero"));
2840 LBasicBlock withinRange = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp withinRange"));
2841 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp continuation"));
2843 Vector<ValueFromBlock, 3> intValues;
2844 intValues.append(m_out.anchor(m_out.int32Zero));
2846 m_out.doubleLessThanOrUnordered(doubleValue, m_out.doubleZero),
2847 unsure(continuation), unsure(atLeastZero));
2849 LBasicBlock lastNext = m_out.appendTo(atLeastZero, withinRange);
2850 intValues.append(m_out.anchor(m_out.constInt32(255)));
2852 m_out.doubleGreaterThan(doubleValue, m_out.constDouble(255)),
2853 unsure(continuation), unsure(withinRange));
2855 m_out.appendTo(withinRange, continuation);
2856 intValues.append(m_out.anchor(m_out.fpToInt32(doubleValue)));
2857 m_out.jump(continuation);
2859 m_out.appendTo(continuation, lastNext);
2860 intValue = m_out.phi(m_out.int32, intValues);
2862 intValue = doubleToInt32(doubleValue);
2867 DFG_CRASH(m_graph, m_node, "Bad use kind");
2870 switch (elementSize(type)) {
2872 valueToStore = m_out.intCast(intValue, m_out.int8);
2873 refType = m_out.ref8;
2876 valueToStore = m_out.intCast(intValue, m_out.int16);
2877 refType = m_out.ref16;
2880 valueToStore = intValue;
2881 refType = m_out.ref32;
2884 DFG_CRASH(m_graph, m_node, "Bad element size");
2886 } else /* !isInt(type) */ {
2887 LValue value = lowDouble(child3);
2890 valueToStore = m_out.fpCast(value, m_out.floatType);
2891 refType = m_out.refFloat;
2894 valueToStore = value;
2895 refType = m_out.refDouble;
2898 DFG_CRASH(m_graph, m_node, "Bad typed array type");
2902 if (m_node->arrayMode().isInBounds() || m_node->op() == PutByValAlias)
2903 m_out.store(valueToStore, pointer, refType);
2905 LBasicBlock isInBounds = FTL_NEW_BLOCK(m_out, ("PutByVal typed array in bounds case"));
2906 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal typed array continuation"));
2909 m_out.aboveOrEqual(index, lowInt32(child5)),
2910 unsure(continuation), unsure(isInBounds));
2912 LBasicBlock lastNext = m_out.appendTo(isInBounds, continuation);
2913 m_out.store(valueToStore, pointer, refType);
2914 m_out.jump(continuation);
2916 m_out.appendTo(continuation, lastNext);
2922 DFG_CRASH(m_graph, m_node, "Bad array type");
2927 void compileArrayPush()
2929 LValue base = lowCell(m_node->child1());
2930 LValue storage = lowStorage(m_node->child3());
2932 switch (m_node->arrayMode().type()) {
2934 case Array::Contiguous:
2935 case Array::Double: {
2939 if (m_node->arrayMode().type() != Array::Double) {
2940 value = lowJSValue(m_node->child2(), ManualOperandSpeculation);
2941 if (m_node->arrayMode().type() == Array::Int32) {
2943 jsValueValue(value), m_node->child2(), SpecInt32, isNotInt32(value));
2945 refType = m_out.ref64;
2947 value = lowDouble(m_node->child2());
2949 doubleValue(value), m_node->child2(), SpecDoubleReal,
2950 m_out.doubleNotEqualOrUnordered(value, value));
2951 refType = m_out.refDouble;
2954 IndexedAbstractHeap& heap = m_heaps.forArrayType(m_node->arrayMode().type());
2956 LValue prevLength = m_out.load32(storage, m_heaps.Butterfly_publicLength);
2958 LBasicBlock fastPath = FTL_NEW_BLOCK(m_out, ("ArrayPush fast path"));
2959 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("ArrayPush slow path"));
2960 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArrayPush continuation"));
2964 prevLength, m_out.load32(storage, m_heaps.Butterfly_vectorLength)),
2965 rarely(slowPath), usually(fastPath));
2967 LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
2969 value, m_out.baseIndex(heap, storage, m_out.zeroExtPtr(prevLength)), refType);
2970 LValue newLength = m_out.add(prevLength, m_out.int32One);
2971 m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength);
2973 ValueFromBlock fastResult = m_out.anchor(boxInt32(newLength));
2974 m_out.jump(continuation);
2976 m_out.appendTo(slowPath, continuation);
2978 if (m_node->arrayMode().type() != Array::Double)
2979 operation = m_out.operation(operationArrayPush);
2981 operation = m_out.operation(operationArrayPushDouble);
2982 ValueFromBlock slowResult = m_out.anchor(
2983 vmCall(operation, m_callFrame, value, base));
2984 m_out.jump(continuation);
2986 m_out.appendTo(continuation, lastNext);
2987 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
2992 DFG_CRASH(m_graph, m_node, "Bad array type");
2997 void compileArrayPop()
2999 LValue base = lowCell(m_node->child1());
3000 LValue storage = lowStorage(m_node->child2());
3002 switch (m_node->arrayMode().type()) {
3005 case Array::Contiguous: {
3006 IndexedAbstractHeap& heap = m_heaps.forArrayType(m_node->arrayMode().type());
3008 LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("ArrayPop fast case"));
3009 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArrayPop slow case"));
3010 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArrayPop continuation"));
3012 LValue prevLength = m_out.load32(storage, m_heaps.Butterfly_publicLength);
3014 Vector<ValueFromBlock, 3> results;
3015 results.append(m_out.anchor(m_out.constInt64(JSValue::encode(jsUndefined()))));
3017 m_out.isZero32(prevLength), rarely(continuation), usually(fastCase));
3019 LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
3020 LValue newLength = m_out.sub(prevLength, m_out.int32One);
3021 m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength);
3022 TypedPointer pointer = m_out.baseIndex(heap, storage, m_out.zeroExtPtr(newLength));
3023 if (m_node->arrayMode().type() != Array::Double) {
3024 LValue result = m_out.load64(pointer);
3025 m_out.store64(m_out.int64Zero, pointer);
3026 results.append(m_out.anchor(result));
3028 m_out.notZero64(result), usually(continuation), rarely(slowCase));
3030 LValue result = m_out.loadDouble(pointer);
3031 m_out.store64(m_out.constInt64(bitwise_cast<int64_t>(PNaN)), pointer);
3032 results.append(m_out.anchor(boxDouble(result)));
3034 m_out.doubleEqual(result, result),
3035 usually(continuation), rarely(slowCase));
3038 m_out.appendTo(slowCase, continuation);
3039 results.append(m_out.anchor(vmCall(
3040 m_out.operation(operationArrayPopAndRecoverLength), m_callFrame, base)));
3041 m_out.jump(continuation);
3043 m_out.appendTo(continuation, lastNext);
3044 setJSValue(m_out.phi(m_out.int64, results));
3049 DFG_CRASH(m_graph, m_node, "Bad array type");