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 "ShadowChicken.h"
73 #include "StructureStubInfo.h"
74 #include "VirtualRegister.h"
80 #include <unordered_set>
82 #include <wtf/ProcessID.h>
84 namespace JSC { namespace FTL {
91 std::atomic<int> compileCounter;
94 NO_RETURN_DUE_TO_CRASH static void ftlUnreachable()
99 NO_RETURN_DUE_TO_CRASH static void ftlUnreachable(
100 CodeBlock* codeBlock, BlockIndex blockIndex, unsigned nodeIndex)
102 dataLog("Crashing in thought-to-be-unreachable FTL-generated code for ", pointerDump(codeBlock), " at basic block #", blockIndex);
103 if (nodeIndex != UINT_MAX)
104 dataLog(", node @", nodeIndex);
110 // Using this instead of typeCheck() helps to reduce the load on B3, by creating
111 // significantly less dead code.
112 #define FTL_TYPE_CHECK_WITH_EXIT_KIND(exitKind, lowValue, highValue, typesPassedThrough, failCondition) do { \
113 FormattedValue _ftc_lowValue = (lowValue); \
114 Edge _ftc_highValue = (highValue); \
115 SpeculatedType _ftc_typesPassedThrough = (typesPassedThrough); \
116 if (!m_interpreter.needsTypeCheck(_ftc_highValue, _ftc_typesPassedThrough)) \
118 typeCheck(_ftc_lowValue, _ftc_highValue, _ftc_typesPassedThrough, (failCondition), exitKind); \
121 #define FTL_TYPE_CHECK(lowValue, highValue, typesPassedThrough, failCondition) \
122 FTL_TYPE_CHECK_WITH_EXIT_KIND(BadType, lowValue, highValue, typesPassedThrough, failCondition)
125 WTF_MAKE_NONCOPYABLE(LowerDFGToB3);
127 LowerDFGToB3(State& state)
128 : m_graph(state.graph)
131 , m_proc(*state.proc)
132 , m_state(state.graph)
133 , m_interpreter(state.graph, m_state)
139 State* state = &m_ftlState;
142 if (verboseCompilationEnabled()) {
144 "jsBody_", ++compileCounter, "_", codeBlock()->inferredName(),
145 "_", codeBlock()->hash());
149 m_graph.ensureDominators();
151 if (verboseCompilationEnabled())
152 dataLog("Function ready, beginning lowering.\n");
154 m_out.initialize(m_heaps);
156 // We use prologue frequency for all of the initialization code.
157 m_out.setFrequency(1);
159 m_prologue = m_out.newBlock();
160 LBasicBlock stackOverflow = m_out.newBlock();
161 m_handleExceptions = m_out.newBlock();
163 LBasicBlock checkArguments = m_out.newBlock();
165 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
166 m_highBlock = m_graph.block(blockIndex);
169 m_out.setFrequency(m_highBlock->executionCount);
170 m_blocks.add(m_highBlock, m_out.newBlock());
173 // Back to prologue frequency for any bocks that get sneakily created in the initialization code.
174 m_out.setFrequency(1);
176 m_out.appendTo(m_prologue, stackOverflow);
177 m_out.initializeConstants(m_proc, m_prologue);
178 createPhiVariables();
180 size_t sizeOfCaptured = sizeof(JSValue) * m_graph.m_nextMachineLocal;
181 B3::SlotBaseValue* capturedBase = m_out.lockedStackSlot(sizeOfCaptured);
182 m_captured = m_out.add(capturedBase, m_out.constIntPtr(sizeOfCaptured));
183 state->capturedValue = capturedBase->slot();
185 auto preOrder = m_graph.blocksInPreOrder();
187 // We should not create any alloca's after this point, since they will cease to
188 // be mem2reg candidates.
190 m_callFrame = m_out.framePointer();
191 m_tagTypeNumber = m_out.constInt64(TagTypeNumber);
192 m_tagMask = m_out.constInt64(TagMask);
194 // Make sure that B3 knows that we really care about the mask registers. This forces the
195 // constants to be materialized in registers.
196 m_proc.addFastConstant(m_tagTypeNumber->key());
197 m_proc.addFastConstant(m_tagMask->key());
199 m_out.storePtr(m_out.constIntPtr(codeBlock()), addressFor(JSStack::CodeBlock));
202 didOverflowStack(), rarely(stackOverflow), usually(checkArguments));
204 m_out.appendTo(stackOverflow, m_handleExceptions);
205 m_out.call(m_out.voidType, m_out.operation(operationThrowStackOverflowError), m_callFrame, m_out.constIntPtr(codeBlock()));
206 m_out.patchpoint(Void)->setGenerator(
207 [=] (CCallHelpers& jit, const StackmapGenerationParams&) {
208 // We are terminal, so we can clobber everything. That's why we don't claim to
210 AllowMacroScratchRegisterUsage allowScratch(jit);
212 jit.copyCalleeSavesToVMCalleeSavesBuffer();
213 jit.move(CCallHelpers::TrustedImmPtr(jit.vm()), GPRInfo::argumentGPR0);
214 jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
215 CCallHelpers::Call call = jit.call();
216 jit.jumpToExceptionHandler();
219 [=] (LinkBuffer& linkBuffer) {
220 linkBuffer.link(call, FunctionPtr(lookupExceptionHandlerFromCallerFrame));
225 m_out.appendTo(m_handleExceptions, checkArguments);
226 Box<CCallHelpers::Label> exceptionHandler = state->exceptionHandler;
227 m_out.patchpoint(Void)->setGenerator(
228 [=] (CCallHelpers& jit, const StackmapGenerationParams&) {
229 CCallHelpers::Jump jump = jit.jump();
231 [=] (LinkBuffer& linkBuffer) {
232 linkBuffer.link(jump, linkBuffer.locationOf(*exceptionHandler));
237 m_out.appendTo(checkArguments, lowBlock(m_graph.block(0)));
238 availabilityMap().clear();
239 availabilityMap().m_locals = Operands<Availability>(codeBlock()->numParameters(), 0);
240 for (unsigned i = codeBlock()->numParameters(); i--;) {
241 availabilityMap().m_locals.argument(i) =
242 Availability(FlushedAt(FlushedJSValue, virtualRegisterForArgument(i)));
245 m_origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), true);
246 for (unsigned i = codeBlock()->numParameters(); i--;) {
247 Node* node = m_graph.m_arguments[i];
248 VirtualRegister operand = virtualRegisterForArgument(i);
250 LValue jsValue = m_out.load64(addressFor(operand));
253 DFG_ASSERT(m_graph, node, operand == node->stackAccessData()->machineLocal);
255 // This is a hack, but it's an effective one. It allows us to do CSE on the
256 // primordial load of arguments. This assumes that the GetLocal that got put in
257 // place of the original SetArgument doesn't have any effects before it. This
259 m_loadedArgumentValues.add(node, jsValue);
262 switch (m_graph.m_argumentFormats[i]) {
264 speculate(BadType, jsValueValue(jsValue), node, isNotInt32(jsValue));
267 speculate(BadType, jsValueValue(jsValue), node, isNotBoolean(jsValue));
270 speculate(BadType, jsValueValue(jsValue), node, isNotCell(jsValue));
275 DFG_CRASH(m_graph, node, "Bad flush format for argument");
279 m_out.jump(lowBlock(m_graph.block(0)));
281 for (DFG::BasicBlock* block : preOrder)
284 // Make sure everything is decorated. This does a bunch of deferred decorating. This has
285 // to happen last because our abstract heaps are generated lazily. They have to be
286 // generated lazily because we have an infiniten number of numbered, indexed, and
287 // absolute heaps. We only become aware of the ones we actually mention while lowering.
288 m_heaps.computeRangesAndDecorateInstructions();
290 // We create all Phi's up front, but we may then decide not to compile the basic block
291 // that would have contained one of them. So this creates orphans, which triggers B3
292 // validation failures. Calling this fixes the issue.
294 // Note that you should avoid the temptation to make this call conditional upon
295 // validation being enabled. B3 makes no guarantees of any kind of correctness when
296 // dealing with IR that would have failed validation. For example, it would be valid to
297 // write a B3 phase that so aggressively assumes the lack of orphans that it would crash
298 // if any orphans were around. We might even have such phases already.
299 m_proc.deleteOrphans();
301 // We put the blocks into the B3 procedure in a super weird order. Now we reorder them.
302 m_out.applyBlockOrder();
307 void createPhiVariables()
309 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
310 DFG::BasicBlock* block = m_graph.block(blockIndex);
313 for (unsigned nodeIndex = block->size(); nodeIndex--;) {
314 Node* node = block->at(nodeIndex);
315 if (node->op() != DFG::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, m_proc.add<Value>(B3::Phi, type, Origin(node)));
343 void compileBlock(DFG::BasicBlock* block)
348 if (verboseCompilationEnabled())
349 dataLog("Compiling block ", *block, "\n");
353 // Make sure that any blocks created while lowering code in the high block have the frequency of
354 // the high block. This is appropriate because B3 doesn't need precise frequencies. It just needs
355 // something roughly approximate for things like register allocation.
356 m_out.setFrequency(m_highBlock->executionCount);
358 LBasicBlock lowBlock = m_blocks.get(m_highBlock);
361 for (BlockIndex nextBlockIndex = m_highBlock->index + 1; nextBlockIndex < m_graph.numBlocks(); ++nextBlockIndex) {
362 m_nextHighBlock = m_graph.block(nextBlockIndex);
366 m_nextLowBlock = m_nextHighBlock ? m_blocks.get(m_nextHighBlock) : 0;
368 // All of this effort to find the next block gives us the ability to keep the
369 // generated IR in roughly program order. This ought not affect the performance
370 // of the generated code (since we expect B3 to reorder things) but it will
371 // make IR dumps easier to read.
372 m_out.appendTo(lowBlock, m_nextLowBlock);
374 if (Options::ftlCrashes())
377 if (!m_highBlock->cfaHasVisited) {
378 if (verboseCompilationEnabled())
379 dataLog("Bailing because CFA didn't reach.\n");
380 crash(m_highBlock->index, UINT_MAX);
384 m_availabilityCalculator.beginBlock(m_highBlock);
387 m_state.beginBasicBlock(m_highBlock);
389 for (m_nodeIndex = 0; m_nodeIndex < m_highBlock->size(); ++m_nodeIndex) {
390 if (!compileNode(m_nodeIndex))
395 void safelyInvalidateAfterTermination()
397 if (verboseCompilationEnabled())
398 dataLog("Bailing.\n");
401 // Invalidate dominated blocks. Under normal circumstances we would expect
402 // them to be invalidated already. But you can have the CFA become more
403 // precise over time because the structures of objects change on the main
404 // thread. Failing to do this would result in weird crashes due to a value
405 // being used but not defined. Race conditions FTW!
406 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
407 DFG::BasicBlock* target = m_graph.block(blockIndex);
410 if (m_graph.m_dominators->dominates(m_highBlock, target)) {
411 if (verboseCompilationEnabled())
412 dataLog("Block ", *target, " will bail also.\n");
413 target->cfaHasVisited = false;
418 bool compileNode(unsigned nodeIndex)
420 if (!m_state.isValid()) {
421 safelyInvalidateAfterTermination();
425 m_node = m_highBlock->at(nodeIndex);
426 m_origin = m_node->origin;
427 m_out.setOrigin(m_node);
429 if (verboseCompilationEnabled())
430 dataLog("Lowering ", m_node, "\n");
432 m_availableRecoveries.resize(0);
434 m_interpreter.startExecuting();
435 m_interpreter.executeKnownEdgeTypes(m_node);
437 switch (m_node->op()) {
447 compileDoubleConstant();
450 compileInt52Constant();
453 compileLazyJSConstant();
459 compileDoubleAsInt32();
468 compileValueToInt32();
470 case BooleanToNumber:
471 compileBooleanToNumber();
473 case ExtractOSREntryLocal:
474 compileExtractOSREntryLocal();
485 case CallObjectConstructor:
486 compileCallObjectConstructor();
499 compileArithAddOrSub();
515 compileArithMinOrMax();
530 compileArithRandom();
551 compileArithFRound();
554 compileArithNegate();
575 compileUInt32ToNumber();
578 compileCheckStructure();
584 compileCheckNotEmpty();
587 compileCheckBadCell();
593 compileGetExecutable();
595 case ArrayifyToStructure:
596 compileArrayifyToStructure();
599 compilePutStructure();
602 compileGetById(AccessType::GetPure);
606 compileGetById(AccessType::Get);
618 compilePutAccessorById();
620 case PutGetterSetterById:
621 compilePutGetterSetterById();
625 compilePutAccessorByVal();
628 compileGetButterfly();
630 case ConstantStoragePointer:
631 compileConstantStoragePointer();
633 case GetIndexedPropertyStorage:
634 compileGetIndexedPropertyStorage();
640 compileGetArrayLength();
643 compileCheckInBounds();
648 case GetMyArgumentByVal:
649 case GetMyArgumentByValOutOfBounds:
650 compileGetMyArgumentByVal();
663 case CreateActivation:
664 compileCreateActivation();
667 case NewGeneratorFunction:
668 compileNewFunction();
670 case CreateDirectArguments:
671 compileCreateDirectArguments();
673 case CreateScopedArguments:
674 compileCreateScopedArguments();
676 case CreateClonedArguments:
677 compileCreateClonedArguments();
686 compileNewArrayBuffer();
688 case NewArrayWithSize:
689 compileNewArrayWithSize();
692 compileNewTypedArray();
694 case GetTypedArrayByteOffset:
695 compileGetTypedArrayByteOffset();
697 case AllocatePropertyStorage:
698 compileAllocatePropertyStorage();
700 case ReallocatePropertyStorage:
701 compileReallocatePropertyStorage();
704 case CallStringConstructor:
705 compileToStringOrCallStringConstructor();
708 compileToPrimitive();
714 compileStringCharAt();
716 case StringCharCodeAt:
717 compileStringCharCodeAt();
719 case StringFromCharCode:
720 compileStringFromCharCode();
723 case GetGetterSetterByOffset:
724 compileGetByOffset();
732 case MultiGetByOffset:
733 compileMultiGetByOffset();
736 compilePutByOffset();
738 case MultiPutByOffset:
739 compileMultiPutByOffset();
742 case GetGlobalLexicalVariable:
743 compileGetGlobalVariable();
745 case PutGlobalVariable:
746 compilePutGlobalVariable();
749 compileNotifyWrite();
754 case GetArgumentCount:
755 compileGetArgumentCount();
763 case GetGlobalObject:
764 compileGetGlobalObject();
767 compileGetClosureVar();
770 compilePutClosureVar();
772 case GetFromArguments:
773 compileGetFromArguments();
776 compilePutToArguments();
781 case CompareStrictEq:
782 compileCompareStrictEq();
785 compileCompareLess();
788 compileCompareLessEq();
791 compileCompareGreater();
793 case CompareGreaterEq:
794 compileCompareGreaterEq();
800 case TailCallInlinedCaller:
802 compileCallOrConstruct();
808 case CallForwardVarargs:
809 case TailCallVarargs:
810 case TailCallVarargsInlinedCaller:
811 case TailCallForwardVarargs:
812 case TailCallForwardVarargsInlinedCaller:
813 case ConstructVarargs:
814 case ConstructForwardVarargs:
815 compileCallOrConstructVarargs();
818 compileLoadVarargs();
821 compileForwardVarargs();
836 compileForceOSRExit();
839 case ThrowReferenceError:
842 case InvalidationPoint:
843 compileInvalidationPoint();
846 compileIsUndefined();
858 compileIsArrayObject();
863 case IsArrayConstructor:
864 compileIsArrayConstructor();
870 compileIsObjectOrNull();
876 compileIsRegExpObject();
881 case CheckTypeInfoFlags:
882 compileCheckTypeInfoFlags();
884 case OverridesHasInstance:
885 compileOverridesHasInstance();
890 case InstanceOfCustom:
891 compileInstanceOfCustom();
894 compileCountExecution();
897 compileStoreBarrier();
899 case HasIndexedProperty:
900 compileHasIndexedProperty();
902 case HasGenericProperty:
903 compileHasGenericProperty();
905 case HasStructureProperty:
906 compileHasStructureProperty();
909 compileGetDirectPname();
911 case GetEnumerableLength:
912 compileGetEnumerableLength();
914 case GetPropertyEnumerator:
915 compileGetPropertyEnumerator();
917 case GetEnumeratorStructurePname:
918 compileGetEnumeratorStructurePname();
920 case GetEnumeratorGenericPname:
921 compileGetEnumeratorGenericPname();
924 compileToIndexString();
926 case CheckStructureImmediate:
927 compileCheckStructureImmediate();
929 case MaterializeNewObject:
930 compileMaterializeNewObject();
932 case MaterializeCreateActivation:
933 compileMaterializeCreateActivation();
935 case CheckWatchdogTimer:
936 compileCheckWatchdogTimer();
942 compileGetRestLength();
953 case SetFunctionName:
954 compileSetFunctionName();
957 compileStringReplace();
959 case GetRegExpObjectLastIndex:
960 compileGetRegExpObjectLastIndex();
962 case SetRegExpObjectLastIndex:
963 compileSetRegExpObjectLastIndex();
965 case LogShadowChickenPrologue:
966 compileLogShadowChickenPrologue();
968 case LogShadowChickenTail:
969 compileLogShadowChickenTail();
971 case RecordRegExpCachedResult:
972 compileRecordRegExpCachedResult();
975 compileResolveScope();
978 compileGetDynamicVar();
981 compilePutDynamicVar();
989 case PhantomNewObject:
990 case PhantomNewFunction:
991 case PhantomNewGeneratorFunction:
992 case PhantomCreateActivation:
993 case PhantomDirectArguments:
994 case PhantomClonedArguments:
1000 DFG_CRASH(m_graph, m_node, "Unrecognized node in FTL backend");
1004 if (m_node->isTerminal())
1007 if (!m_state.isValid()) {
1008 safelyInvalidateAfterTermination();
1012 m_availabilityCalculator.executeNode(m_node);
1013 m_interpreter.executeEffects(nodeIndex);
1018 void compileUpsilon()
1020 LValue upsilonValue = nullptr;
1021 switch (m_node->child1().useKind()) {
1023 upsilonValue = lowDouble(m_node->child1());
1027 upsilonValue = lowInt32(m_node->child1());
1030 upsilonValue = lowInt52(m_node->child1());
1033 case KnownBooleanUse:
1034 upsilonValue = lowBoolean(m_node->child1());
1038 upsilonValue = lowCell(m_node->child1());
1041 upsilonValue = lowJSValue(m_node->child1());
1044 DFG_CRASH(m_graph, m_node, "Bad use kind");
1047 ValueFromBlock upsilon = m_out.anchor(upsilonValue);
1048 LValue phiNode = m_phis.get(m_node->phi());
1049 m_out.addIncomingToPhi(phiNode, upsilon);
1054 LValue phi = m_phis.get(m_node);
1055 m_out.m_block->append(phi);
1057 switch (m_node->flags() & NodeResultMask) {
1058 case NodeResultDouble:
1061 case NodeResultInt32:
1064 case NodeResultInt52:
1067 case NodeResultBoolean:
1074 DFG_CRASH(m_graph, m_node, "Bad use kind");
1079 void compileDoubleConstant()
1081 setDouble(m_out.constDouble(m_node->asNumber()));
1084 void compileInt52Constant()
1086 int64_t value = m_node->asAnyInt();
1088 setInt52(m_out.constInt64(value << JSValue::int52ShiftAmount));
1089 setStrictInt52(m_out.constInt64(value));
1092 void compileLazyJSConstant()
1094 PatchpointValue* patchpoint = m_out.patchpoint(Int64);
1095 LazyJSValue value = m_node->lazyJSValue();
1096 patchpoint->setGenerator(
1097 [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
1098 value.emit(jit, JSValueRegs(params[0].gpr()));
1100 patchpoint->effects = Effects::none();
1101 setJSValue(patchpoint);
1104 void compileDoubleRep()
1106 switch (m_node->child1().useKind()) {
1107 case RealNumberUse: {
1108 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
1110 LValue doubleValue = unboxDouble(value);
1112 LBasicBlock intCase = m_out.newBlock();
1113 LBasicBlock continuation = m_out.newBlock();
1115 ValueFromBlock fastResult = m_out.anchor(doubleValue);
1117 m_out.doubleEqual(doubleValue, doubleValue),
1118 usually(continuation), rarely(intCase));
1120 LBasicBlock lastNext = m_out.appendTo(intCase, continuation);
1123 jsValueValue(value), m_node->child1(), SpecBytecodeRealNumber,
1124 isNotInt32(value, provenType(m_node->child1()) & ~SpecFullDouble));
1125 ValueFromBlock slowResult = m_out.anchor(m_out.intToDouble(unboxInt32(value)));
1126 m_out.jump(continuation);
1128 m_out.appendTo(continuation, lastNext);
1130 setDouble(m_out.phi(m_out.doubleType, fastResult, slowResult));
1136 bool shouldConvertNonNumber = m_node->child1().useKind() == NotCellUse;
1138 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
1140 LBasicBlock intCase = m_out.newBlock();
1141 LBasicBlock doubleTesting = m_out.newBlock();
1142 LBasicBlock doubleCase = m_out.newBlock();
1143 LBasicBlock nonDoubleCase = m_out.newBlock();
1144 LBasicBlock continuation = m_out.newBlock();
1147 isNotInt32(value, provenType(m_node->child1())),
1148 unsure(doubleTesting), unsure(intCase));
1150 LBasicBlock lastNext = m_out.appendTo(intCase, doubleTesting);
1152 ValueFromBlock intToDouble = m_out.anchor(
1153 m_out.intToDouble(unboxInt32(value)));
1154 m_out.jump(continuation);
1156 m_out.appendTo(doubleTesting, doubleCase);
1157 LValue valueIsNumber = isNumber(value, provenType(m_node->child1()));
1158 m_out.branch(valueIsNumber, usually(doubleCase), rarely(nonDoubleCase));
1160 m_out.appendTo(doubleCase, nonDoubleCase);
1161 ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(value));
1162 m_out.jump(continuation);
1164 if (shouldConvertNonNumber) {
1165 LBasicBlock undefinedCase = m_out.newBlock();
1166 LBasicBlock testNullCase = m_out.newBlock();
1167 LBasicBlock nullCase = m_out.newBlock();
1168 LBasicBlock testBooleanTrueCase = m_out.newBlock();
1169 LBasicBlock convertBooleanTrueCase = m_out.newBlock();
1170 LBasicBlock convertBooleanFalseCase = m_out.newBlock();
1172 m_out.appendTo(nonDoubleCase, undefinedCase);
1173 LValue valueIsUndefined = m_out.equal(value, m_out.constInt64(ValueUndefined));
1174 m_out.branch(valueIsUndefined, unsure(undefinedCase), unsure(testNullCase));
1176 m_out.appendTo(undefinedCase, testNullCase);
1177 ValueFromBlock convertedUndefined = m_out.anchor(m_out.constDouble(PNaN));
1178 m_out.jump(continuation);
1180 m_out.appendTo(testNullCase, nullCase);
1181 LValue valueIsNull = m_out.equal(value, m_out.constInt64(ValueNull));
1182 m_out.branch(valueIsNull, unsure(nullCase), unsure(testBooleanTrueCase));
1184 m_out.appendTo(nullCase, testBooleanTrueCase);
1185 ValueFromBlock convertedNull = m_out.anchor(m_out.constDouble(0));
1186 m_out.jump(continuation);
1188 m_out.appendTo(testBooleanTrueCase, convertBooleanTrueCase);
1189 LValue valueIsBooleanTrue = m_out.equal(value, m_out.constInt64(ValueTrue));
1190 m_out.branch(valueIsBooleanTrue, unsure(convertBooleanTrueCase), unsure(convertBooleanFalseCase));
1192 m_out.appendTo(convertBooleanTrueCase, convertBooleanFalseCase);
1193 ValueFromBlock convertedTrue = m_out.anchor(m_out.constDouble(1));
1194 m_out.jump(continuation);
1196 m_out.appendTo(convertBooleanFalseCase, continuation);
1198 LValue valueIsNotBooleanFalse = m_out.notEqual(value, m_out.constInt64(ValueFalse));
1199 FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), ~SpecCell, valueIsNotBooleanFalse);
1200 ValueFromBlock convertedFalse = m_out.anchor(m_out.constDouble(0));
1201 m_out.jump(continuation);
1203 m_out.appendTo(continuation, lastNext);
1204 setDouble(m_out.phi(m_out.doubleType, intToDouble, unboxedDouble, convertedUndefined, convertedNull, convertedTrue, convertedFalse));
1207 m_out.appendTo(nonDoubleCase, continuation);
1208 FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), SpecBytecodeNumber, m_out.booleanTrue);
1209 m_out.unreachable();
1211 m_out.appendTo(continuation, lastNext);
1213 setDouble(m_out.phi(m_out.doubleType, intToDouble, unboxedDouble));
1218 setDouble(strictInt52ToDouble(lowStrictInt52(m_node->child1())));
1223 DFG_CRASH(m_graph, m_node, "Bad use kind");
1227 void compileDoubleAsInt32()
1229 LValue integerValue = convertDoubleToInt32(lowDouble(m_node->child1()), shouldCheckNegativeZero(m_node->arithMode()));
1230 setInt32(integerValue);
1233 void compileValueRep()
1235 switch (m_node->child1().useKind()) {
1236 case DoubleRepUse: {
1237 LValue value = lowDouble(m_node->child1());
1239 if (m_interpreter.needsTypeCheck(m_node->child1(), ~SpecDoubleImpureNaN)) {
1240 value = m_out.select(
1241 m_out.doubleEqual(value, value), value, m_out.constDouble(PNaN));
1244 setJSValue(boxDouble(value));
1249 setJSValue(strictInt52ToJSValue(lowStrictInt52(m_node->child1())));
1254 DFG_CRASH(m_graph, m_node, "Bad use kind");
1258 void compileInt52Rep()
1260 switch (m_node->child1().useKind()) {
1262 setStrictInt52(m_out.signExt32To64(lowInt32(m_node->child1())));
1267 jsValueToStrictInt52(
1268 m_node->child1(), lowJSValue(m_node->child1(), ManualOperandSpeculation)));
1271 case DoubleRepAnyIntUse:
1273 doubleToStrictInt52(
1274 m_node->child1(), lowDouble(m_node->child1())));
1278 RELEASE_ASSERT_NOT_REACHED();
1282 void compileValueToInt32()
1284 switch (m_node->child1().useKind()) {
1286 setInt32(m_out.castToInt32(lowStrictInt52(m_node->child1())));
1290 setInt32(doubleToInt32(lowDouble(m_node->child1())));
1295 LoweredNodeValue value = m_int32Values.get(m_node->child1().node());
1296 if (isValid(value)) {
1297 setInt32(value.value());
1301 value = m_jsValueValues.get(m_node->child1().node());
1302 if (isValid(value)) {
1303 setInt32(numberOrNotCellToInt32(m_node->child1(), value.value()));
1307 // We'll basically just get here for constants. But it's good to have this
1308 // catch-all since we often add new representations into the mix.
1310 numberOrNotCellToInt32(
1312 lowJSValue(m_node->child1(), ManualOperandSpeculation)));
1317 DFG_CRASH(m_graph, m_node, "Bad use kind");
1322 void compileBooleanToNumber()
1324 switch (m_node->child1().useKind()) {
1326 setInt32(m_out.zeroExt(lowBoolean(m_node->child1()), m_out.int32));
1331 LValue value = lowJSValue(m_node->child1());
1333 if (!m_interpreter.needsTypeCheck(m_node->child1(), SpecBoolInt32 | SpecBoolean)) {
1334 setInt32(m_out.bitAnd(m_out.castToInt32(value), m_out.int32One));
1338 LBasicBlock booleanCase = m_out.newBlock();
1339 LBasicBlock continuation = m_out.newBlock();
1341 ValueFromBlock notBooleanResult = m_out.anchor(value);
1343 isBoolean(value, provenType(m_node->child1())),
1344 unsure(booleanCase), unsure(continuation));
1346 LBasicBlock lastNext = m_out.appendTo(booleanCase, continuation);
1347 ValueFromBlock booleanResult = m_out.anchor(m_out.bitOr(
1348 m_out.zeroExt(unboxBoolean(value), m_out.int64), m_tagTypeNumber));
1349 m_out.jump(continuation);
1351 m_out.appendTo(continuation, lastNext);
1352 setJSValue(m_out.phi(m_out.int64, booleanResult, notBooleanResult));
1357 RELEASE_ASSERT_NOT_REACHED();
1362 void compileExtractOSREntryLocal()
1364 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(
1365 m_ftlState.jitCode->ftlForOSREntry()->entryBuffer()->dataBuffer());
1366 setJSValue(m_out.load64(m_out.absolute(buffer + m_node->unlinkedLocal().toLocal())));
1369 void compileGetStack()
1371 // GetLocals arise only for captured variables and arguments. For arguments, we might have
1372 // already loaded it.
1373 if (LValue value = m_loadedArgumentValues.get(m_node)) {
1378 StackAccessData* data = m_node->stackAccessData();
1379 AbstractValue& value = m_state.variables().operand(data->local);
1381 DFG_ASSERT(m_graph, m_node, isConcrete(data->format));
1382 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.
1384 if (isInt32Speculation(value.m_type))
1385 setInt32(m_out.load32(payloadFor(data->machineLocal)));
1387 setJSValue(m_out.load64(addressFor(data->machineLocal)));
1390 void compilePutStack()
1392 StackAccessData* data = m_node->stackAccessData();
1393 switch (data->format) {
1394 case FlushedJSValue: {
1395 LValue value = lowJSValue(m_node->child1());
1396 m_out.store64(value, addressFor(data->machineLocal));
1400 case FlushedDouble: {
1401 LValue value = lowDouble(m_node->child1());
1402 m_out.storeDouble(value, addressFor(data->machineLocal));
1406 case FlushedInt32: {
1407 LValue value = lowInt32(m_node->child1());
1408 m_out.store32(value, payloadFor(data->machineLocal));
1412 case FlushedInt52: {
1413 LValue value = lowInt52(m_node->child1());
1414 m_out.store64(value, addressFor(data->machineLocal));
1419 LValue value = lowCell(m_node->child1());
1420 m_out.store64(value, addressFor(data->machineLocal));
1424 case FlushedBoolean: {
1425 speculateBoolean(m_node->child1());
1427 lowJSValue(m_node->child1(), ManualOperandSpeculation),
1428 addressFor(data->machineLocal));
1433 DFG_CRASH(m_graph, m_node, "Bad flush format");
1440 DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, speculate);
1443 void compileCallObjectConstructor()
1445 LValue value = lowJSValue(m_node->child1());
1447 LBasicBlock isCellCase = m_out.newBlock();
1448 LBasicBlock slowCase = m_out.newBlock();
1449 LBasicBlock continuation = m_out.newBlock();
1451 m_out.branch(isCell(value, provenType(m_node->child1())), usually(isCellCase), rarely(slowCase));
1453 LBasicBlock lastNext = m_out.appendTo(isCellCase, slowCase);
1454 ValueFromBlock fastResult = m_out.anchor(value);
1455 m_out.branch(isObject(value), usually(continuation), rarely(slowCase));
1457 m_out.appendTo(slowCase, continuation);
1458 ValueFromBlock slowResult = m_out.anchor(vmCall(m_out.int64, m_out.operation(operationToObject), m_callFrame, value));
1459 m_out.jump(continuation);
1461 m_out.appendTo(continuation, lastNext);
1462 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
1465 void compileToThis()
1467 LValue value = lowJSValue(m_node->child1());
1469 LBasicBlock isCellCase = m_out.newBlock();
1470 LBasicBlock slowCase = m_out.newBlock();
1471 LBasicBlock continuation = m_out.newBlock();
1474 isCell(value, provenType(m_node->child1())), usually(isCellCase), rarely(slowCase));
1476 LBasicBlock lastNext = m_out.appendTo(isCellCase, slowCase);
1477 ValueFromBlock fastResult = m_out.anchor(value);
1480 m_out.load8ZeroExt32(value, m_heaps.JSCell_typeInfoFlags),
1481 m_out.constInt32(OverridesToThis)),
1482 usually(continuation), rarely(slowCase));
1484 m_out.appendTo(slowCase, continuation);
1485 J_JITOperation_EJ function;
1486 if (m_graph.isStrictModeFor(m_node->origin.semantic))
1487 function = operationToThisStrict;
1489 function = operationToThis;
1490 ValueFromBlock slowResult = m_out.anchor(
1491 vmCall(m_out.int64, m_out.operation(function), m_callFrame, value));
1492 m_out.jump(continuation);
1494 m_out.appendTo(continuation, lastNext);
1495 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
1498 void compileValueAdd()
1500 emitBinarySnippet<JITAddGenerator>(operationValueAdd);
1503 void compileStrCat()
1506 if (m_node->child3()) {
1508 m_out.int64, m_out.operation(operationStrCat3), m_callFrame,
1509 lowJSValue(m_node->child1(), ManualOperandSpeculation),
1510 lowJSValue(m_node->child2(), ManualOperandSpeculation),
1511 lowJSValue(m_node->child3(), ManualOperandSpeculation));
1514 m_out.int64, m_out.operation(operationStrCat2), m_callFrame,
1515 lowJSValue(m_node->child1(), ManualOperandSpeculation),
1516 lowJSValue(m_node->child2(), ManualOperandSpeculation));
1521 void compileArithAddOrSub()
1523 bool isSub = m_node->op() == ArithSub;
1524 switch (m_node->binaryUseKind()) {
1526 LValue left = lowInt32(m_node->child1());
1527 LValue right = lowInt32(m_node->child2());
1529 if (!shouldCheckOverflow(m_node->arithMode())) {
1530 setInt32(isSub ? m_out.sub(left, right) : m_out.add(left, right));
1534 CheckValue* result =
1535 isSub ? m_out.speculateSub(left, right) : m_out.speculateAdd(left, right);
1536 blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
1542 if (!abstractValue(m_node->child1()).couldBeType(SpecInt52Only)
1543 && !abstractValue(m_node->child2()).couldBeType(SpecInt52Only)) {
1545 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1546 LValue right = lowInt52(m_node->child2(), kind);
1547 setInt52(isSub ? m_out.sub(left, right) : m_out.add(left, right), kind);
1551 LValue left = lowInt52(m_node->child1());
1552 LValue right = lowInt52(m_node->child2());
1553 CheckValue* result =
1554 isSub ? m_out.speculateSub(left, right) : m_out.speculateAdd(left, right);
1555 blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
1560 case DoubleRepUse: {
1561 LValue C1 = lowDouble(m_node->child1());
1562 LValue C2 = lowDouble(m_node->child2());
1564 setDouble(isSub ? m_out.doubleSub(C1, C2) : m_out.doubleAdd(C1, C2));
1570 DFG_CRASH(m_graph, m_node, "Bad use kind");
1574 emitBinarySnippet<JITSubGenerator>(operationValueSub);
1579 DFG_CRASH(m_graph, m_node, "Bad use kind");
1584 void compileArithClz32()
1586 LValue operand = lowInt32(m_node->child1());
1587 setInt32(m_out.ctlz32(operand));
1590 void compileArithMul()
1592 switch (m_node->binaryUseKind()) {
1594 LValue left = lowInt32(m_node->child1());
1595 LValue right = lowInt32(m_node->child2());
1599 if (!shouldCheckOverflow(m_node->arithMode()))
1600 result = m_out.mul(left, right);
1602 CheckValue* speculation = m_out.speculateMul(left, right);
1603 blessSpeculation(speculation, Overflow, noValue(), nullptr, m_origin);
1604 result = speculation;
1607 if (shouldCheckNegativeZero(m_node->arithMode())) {
1608 LBasicBlock slowCase = m_out.newBlock();
1609 LBasicBlock continuation = m_out.newBlock();
1612 m_out.notZero32(result), usually(continuation), rarely(slowCase));
1614 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
1615 speculate(NegativeZero, noValue(), nullptr, m_out.lessThan(left, m_out.int32Zero));
1616 speculate(NegativeZero, noValue(), nullptr, m_out.lessThan(right, m_out.int32Zero));
1617 m_out.jump(continuation);
1618 m_out.appendTo(continuation, lastNext);
1627 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1628 LValue right = lowInt52(m_node->child2(), opposite(kind));
1630 CheckValue* result = m_out.speculateMul(left, right);
1631 blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
1633 if (shouldCheckNegativeZero(m_node->arithMode())) {
1634 LBasicBlock slowCase = m_out.newBlock();
1635 LBasicBlock continuation = m_out.newBlock();
1638 m_out.notZero64(result), usually(continuation), rarely(slowCase));
1640 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
1641 speculate(NegativeZero, noValue(), nullptr, m_out.lessThan(left, m_out.int64Zero));
1642 speculate(NegativeZero, noValue(), nullptr, m_out.lessThan(right, m_out.int64Zero));
1643 m_out.jump(continuation);
1644 m_out.appendTo(continuation, lastNext);
1651 case DoubleRepUse: {
1653 m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1658 emitBinarySnippet<JITMulGenerator>(operationValueMul);
1663 DFG_CRASH(m_graph, m_node, "Bad use kind");
1668 void compileArithDiv()
1670 switch (m_node->binaryUseKind()) {
1672 LValue numerator = lowInt32(m_node->child1());
1673 LValue denominator = lowInt32(m_node->child2());
1675 if (shouldCheckNegativeZero(m_node->arithMode())) {
1676 LBasicBlock zeroNumerator = m_out.newBlock();
1677 LBasicBlock numeratorContinuation = m_out.newBlock();
1680 m_out.isZero32(numerator),
1681 rarely(zeroNumerator), usually(numeratorContinuation));
1683 LBasicBlock innerLastNext = m_out.appendTo(zeroNumerator, numeratorContinuation);
1686 NegativeZero, noValue(), 0, m_out.lessThan(denominator, m_out.int32Zero));
1688 m_out.jump(numeratorContinuation);
1690 m_out.appendTo(numeratorContinuation, innerLastNext);
1693 if (shouldCheckOverflow(m_node->arithMode())) {
1694 LBasicBlock unsafeDenominator = m_out.newBlock();
1695 LBasicBlock continuation = m_out.newBlock();
1697 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
1699 m_out.above(adjustedDenominator, m_out.int32One),
1700 usually(continuation), rarely(unsafeDenominator));
1702 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
1703 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
1704 speculate(Overflow, noValue(), nullptr, m_out.isZero32(denominator));
1705 speculate(Overflow, noValue(), nullptr, m_out.equal(numerator, neg2ToThe31));
1706 m_out.jump(continuation);
1708 m_out.appendTo(continuation, lastNext);
1709 LValue result = m_out.div(numerator, denominator);
1711 Overflow, noValue(), 0,
1712 m_out.notEqual(m_out.mul(result, denominator), numerator));
1715 setInt32(m_out.chillDiv(numerator, denominator));
1720 case DoubleRepUse: {
1721 setDouble(m_out.doubleDiv(
1722 lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1727 emitBinarySnippet<JITDivGenerator, NeedScratchFPR>(operationValueDiv);
1732 DFG_CRASH(m_graph, m_node, "Bad use kind");
1737 void compileArithMod()
1739 switch (m_node->binaryUseKind()) {
1741 LValue numerator = lowInt32(m_node->child1());
1742 LValue denominator = lowInt32(m_node->child2());
1745 if (shouldCheckOverflow(m_node->arithMode())) {
1746 LBasicBlock unsafeDenominator = m_out.newBlock();
1747 LBasicBlock continuation = m_out.newBlock();
1749 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
1751 m_out.above(adjustedDenominator, m_out.int32One),
1752 usually(continuation), rarely(unsafeDenominator));
1754 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
1755 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
1756 speculate(Overflow, noValue(), nullptr, m_out.isZero32(denominator));
1757 speculate(Overflow, noValue(), nullptr, m_out.equal(numerator, neg2ToThe31));
1758 m_out.jump(continuation);
1760 m_out.appendTo(continuation, lastNext);
1761 LValue result = m_out.mod(numerator, denominator);
1764 remainder = m_out.chillMod(numerator, denominator);
1766 if (shouldCheckNegativeZero(m_node->arithMode())) {
1767 LBasicBlock negativeNumerator = m_out.newBlock();
1768 LBasicBlock numeratorContinuation = m_out.newBlock();
1771 m_out.lessThan(numerator, m_out.int32Zero),
1772 unsure(negativeNumerator), unsure(numeratorContinuation));
1774 LBasicBlock innerLastNext = m_out.appendTo(negativeNumerator, numeratorContinuation);
1776 speculate(NegativeZero, noValue(), 0, m_out.isZero32(remainder));
1778 m_out.jump(numeratorContinuation);
1780 m_out.appendTo(numeratorContinuation, innerLastNext);
1783 setInt32(remainder);
1787 case DoubleRepUse: {
1789 m_out.doubleMod(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1794 DFG_CRASH(m_graph, m_node, "Bad use kind");
1799 void compileArithMinOrMax()
1801 switch (m_node->binaryUseKind()) {
1803 LValue left = lowInt32(m_node->child1());
1804 LValue right = lowInt32(m_node->child2());
1808 m_node->op() == ArithMin
1809 ? m_out.lessThan(left, right)
1810 : m_out.lessThan(right, left),
1815 case DoubleRepUse: {
1816 LValue left = lowDouble(m_node->child1());
1817 LValue right = lowDouble(m_node->child2());
1819 LBasicBlock notLessThan = m_out.newBlock();
1820 LBasicBlock continuation = m_out.newBlock();
1822 Vector<ValueFromBlock, 2> results;
1824 results.append(m_out.anchor(left));
1826 m_node->op() == ArithMin
1827 ? m_out.doubleLessThan(left, right)
1828 : m_out.doubleGreaterThan(left, right),
1829 unsure(continuation), unsure(notLessThan));
1831 LBasicBlock lastNext = m_out.appendTo(notLessThan, continuation);
1832 results.append(m_out.anchor(m_out.select(
1833 m_node->op() == ArithMin
1834 ? m_out.doubleGreaterThanOrEqual(left, right)
1835 : m_out.doubleLessThanOrEqual(left, right),
1836 right, m_out.constDouble(PNaN))));
1837 m_out.jump(continuation);
1839 m_out.appendTo(continuation, lastNext);
1840 setDouble(m_out.phi(m_out.doubleType, results));
1845 DFG_CRASH(m_graph, m_node, "Bad use kind");
1850 void compileArithAbs()
1852 switch (m_node->child1().useKind()) {
1854 LValue value = lowInt32(m_node->child1());
1856 LValue mask = m_out.aShr(value, m_out.constInt32(31));
1857 LValue result = m_out.bitXor(mask, m_out.add(mask, value));
1859 if (shouldCheckOverflow(m_node->arithMode()))
1860 speculate(Overflow, noValue(), 0, m_out.lessThan(result, m_out.int32Zero));
1866 case DoubleRepUse: {
1867 setDouble(m_out.doubleAbs(lowDouble(m_node->child1())));
1872 DFG_CRASH(m_graph, m_node, "Bad use kind");
1877 void compileArithSin() { setDouble(m_out.doubleSin(lowDouble(m_node->child1()))); }
1879 void compileArithCos() { setDouble(m_out.doubleCos(lowDouble(m_node->child1()))); }
1881 void compileArithPow()
1883 if (m_node->child2().useKind() == Int32Use)
1884 setDouble(m_out.doublePowi(lowDouble(m_node->child1()), lowInt32(m_node->child2())));
1886 LValue base = lowDouble(m_node->child1());
1887 LValue exponent = lowDouble(m_node->child2());
1889 LBasicBlock integerExponentIsSmallBlock = m_out.newBlock();
1890 LBasicBlock integerExponentPowBlock = m_out.newBlock();
1891 LBasicBlock doubleExponentPowBlockEntry = m_out.newBlock();
1892 LBasicBlock nanExceptionExponentIsInfinity = m_out.newBlock();
1893 LBasicBlock nanExceptionBaseIsOne = m_out.newBlock();
1894 LBasicBlock powBlock = m_out.newBlock();
1895 LBasicBlock nanExceptionResultIsNaN = m_out.newBlock();
1896 LBasicBlock continuation = m_out.newBlock();
1898 LValue integerExponent = m_out.doubleToInt(exponent);
1899 LValue integerExponentConvertedToDouble = m_out.intToDouble(integerExponent);
1900 LValue exponentIsInteger = m_out.doubleEqual(exponent, integerExponentConvertedToDouble);
1901 m_out.branch(exponentIsInteger, unsure(integerExponentIsSmallBlock), unsure(doubleExponentPowBlockEntry));
1903 LBasicBlock lastNext = m_out.appendTo(integerExponentIsSmallBlock, integerExponentPowBlock);
1904 LValue integerExponentBelow1000 = m_out.below(integerExponent, m_out.constInt32(1000));
1905 m_out.branch(integerExponentBelow1000, usually(integerExponentPowBlock), rarely(doubleExponentPowBlockEntry));
1907 m_out.appendTo(integerExponentPowBlock, doubleExponentPowBlockEntry);
1908 ValueFromBlock powDoubleIntResult = m_out.anchor(m_out.doublePowi(base, integerExponent));
1909 m_out.jump(continuation);
1911 // If y is NaN, the result is NaN.
1912 m_out.appendTo(doubleExponentPowBlockEntry, nanExceptionExponentIsInfinity);
1913 LValue exponentIsNaN;
1914 if (provenType(m_node->child2()) & SpecDoubleNaN)
1915 exponentIsNaN = m_out.doubleNotEqualOrUnordered(exponent, exponent);
1917 exponentIsNaN = m_out.booleanFalse;
1918 m_out.branch(exponentIsNaN, rarely(nanExceptionResultIsNaN), usually(nanExceptionExponentIsInfinity));
1920 // If abs(x) is 1 and y is +infinity, the result is NaN.
1921 // If abs(x) is 1 and y is -infinity, the result is NaN.
1922 m_out.appendTo(nanExceptionExponentIsInfinity, nanExceptionBaseIsOne);
1923 LValue absoluteExponent = m_out.doubleAbs(exponent);
1924 LValue absoluteExponentIsInfinity = m_out.doubleEqual(absoluteExponent, m_out.constDouble(std::numeric_limits<double>::infinity()));
1925 m_out.branch(absoluteExponentIsInfinity, rarely(nanExceptionBaseIsOne), usually(powBlock));
1927 m_out.appendTo(nanExceptionBaseIsOne, powBlock);
1928 LValue absoluteBase = m_out.doubleAbs(base);
1929 LValue absoluteBaseIsOne = m_out.doubleEqual(absoluteBase, m_out.constDouble(1));
1930 m_out.branch(absoluteBaseIsOne, unsure(nanExceptionResultIsNaN), unsure(powBlock));
1932 m_out.appendTo(powBlock, nanExceptionResultIsNaN);
1933 ValueFromBlock powResult = m_out.anchor(m_out.doublePow(base, exponent));
1934 m_out.jump(continuation);
1936 m_out.appendTo(nanExceptionResultIsNaN, continuation);
1937 ValueFromBlock pureNan = m_out.anchor(m_out.constDouble(PNaN));
1938 m_out.jump(continuation);
1940 m_out.appendTo(continuation, lastNext);
1941 setDouble(m_out.phi(m_out.doubleType, powDoubleIntResult, powResult, pureNan));
1945 void compileArithRandom()
1947 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
1949 // Inlined WeakRandom::advance().
1950 // uint64_t x = m_low;
1951 void* lowAddress = reinterpret_cast<uint8_t*>(globalObject) + JSGlobalObject::weakRandomOffset() + WeakRandom::lowOffset();
1952 LValue low = m_out.load64(m_out.absolute(lowAddress));
1953 // uint64_t y = m_high;
1954 void* highAddress = reinterpret_cast<uint8_t*>(globalObject) + JSGlobalObject::weakRandomOffset() + WeakRandom::highOffset();
1955 LValue high = m_out.load64(m_out.absolute(highAddress));
1957 m_out.store64(high, m_out.absolute(lowAddress));
1960 LValue phase1 = m_out.bitXor(m_out.shl(low, m_out.constInt64(23)), low);
1963 LValue phase2 = m_out.bitXor(m_out.lShr(phase1, m_out.constInt64(17)), phase1);
1965 // x ^= y ^ (y >> 26);
1966 LValue phase3 = m_out.bitXor(m_out.bitXor(high, m_out.lShr(high, m_out.constInt64(26))), phase2);
1969 m_out.store64(phase3, m_out.absolute(highAddress));
1972 LValue random64 = m_out.add(phase3, high);
1974 // Extract random 53bit. [0, 53] bit is safe integer number ranges in double representation.
1975 LValue random53 = m_out.bitAnd(random64, m_out.constInt64((1ULL << 53) - 1));
1977 LValue double53Integer = m_out.intToDouble(random53);
1979 // Convert `(53bit double integer value) / (1 << 53)` to `(53bit double integer value) * (1.0 / (1 << 53))`.
1980 // In latter case, `1.0 / (1 << 53)` will become a double value represented as (mantissa = 0 & exp = 970, it means 1e-(2**54)).
1981 static const double scale = 1.0 / (1ULL << 53);
1983 // Multiplying 1e-(2**54) with the double integer does not change anything of the mantissa part of the double integer.
1984 // It just reduces the exp part of the given 53bit double integer.
1985 // (Except for 0.0. This is specially handled and in this case, exp just becomes 0.)
1986 // Now we get 53bit precision random double value in [0, 1).
1987 LValue result = m_out.doubleMul(double53Integer, m_out.constDouble(scale));
1992 void compileArithRound()
1994 LValue result = nullptr;
1996 if (producesInteger(m_node->arithRoundingMode()) && !shouldCheckNegativeZero(m_node->arithRoundingMode())) {
1997 LValue value = lowDouble(m_node->child1());
1998 result = m_out.doubleFloor(m_out.doubleAdd(value, m_out.constDouble(0.5)));
2000 LBasicBlock realPartIsMoreThanHalf = m_out.newBlock();
2001 LBasicBlock continuation = m_out.newBlock();
2003 LValue value = lowDouble(m_node->child1());
2004 LValue integerValue = m_out.doubleCeil(value);
2005 ValueFromBlock integerValueResult = m_out.anchor(integerValue);
2007 LValue realPart = m_out.doubleSub(integerValue, value);
2009 m_out.branch(m_out.doubleGreaterThanOrUnordered(realPart, m_out.constDouble(0.5)), unsure(realPartIsMoreThanHalf), unsure(continuation));
2011 LBasicBlock lastNext = m_out.appendTo(realPartIsMoreThanHalf, continuation);
2012 LValue integerValueRoundedDown = m_out.doubleSub(integerValue, m_out.constDouble(1));
2013 ValueFromBlock integerValueRoundedDownResult = m_out.anchor(integerValueRoundedDown);
2014 m_out.jump(continuation);
2015 m_out.appendTo(continuation, lastNext);
2017 result = m_out.phi(m_out.doubleType, integerValueResult, integerValueRoundedDownResult);
2020 if (producesInteger(m_node->arithRoundingMode())) {
2021 LValue integerValue = convertDoubleToInt32(result, shouldCheckNegativeZero(m_node->arithRoundingMode()));
2022 setInt32(integerValue);
2027 void compileArithFloor()
2029 LValue value = lowDouble(m_node->child1());
2030 LValue integerValue = m_out.doubleFloor(value);
2031 if (producesInteger(m_node->arithRoundingMode()))
2032 setInt32(convertDoubleToInt32(integerValue, shouldCheckNegativeZero(m_node->arithRoundingMode())));
2034 setDouble(integerValue);
2037 void compileArithCeil()
2039 LValue value = lowDouble(m_node->child1());
2040 LValue integerValue = m_out.doubleCeil(value);
2041 if (producesInteger(m_node->arithRoundingMode()))
2042 setInt32(convertDoubleToInt32(integerValue, shouldCheckNegativeZero(m_node->arithRoundingMode())));
2044 setDouble(integerValue);
2047 void compileArithTrunc()
2049 LValue value = lowDouble(m_node->child1());
2050 LValue result = m_out.doubleTrunc(value);
2051 if (producesInteger(m_node->arithRoundingMode()))
2052 setInt32(convertDoubleToInt32(result, shouldCheckNegativeZero(m_node->arithRoundingMode())));
2057 void compileArithSqrt() { setDouble(m_out.doubleSqrt(lowDouble(m_node->child1()))); }
2059 void compileArithLog() { setDouble(m_out.doubleLog(lowDouble(m_node->child1()))); }
2061 void compileArithFRound()
2063 setDouble(m_out.fround(lowDouble(m_node->child1())));
2066 void compileArithNegate()
2068 switch (m_node->child1().useKind()) {
2070 LValue value = lowInt32(m_node->child1());
2073 if (!shouldCheckOverflow(m_node->arithMode()))
2074 result = m_out.neg(value);
2075 else if (!shouldCheckNegativeZero(m_node->arithMode())) {
2076 CheckValue* check = m_out.speculateSub(m_out.int32Zero, value);
2077 blessSpeculation(check, Overflow, noValue(), nullptr, m_origin);
2080 speculate(Overflow, noValue(), 0, m_out.testIsZero32(value, m_out.constInt32(0x7fffffff)));
2081 result = m_out.neg(value);
2089 if (!abstractValue(m_node->child1()).couldBeType(SpecInt52Only)) {
2091 LValue value = lowWhicheverInt52(m_node->child1(), kind);
2092 LValue result = m_out.neg(value);
2093 if (shouldCheckNegativeZero(m_node->arithMode()))
2094 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
2095 setInt52(result, kind);
2099 LValue value = lowInt52(m_node->child1());
2100 CheckValue* result = m_out.speculateSub(m_out.int64Zero, value);
2101 blessSpeculation(result, Int52Overflow, noValue(), nullptr, m_origin);
2102 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
2107 case DoubleRepUse: {
2108 setDouble(m_out.doubleNeg(lowDouble(m_node->child1())));
2113 DFG_CRASH(m_graph, m_node, "Bad use kind");
2118 void compileBitAnd()
2120 if (m_node->isBinaryUseKind(UntypedUse)) {
2121 emitBinaryBitOpSnippet<JITBitAndGenerator>(operationValueBitAnd);
2124 setInt32(m_out.bitAnd(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
2129 if (m_node->isBinaryUseKind(UntypedUse)) {
2130 emitBinaryBitOpSnippet<JITBitOrGenerator>(operationValueBitOr);
2133 setInt32(m_out.bitOr(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
2136 void compileBitXor()
2138 if (m_node->isBinaryUseKind(UntypedUse)) {
2139 emitBinaryBitOpSnippet<JITBitXorGenerator>(operationValueBitXor);
2142 setInt32(m_out.bitXor(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
2145 void compileBitRShift()
2147 if (m_node->isBinaryUseKind(UntypedUse)) {
2148 emitRightShiftSnippet(JITRightShiftGenerator::SignedShift);
2151 setInt32(m_out.aShr(
2152 lowInt32(m_node->child1()),
2153 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2156 void compileBitLShift()
2158 if (m_node->isBinaryUseKind(UntypedUse)) {
2159 emitBinaryBitOpSnippet<JITLeftShiftGenerator>(operationValueBitLShift);
2163 lowInt32(m_node->child1()),
2164 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2167 void compileBitURShift()
2169 if (m_node->isBinaryUseKind(UntypedUse)) {
2170 emitRightShiftSnippet(JITRightShiftGenerator::UnsignedShift);
2173 setInt32(m_out.lShr(
2174 lowInt32(m_node->child1()),
2175 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2178 void compileUInt32ToNumber()
2180 LValue value = lowInt32(m_node->child1());
2182 if (doesOverflow(m_node->arithMode())) {
2183 setStrictInt52(m_out.zeroExtPtr(value));
2187 speculate(Overflow, noValue(), 0, m_out.lessThan(value, m_out.int32Zero));
2191 void compileCheckStructure()
2194 if (m_node->child1()->hasConstant())
2195 exitKind = BadConstantCache;
2197 exitKind = BadCache;
2199 switch (m_node->child1().useKind()) {
2201 case KnownCellUse: {
2202 LValue cell = lowCell(m_node->child1());
2205 m_out.load32(cell, m_heaps.JSCell_structureID), jsValueValue(cell),
2206 exitKind, m_node->structureSet(),
2207 [&] (Structure* structure) {
2208 return weakStructureID(structure);
2213 case CellOrOtherUse: {
2214 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
2216 LBasicBlock cellCase = m_out.newBlock();
2217 LBasicBlock notCellCase = m_out.newBlock();
2218 LBasicBlock continuation = m_out.newBlock();
2221 isCell(value, provenType(m_node->child1())), unsure(cellCase), unsure(notCellCase));
2223 LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase);
2225 m_out.load32(value, m_heaps.JSCell_structureID), jsValueValue(value),
2226 exitKind, m_node->structureSet(),
2227 [&] (Structure* structure) {
2228 return weakStructureID(structure);
2230 m_out.jump(continuation);
2232 m_out.appendTo(notCellCase, continuation);
2233 FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), SpecCell | SpecOther, isNotOther(value));
2234 m_out.jump(continuation);
2236 m_out.appendTo(continuation, lastNext);
2241 DFG_CRASH(m_graph, m_node, "Bad use kind");
2246 void compileCheckCell()
2248 LValue cell = lowCell(m_node->child1());
2251 BadCell, jsValueValue(cell), m_node->child1().node(),
2252 m_out.notEqual(cell, weakPointer(m_node->cellOperand()->cell())));
2255 void compileCheckBadCell()
2260 void compileCheckNotEmpty()
2262 speculate(TDZFailure, noValue(), nullptr, m_out.isZero64(lowJSValue(m_node->child1())));
2265 void compileCheckIdent()
2267 UniquedStringImpl* uid = m_node->uidOperand();
2268 if (uid->isSymbol()) {
2269 LValue symbol = lowSymbol(m_node->child1());
2270 LValue stringImpl = m_out.loadPtr(symbol, m_heaps.Symbol_privateName);
2271 speculate(BadIdent, noValue(), nullptr, m_out.notEqual(stringImpl, m_out.constIntPtr(uid)));
2273 LValue string = lowStringIdent(m_node->child1());
2274 LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
2275 speculate(BadIdent, noValue(), nullptr, m_out.notEqual(stringImpl, m_out.constIntPtr(uid)));
2279 void compileGetExecutable()
2281 LValue cell = lowCell(m_node->child1());
2282 speculateFunction(m_node->child1(), cell);
2283 setJSValue(m_out.loadPtr(cell, m_heaps.JSFunction_executable));
2286 void compileArrayifyToStructure()
2288 LValue cell = lowCell(m_node->child1());
2289 LValue property = !!m_node->child2() ? lowInt32(m_node->child2()) : 0;
2291 LBasicBlock unexpectedStructure = m_out.newBlock();
2292 LBasicBlock continuation = m_out.newBlock();
2294 LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
2297 m_out.notEqual(structureID, weakStructureID(m_node->structure())),
2298 rarely(unexpectedStructure), usually(continuation));
2300 LBasicBlock lastNext = m_out.appendTo(unexpectedStructure, continuation);
2303 switch (m_node->arrayMode().type()) {
2306 case Array::Contiguous:
2308 Uncountable, noValue(), 0,
2309 m_out.aboveOrEqual(property, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)));
2316 switch (m_node->arrayMode().type()) {
2318 vmCall(m_out.voidType, m_out.operation(operationEnsureInt32), m_callFrame, cell);
2321 vmCall(m_out.voidType, m_out.operation(operationEnsureDouble), m_callFrame, cell);
2323 case Array::Contiguous:
2324 vmCall(m_out.voidType, m_out.operation(operationEnsureContiguous), m_callFrame, cell);
2326 case Array::ArrayStorage:
2327 case Array::SlowPutArrayStorage:
2328 vmCall(m_out.voidType, m_out.operation(operationEnsureArrayStorage), m_callFrame, cell);
2331 DFG_CRASH(m_graph, m_node, "Bad array type");
2335 structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
2337 BadIndexingType, jsValueValue(cell), 0,
2338 m_out.notEqual(structureID, weakStructureID(m_node->structure())));
2339 m_out.jump(continuation);
2341 m_out.appendTo(continuation, lastNext);
2344 void compilePutStructure()
2346 m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node);
2348 Structure* oldStructure = m_node->transition()->previous;
2349 Structure* newStructure = m_node->transition()->next;
2350 ASSERT_UNUSED(oldStructure, oldStructure->indexingType() == newStructure->indexingType());
2351 ASSERT(oldStructure->typeInfo().inlineTypeFlags() == newStructure->typeInfo().inlineTypeFlags());
2352 ASSERT(oldStructure->typeInfo().type() == newStructure->typeInfo().type());
2354 LValue cell = lowCell(m_node->child1());
2356 weakStructureID(newStructure),
2357 cell, m_heaps.JSCell_structureID);
2360 void compileGetById(AccessType type)
2362 ASSERT(type == AccessType::Get || type == AccessType::GetPure);
2363 switch (m_node->child1().useKind()) {
2365 setJSValue(getById(lowCell(m_node->child1()), type));
2370 // This is pretty weird, since we duplicate the slow path both here and in the
2371 // code generated by the IC. We should investigate making this less bad.
2372 // https://bugs.webkit.org/show_bug.cgi?id=127830
2373 LValue value = lowJSValue(m_node->child1());
2375 LBasicBlock cellCase = m_out.newBlock();
2376 LBasicBlock notCellCase = m_out.newBlock();
2377 LBasicBlock continuation = m_out.newBlock();
2380 isCell(value, provenType(m_node->child1())), unsure(cellCase), unsure(notCellCase));
2382 LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase);
2383 ValueFromBlock cellResult = m_out.anchor(getById(value, type));
2384 m_out.jump(continuation);
2386 J_JITOperation_EJI getByIdFunction;
2387 if (type == AccessType::Get)
2388 getByIdFunction = operationGetByIdGeneric;
2390 getByIdFunction = operationTryGetByIdGeneric;
2392 m_out.appendTo(notCellCase, continuation);
2393 ValueFromBlock notCellResult = m_out.anchor(vmCall(
2394 m_out.int64, m_out.operation(getByIdFunction),
2396 m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()])));
2397 m_out.jump(continuation);
2399 m_out.appendTo(continuation, lastNext);
2400 setJSValue(m_out.phi(m_out.int64, cellResult, notCellResult));
2405 DFG_CRASH(m_graph, m_node, "Bad use kind");
2410 void compilePutById()
2412 Node* node = m_node;
2414 // See above; CellUse is easier so we do only that for now.
2415 ASSERT(node->child1().useKind() == CellUse);
2417 LValue base = lowCell(node->child1());
2418 LValue value = lowJSValue(node->child2());
2419 auto uid = m_graph.identifiers()[node->identifierNumber()];
2421 B3::PatchpointValue* patchpoint = m_out.patchpoint(Void);
2422 patchpoint->appendSomeRegister(base);
2423 patchpoint->appendSomeRegister(value);
2424 patchpoint->append(m_tagMask, ValueRep::reg(GPRInfo::tagMaskRegister));
2425 patchpoint->append(m_tagTypeNumber, ValueRep::reg(GPRInfo::tagTypeNumberRegister));
2426 patchpoint->clobber(RegisterSet::macroScratchRegisters());
2428 // FIXME: If this is a PutByIdFlush, we might want to late-clobber volatile registers.
2429 // https://bugs.webkit.org/show_bug.cgi?id=152848
2431 RefPtr<PatchpointExceptionHandle> exceptionHandle =
2432 preparePatchpointForExceptions(patchpoint);
2434 State* state = &m_ftlState;
2435 ECMAMode ecmaMode = m_graph.executableFor(node->origin.semantic)->ecmaMode();
2437 patchpoint->setGenerator(
2438 [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
2439 AllowMacroScratchRegisterUsage allowScratch(jit);
2441 CallSiteIndex callSiteIndex =
2442 state->jitCode->common.addUniqueCallSiteIndex(node->origin.semantic);
2444 Box<CCallHelpers::JumpList> exceptions =
2445 exceptionHandle->scheduleExitCreation(params)->jumps(jit);
2447 // JS setter call ICs generated by the PutById IC will need this.
2448 exceptionHandle->scheduleExitCreationForUnwind(params, callSiteIndex);
2450 auto generator = Box<JITPutByIdGenerator>::create(
2451 jit.codeBlock(), node->origin.semantic, callSiteIndex,
2452 params.unavailableRegisters(), JSValueRegs(params[0].gpr()),
2453 JSValueRegs(params[1].gpr()), GPRInfo::patchpointScratchRegister, ecmaMode,
2454 node->op() == PutByIdDirect ? Direct : NotDirect);
2456 generator->generateFastPath(jit);
2457 CCallHelpers::Label done = jit.label();
2460 [=] (CCallHelpers& jit) {
2461 AllowMacroScratchRegisterUsage allowScratch(jit);
2463 generator->slowPathJump().link(&jit);
2464 CCallHelpers::Label slowPathBegin = jit.label();
2465 CCallHelpers::Call slowPathCall = callOperation(
2466 *state, params.unavailableRegisters(), jit, node->origin.semantic,
2467 exceptions.get(), generator->slowPathFunction(), InvalidGPRReg,
2468 CCallHelpers::TrustedImmPtr(generator->stubInfo()), params[1].gpr(),
2469 params[0].gpr(), CCallHelpers::TrustedImmPtr(uid)).call();
2470 jit.jump().linkTo(done, &jit);
2472 generator->reportSlowPathCall(slowPathBegin, slowPathCall);
2475 [=] (LinkBuffer& linkBuffer) {
2476 generator->finalize(linkBuffer);
2482 void compileGetButterfly()
2484 setStorage(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSObject_butterfly));
2487 void compileConstantStoragePointer()
2489 setStorage(m_out.constIntPtr(m_node->storagePointer()));
2492 void compileGetIndexedPropertyStorage()
2494 LValue cell = lowCell(m_node->child1());
2496 if (m_node->arrayMode().type() == Array::String) {
2497 LBasicBlock slowPath = m_out.newBlock();
2498 LBasicBlock continuation = m_out.newBlock();
2500 LValue fastResultValue = m_out.loadPtr(cell, m_heaps.JSString_value);
2501 ValueFromBlock fastResult = m_out.anchor(fastResultValue);
2504 m_out.notNull(fastResultValue), usually(continuation), rarely(slowPath));
2506 LBasicBlock lastNext = m_out.appendTo(slowPath, continuation);
2508 ValueFromBlock slowResult = m_out.anchor(
2509 vmCall(m_out.intPtr, m_out.operation(operationResolveRope), m_callFrame, cell));
2511 m_out.jump(continuation);
2513 m_out.appendTo(continuation, lastNext);
2515 setStorage(m_out.loadPtr(m_out.phi(m_out.intPtr, fastResult, slowResult), m_heaps.StringImpl_data));
2519 setStorage(m_out.loadPtr(cell, m_heaps.JSArrayBufferView_vector));
2522 void compileCheckArray()
2524 Edge edge = m_node->child1();
2525 LValue cell = lowCell(edge);
2527 if (m_node->arrayMode().alreadyChecked(m_graph, m_node, abstractValue(edge)))
2531 BadIndexingType, jsValueValue(cell), 0,
2532 m_out.logicalNot(isArrayType(cell, m_node->arrayMode())));
2535 void compileGetTypedArrayByteOffset()
2537 LValue basePtr = lowCell(m_node->child1());
2539 LBasicBlock simpleCase = m_out.newBlock();
2540 LBasicBlock wastefulCase = m_out.newBlock();
2541 LBasicBlock continuation = m_out.newBlock();
2543 LValue mode = m_out.load32(basePtr, m_heaps.JSArrayBufferView_mode);
2545 m_out.notEqual(mode, m_out.constInt32(WastefulTypedArray)),
2546 unsure(simpleCase), unsure(wastefulCase));
2548 LBasicBlock lastNext = m_out.appendTo(simpleCase, wastefulCase);
2550 ValueFromBlock simpleOut = m_out.anchor(m_out.constIntPtr(0));
2552 m_out.jump(continuation);
2554 m_out.appendTo(wastefulCase, continuation);
2556 LValue vectorPtr = m_out.loadPtr(basePtr, m_heaps.JSArrayBufferView_vector);
2557 LValue butterflyPtr = m_out.loadPtr(basePtr, m_heaps.JSObject_butterfly);
2558 LValue arrayBufferPtr = m_out.loadPtr(butterflyPtr, m_heaps.Butterfly_arrayBuffer);
2559 LValue dataPtr = m_out.loadPtr(arrayBufferPtr, m_heaps.ArrayBuffer_data);
2561 ValueFromBlock wastefulOut = m_out.anchor(m_out.sub(vectorPtr, dataPtr));
2563 m_out.jump(continuation);
2564 m_out.appendTo(continuation, lastNext);
2566 setInt32(m_out.castToInt32(m_out.phi(m_out.intPtr, simpleOut, wastefulOut)));
2569 void compileGetArrayLength()
2571 switch (m_node->arrayMode().type()) {
2574 case Array::Contiguous: {
2575 setInt32(m_out.load32NonNegative(lowStorage(m_node->child2()), m_heaps.Butterfly_publicLength));
2579 case Array::String: {
2580 LValue string = lowCell(m_node->child1());
2581 setInt32(m_out.load32NonNegative(string, m_heaps.JSString_length));
2585 case Array::DirectArguments: {
2586 LValue arguments = lowCell(m_node->child1());
2588 ExoticObjectMode, noValue(), nullptr,
2589 m_out.notNull(m_out.loadPtr(arguments, m_heaps.DirectArguments_overrides)));
2590 setInt32(m_out.load32NonNegative(arguments, m_heaps.DirectArguments_length));
2594 case Array::ScopedArguments: {
2595 LValue arguments = lowCell(m_node->child1());
2597 ExoticObjectMode, noValue(), nullptr,
2598 m_out.notZero32(m_out.load8ZeroExt32(arguments, m_heaps.ScopedArguments_overrodeThings)));
2599 setInt32(m_out.load32NonNegative(arguments, m_heaps.ScopedArguments_totalLength));
2604 if (m_node->arrayMode().isSomeTypedArrayView()) {
2606 m_out.load32NonNegative(lowCell(m_node->child1()), m_heaps.JSArrayBufferView_length));
2610 DFG_CRASH(m_graph, m_node, "Bad array type");
2615 void compileCheckInBounds()
2618 OutOfBounds, noValue(), 0,
2619 m_out.aboveOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
2622 void compileGetByVal()
2624 switch (m_node->arrayMode().type()) {
2626 case Array::Contiguous: {
2627 LValue index = lowInt32(m_node->child2());
2628 LValue storage = lowStorage(m_node->child3());
2630 IndexedAbstractHeap& heap = m_node->arrayMode().type() == Array::Int32 ?
2631 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties;
2633 if (m_node->arrayMode().isInBounds()) {
2634 LValue result = m_out.load64(baseIndex(heap, storage, index, m_node->child2()));
2635 LValue isHole = m_out.isZero64(result);
2636 if (m_node->arrayMode().isSaneChain()) {
2638 m_graph, m_node, m_node->arrayMode().type() == Array::Contiguous);
2639 result = m_out.select(
2640 isHole, m_out.constInt64(JSValue::encode(jsUndefined())), result);
2642 speculate(LoadFromHole, noValue(), 0, isHole);
2647 LValue base = lowCell(m_node->child1());
2649 LBasicBlock fastCase = m_out.newBlock();
2650 LBasicBlock slowCase = m_out.newBlock();
2651 LBasicBlock continuation = m_out.newBlock();
2655 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
2656 rarely(slowCase), usually(fastCase));
2658 LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
2660 LValue fastResultValue = m_out.load64(baseIndex(heap, storage, index, m_node->child2()));
2661 ValueFromBlock fastResult = m_out.anchor(fastResultValue);
2663 m_out.isZero64(fastResultValue), rarely(slowCase), usually(continuation));
2665 m_out.appendTo(slowCase, continuation);
2666 ValueFromBlock slowResult = m_out.anchor(
2667 vmCall(m_out.int64, m_out.operation(operationGetByValArrayInt), m_callFrame, base, index));
2668 m_out.jump(continuation);
2670 m_out.appendTo(continuation, lastNext);
2671 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
2675 case Array::Double: {
2676 LValue index = lowInt32(m_node->child2());
2677 LValue storage = lowStorage(m_node->child3());
2679 IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties;
2681 if (m_node->arrayMode().isInBounds()) {
2682 LValue result = m_out.loadDouble(
2683 baseIndex(heap, storage, index, m_node->child2()));
2685 if (!m_node->arrayMode().isSaneChain()) {
2687 LoadFromHole, noValue(), 0,
2688 m_out.doubleNotEqualOrUnordered(result, result));
2694 LValue base = lowCell(m_node->child1());
2696 LBasicBlock inBounds = m_out.newBlock();
2697 LBasicBlock boxPath = m_out.newBlock();
2698 LBasicBlock slowCase = m_out.newBlock();
2699 LBasicBlock continuation = m_out.newBlock();
2703 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
2704 rarely(slowCase), usually(inBounds));
2706 LBasicBlock lastNext = m_out.appendTo(inBounds, boxPath);
2707 LValue doubleValue = m_out.loadDouble(
2708 baseIndex(heap, storage, index, m_node->child2()));
2710 m_out.doubleNotEqualOrUnordered(doubleValue, doubleValue),
2711 rarely(slowCase), usually(boxPath));
2713 m_out.appendTo(boxPath, slowCase);
2714 ValueFromBlock fastResult = m_out.anchor(boxDouble(doubleValue));
2715 m_out.jump(continuation);
2717 m_out.appendTo(slowCase, continuation);
2718 ValueFromBlock slowResult = m_out.anchor(
2719 vmCall(m_out.int64, m_out.operation(operationGetByValArrayInt), m_callFrame, base, index));
2720 m_out.jump(continuation);
2722 m_out.appendTo(continuation, lastNext);
2723 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
2727 case Array::Undecided: {
2728 LValue index = lowInt32(m_node->child2());
2730 speculate(OutOfBounds, noValue(), m_node, m_out.lessThan(index, m_out.int32Zero));
2731 setJSValue(m_out.constInt64(ValueUndefined));
2735 case Array::DirectArguments: {
2736 LValue base = lowCell(m_node->child1());
2737 LValue index = lowInt32(m_node->child2());
2740 ExoticObjectMode, noValue(), nullptr,
2741 m_out.notNull(m_out.loadPtr(base, m_heaps.DirectArguments_overrides)));
2743 ExoticObjectMode, noValue(), nullptr,
2746 m_out.load32NonNegative(base, m_heaps.DirectArguments_length)));
2748 TypedPointer address = m_out.baseIndex(
2749 m_heaps.DirectArguments_storage, base, m_out.zeroExtPtr(index));
2750 setJSValue(m_out.load64(address));
2754 case Array::ScopedArguments: {
2755 LValue base = lowCell(m_node->child1());
2756 LValue index = lowInt32(m_node->child2());
2759 ExoticObjectMode, noValue(), nullptr,
2762 m_out.load32NonNegative(base, m_heaps.ScopedArguments_totalLength)));
2764 LValue table = m_out.loadPtr(base, m_heaps.ScopedArguments_table);
2765 LValue namedLength = m_out.load32(table, m_heaps.ScopedArgumentsTable_length);
2767 LBasicBlock namedCase = m_out.newBlock();
2768 LBasicBlock overflowCase = m_out.newBlock();
2769 LBasicBlock continuation = m_out.newBlock();
2772 m_out.aboveOrEqual(index, namedLength), unsure(overflowCase), unsure(namedCase));
2774 LBasicBlock lastNext = m_out.appendTo(namedCase, overflowCase);
2776 LValue scope = m_out.loadPtr(base, m_heaps.ScopedArguments_scope);
2777 LValue arguments = m_out.loadPtr(table, m_heaps.ScopedArgumentsTable_arguments);
2779 TypedPointer address = m_out.baseIndex(
2780 m_heaps.scopedArgumentsTableArguments, arguments, m_out.zeroExtPtr(index));
2781 LValue scopeOffset = m_out.load32(address);
2784 ExoticObjectMode, noValue(), nullptr,
2785 m_out.equal(scopeOffset, m_out.constInt32(ScopeOffset::invalidOffset)));
2787 address = m_out.baseIndex(
2788 m_heaps.JSEnvironmentRecord_variables, scope, m_out.zeroExtPtr(scopeOffset));
2789 ValueFromBlock namedResult = m_out.anchor(m_out.load64(address));
2790 m_out.jump(continuation);
2792 m_out.appendTo(overflowCase, continuation);
2794 address = m_out.baseIndex(
2795 m_heaps.ScopedArguments_overflowStorage, base,
2796 m_out.zeroExtPtr(m_out.sub(index, namedLength)));
2797 LValue overflowValue = m_out.load64(address);
2798 speculate(ExoticObjectMode, noValue(), nullptr, m_out.isZero64(overflowValue));
2799 ValueFromBlock overflowResult = m_out.anchor(overflowValue);
2800 m_out.jump(continuation);
2802 m_out.appendTo(continuation, lastNext);
2803 setJSValue(m_out.phi(m_out.int64, namedResult, overflowResult));
2807 case Array::Generic: {
2809 m_out.int64, m_out.operation(operationGetByVal), m_callFrame,
2810 lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));
2814 case Array::String: {
2815 compileStringCharAt();
2820 LValue index = lowInt32(m_node->child2());
2821 LValue storage = lowStorage(m_node->child3());
2823 TypedArrayType type = m_node->arrayMode().typedArrayType();
2825 if (isTypedView(type)) {
2826 TypedPointer pointer = TypedPointer(
2827 m_heaps.typedArrayProperties,
2831 m_out.zeroExtPtr(index),
2832 m_out.constIntPtr(logElementSize(type)))));
2836 switch (elementSize(type)) {
2838 result = isSigned(type) ? m_out.load8SignExt32(pointer) : m_out.load8ZeroExt32(pointer);
2841 result = isSigned(type) ? m_out.load16SignExt32(pointer) : m_out.load16ZeroExt32(pointer);
2844 result = m_out.load32(pointer);
2847 DFG_CRASH(m_graph, m_node, "Bad element size");
2850 if (elementSize(type) < 4 || isSigned(type)) {
2855 if (m_node->shouldSpeculateInt32()) {
2857 Overflow, noValue(), 0, m_out.lessThan(result, m_out.int32Zero));
2862 if (m_node->shouldSpeculateAnyInt()) {
2863 setStrictInt52(m_out.zeroExt(result, m_out.int64));
2867 setDouble(m_out.unsignedToDouble(result));
2871 ASSERT(isFloat(type));
2876 result = m_out.floatToDouble(m_out.loadFloat(pointer));
2879 result = m_out.loadDouble(pointer);
2882 DFG_CRASH(m_graph, m_node, "Bad typed array type");
2889 DFG_CRASH(m_graph, m_node, "Bad array type");
2894 void compileGetMyArgumentByVal()
2896 InlineCallFrame* inlineCallFrame = m_node->child1()->origin.semantic.inlineCallFrame;
2898 LValue index = lowInt32(m_node->child2());
2901 if (inlineCallFrame && !inlineCallFrame->isVarargs())
2902 limit = m_out.constInt32(inlineCallFrame->arguments.size() - 1);
2904 VirtualRegister argumentCountRegister;
2905 if (!inlineCallFrame)
2906 argumentCountRegister = VirtualRegister(JSStack::ArgumentCount);
2908 argumentCountRegister = inlineCallFrame->argumentCountRegister;
2909 limit = m_out.sub(m_out.load32(payloadFor(argumentCountRegister)), m_out.int32One);
2912 LValue isOutOfBounds = m_out.aboveOrEqual(index, limit);
2913 LBasicBlock continuation = nullptr;
2914 LBasicBlock lastNext = nullptr;
2915 ValueFromBlock slowResult;
2916 if (m_node->op() == GetMyArgumentByValOutOfBounds) {
2917 LBasicBlock normalCase = m_out.newBlock();
2918 continuation = m_out.newBlock();
2920 slowResult = m_out.anchor(m_out.constInt64(JSValue::encode(jsUndefined())));
2921 m_out.branch(isOutOfBounds, unsure(continuation), unsure(normalCase));
2923 lastNext = m_out.appendTo(normalCase, continuation);
2925 speculate(ExoticObjectMode, noValue(), 0, isOutOfBounds);
2928 if (inlineCallFrame) {
2929 if (inlineCallFrame->arguments.size() > 1)
2930 base = addressFor(inlineCallFrame->arguments[1].virtualRegister());
2932 base = addressFor(virtualRegisterForArgument(1));
2936 LValue pointer = m_out.baseIndex(
2937 base.value(), m_out.zeroExt(index, m_out.intPtr), ScaleEight);
2938 result = m_out.load64(TypedPointer(m_heaps.variables.atAnyIndex(), pointer));
2940 result = m_out.constInt64(JSValue::encode(jsUndefined()));
2942 if (m_node->op() == GetMyArgumentByValOutOfBounds) {
2943 ValueFromBlock normalResult = m_out.anchor(result);
2944 m_out.jump(continuation);
2946 m_out.appendTo(continuation, lastNext);
2947 result = m_out.phi(Int64, slowResult, normalResult);
2953 void compilePutByVal()
2955 Edge child1 = m_graph.varArgChild(m_node, 0);
2956 Edge child2 = m_graph.varArgChild(m_node, 1);
2957 Edge child3 = m_graph.varArgChild(m_node, 2);
2958 Edge child4 = m_graph.varArgChild(m_node, 3);
2959 Edge child5 = m_graph.varArgChild(m_node, 4);
2961 switch (m_node->arrayMode().type()) {
2962 case Array::Generic: {
2963 V_JITOperation_EJJJ operation;
2964 if (m_node->op() == PutByValDirect) {
2965 if (m_graph.isStrictModeFor(m_node->origin.semantic))
2966 operation = operationPutByValDirectStrict;
2968 operation = operationPutByValDirectNonStrict;
2970 if (m_graph.isStrictModeFor(m_node->origin.semantic))
2971 operation = operationPutByValStrict;
2973 operation = operationPutByValNonStrict;
2977 m_out.voidType, m_out.operation(operation), m_callFrame,
2978 lowJSValue(child1), lowJSValue(child2), lowJSValue(child3));
2986 LValue base = lowCell(child1);
2987 LValue index = lowInt32(child2);
2988 LValue storage = lowStorage(child4);
2990 switch (m_node->arrayMode().type()) {
2993 case Array::Contiguous: {
2994 LBasicBlock continuation = m_out.newBlock();
2995 LBasicBlock outerLastNext = m_out.appendTo(m_out.m_block, continuation);
2997 switch (m_node->arrayMode().type()) {
2999 case Array::Contiguous: {
3000 LValue value = lowJSValue(child3, ManualOperandSpeculation);
3002 if (m_node->arrayMode().type() == Array::Int32)
3003 FTL_TYPE_CHECK(jsValueValue(value), child3, SpecInt32Only, isNotInt32(value));
3005 TypedPointer elementPointer = m_out.baseIndex(
3006 m_node->arrayMode().type() == Array::Int32 ?
3007 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties,
3008 storage, m_out.zeroExtPtr(index), provenValue(child2));
3010 if (m_node->op() == PutByValAlias) {
3011 m_out.store64(value, elementPointer);
3015 contiguousPutByValOutOfBounds(
3016 codeBlock()->isStrictMode()
3017 ? operationPutByValBeyondArrayBoundsStrict
3018 : operationPutByValBeyondArrayBoundsNonStrict,
3019 base, storage, index, value, continuation);
3021 m_out.store64(value, elementPointer);
3025 case Array::Double: {
3026 LValue value = lowDouble(child3);
3029 doubleValue(value), child3, SpecDoubleReal,
3030 m_out.doubleNotEqualOrUnordered(value, value));
3032 TypedPointer elementPointer = m_out.baseIndex(
3033 m_heaps.indexedDoubleProperties, storage, m_out.zeroExtPtr(index),
3034 provenValue(child2));
3036 if (m_node->op() == PutByValAlias) {
3037 m_out.storeDouble(value, elementPointer);
3041 contiguousPutByValOutOfBounds(
3042 codeBlock()->isStrictMode()
3043 ? operationPutDoubleByValBeyondArrayBoundsStrict
3044 : operationPutDoubleByValBeyondArrayBoundsNonStrict,
3045 base, storage, index, value, continuation);
3047 m_out.storeDouble(value, elementPointer);
3052 DFG_CRASH(m_graph, m_node, "Bad array type");
3055 m_out.jump(continuation);
3056 m_out.appendTo(continuation, outerLastNext);
3061 TypedArrayType type = m_node->arrayMode().typedArrayType();
3063 if (isTypedView(type)) {
3064 TypedPointer pointer = TypedPointer(
3065 m_heaps.typedArrayProperties,
3069 m_out.zeroExt(index, m_out.intPtr),
3070 m_out.constIntPtr(logElementSize(type)))));
3072 Output::StoreType storeType;
3073 LValue valueToStore;
3077 switch (child3.useKind()) {
3080 if (child3.useKind() == Int32Use)
3081 intValue = lowInt32(child3);
3083 intValue = m_out.castToInt32(lowStrictInt52(child3));
3085 if (isClamped(type)) {
3086 ASSERT(elementSize(type) == 1);
3088 LBasicBlock atLeastZero = m_out.newBlock();
3089 LBasicBlock continuation = m_out.newBlock();
3091 Vector<ValueFromBlock, 2> intValues;
3092 intValues.append(m_out.anchor(m_out.int32Zero));
3094 m_out.lessThan(intValue, m_out.int32Zero),
3095 unsure(continuation), unsure(atLeastZero));
3097 LBasicBlock lastNext = m_out.appendTo(atLeastZero, continuation);
3099 intValues.append(m_out.anchor(m_out.select(
3100 m_out.greaterThan(intValue, m_out.constInt32(255)),
3101 m_out.constInt32(255),
3103 m_out.jump(continuation);
3105 m_out.appendTo(continuation, lastNext);
3106 intValue = m_out.phi(m_out.int32, intValues);
3111 case DoubleRepUse: {
3112 LValue doubleValue = lowDouble(child3);
3114 if (isClamped(type)) {
3115 ASSERT(elementSize(type) == 1);
3117 LBasicBlock atLeastZero = m_out.newBlock();
3118 LBasicBlock withinRange = m_out.newBlock();
3119 LBasicBlock continuation = m_out.newBlock();
3121 Vector<ValueFromBlock, 3> intValues;
3122 intValues.append(m_out.anchor(m_out.int32Zero));
3124 m_out.doubleLessThanOrUnordered(doubleValue, m_out.doubleZero),
3125 unsure(continuation), unsure(atLeastZero));
3127 LBasicBlock lastNext = m_out.appendTo(atLeastZero, withinRange);
3128 intValues.append(m_out.anchor(m_out.constInt32(255)));
3130 m_out.doubleGreaterThan(doubleValue, m_out.constDouble(255)),
3131 unsure(continuation), unsure(withinRange));
3133 m_out.appendTo(withinRange, continuation);
3134 intValues.append(m_out.anchor(m_out.doubleToInt(doubleValue)));
3135 m_out.jump(continuation);