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 "B3CheckValue.h"
34 #include "B3FenceValue.h"
35 #include "B3PatchpointValue.h"
36 #include "B3SlotBaseValue.h"
37 #include "B3StackmapGenerationParams.h"
38 #include "B3ValueInlines.h"
39 #include "CallFrameShuffler.h"
40 #include "CodeBlockWithJITType.h"
41 #include "DFGAbstractInterpreterInlines.h"
42 #include "DFGCapabilities.h"
43 #include "DFGDominators.h"
44 #include "DFGInPlaceAbstractState.h"
45 #include "DFGOSRAvailabilityAnalysisPhase.h"
46 #include "DFGOSRExitFuzz.h"
47 #include "DOMJITPatchpoint.h"
48 #include "DirectArguments.h"
49 #include "FTLAbstractHeapRepository.h"
50 #include "FTLAvailableRecovery.h"
51 #include "FTLDOMJITPatchpointParams.h"
52 #include "FTLExceptionTarget.h"
53 #include "FTLForOSREntryJITCode.h"
54 #include "FTLFormattedValue.h"
55 #include "FTLLazySlowPathCall.h"
56 #include "FTLLoweredNodeValue.h"
57 #include "FTLOperations.h"
58 #include "FTLOutput.h"
59 #include "FTLPatchpointExceptionHandle.h"
60 #include "FTLThunks.h"
61 #include "FTLWeightedTarget.h"
62 #include "JITAddGenerator.h"
63 #include "JITBitAndGenerator.h"
64 #include "JITBitOrGenerator.h"
65 #include "JITBitXorGenerator.h"
66 #include "JITDivGenerator.h"
67 #include "JITInlineCacheGenerator.h"
68 #include "JITLeftShiftGenerator.h"
69 #include "JITMathIC.h"
70 #include "JITMulGenerator.h"
71 #include "JITRightShiftGenerator.h"
72 #include "JITSubGenerator.h"
73 #include "JSCInlines.h"
74 #include "JSGeneratorFunction.h"
75 #include "JSLexicalEnvironment.h"
77 #include "OperandsInlines.h"
78 #include "ScopedArguments.h"
79 #include "ScopedArgumentsTable.h"
80 #include "ScratchRegisterAllocator.h"
81 #include "SetupVarargsFrame.h"
82 #include "ShadowChicken.h"
83 #include "StructureStubInfo.h"
84 #include "VirtualRegister.h"
90 #include <unordered_set>
92 #include <wtf/ProcessID.h>
94 namespace JSC { namespace FTL {
101 std::atomic<int> compileCounter;
104 NO_RETURN_DUE_TO_CRASH static void ftlUnreachable(
105 CodeBlock* codeBlock, BlockIndex blockIndex, unsigned nodeIndex)
107 dataLog("Crashing in thought-to-be-unreachable FTL-generated code for ", pointerDump(codeBlock), " at basic block #", blockIndex);
108 if (nodeIndex != UINT_MAX)
109 dataLog(", node @", nodeIndex);
115 // Using this instead of typeCheck() helps to reduce the load on B3, by creating
116 // significantly less dead code.
117 #define FTL_TYPE_CHECK_WITH_EXIT_KIND(exitKind, lowValue, highValue, typesPassedThrough, failCondition) do { \
118 FormattedValue _ftc_lowValue = (lowValue); \
119 Edge _ftc_highValue = (highValue); \
120 SpeculatedType _ftc_typesPassedThrough = (typesPassedThrough); \
121 if (!m_interpreter.needsTypeCheck(_ftc_highValue, _ftc_typesPassedThrough)) \
123 typeCheck(_ftc_lowValue, _ftc_highValue, _ftc_typesPassedThrough, (failCondition), exitKind); \
126 #define FTL_TYPE_CHECK(lowValue, highValue, typesPassedThrough, failCondition) \
127 FTL_TYPE_CHECK_WITH_EXIT_KIND(BadType, lowValue, highValue, typesPassedThrough, failCondition)
130 WTF_MAKE_NONCOPYABLE(LowerDFGToB3);
132 LowerDFGToB3(State& state)
133 : m_graph(state.graph)
136 , m_proc(*state.proc)
137 , m_availabilityCalculator(m_graph)
138 , m_state(state.graph)
139 , m_interpreter(state.graph, m_state)
145 State* state = &m_ftlState;
148 if (verboseCompilationEnabled()) {
150 "jsBody_", ++compileCounter, "_", codeBlock()->inferredName(),
151 "_", codeBlock()->hash());
155 m_graph.ensureDominators();
157 if (verboseCompilationEnabled())
158 dataLog("Function ready, beginning lowering.\n");
160 m_out.initialize(m_heaps);
162 // We use prologue frequency for all of the initialization code.
163 m_out.setFrequency(1);
165 m_prologue = m_out.newBlock();
166 m_handleExceptions = m_out.newBlock();
168 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
169 m_highBlock = m_graph.block(blockIndex);
172 m_out.setFrequency(m_highBlock->executionCount);
173 m_blocks.add(m_highBlock, m_out.newBlock());
176 // Back to prologue frequency for any bocks that get sneakily created in the initialization code.
177 m_out.setFrequency(1);
179 m_out.appendTo(m_prologue, m_handleExceptions);
180 m_out.initializeConstants(m_proc, m_prologue);
181 createPhiVariables();
183 size_t sizeOfCaptured = sizeof(JSValue) * m_graph.m_nextMachineLocal;
184 B3::SlotBaseValue* capturedBase = m_out.lockedStackSlot(sizeOfCaptured);
185 m_captured = m_out.add(capturedBase, m_out.constIntPtr(sizeOfCaptured));
186 state->capturedValue = capturedBase->slot();
188 auto preOrder = m_graph.blocksInPreOrder();
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(CallFrameSlot::codeBlock));
201 // Stack Overflow Check.
202 unsigned exitFrameSize = m_graph.requiredRegisterCountForExit() * sizeof(Register);
203 MacroAssembler::AbsoluteAddress addressOfStackLimit(vm().addressOfSoftStackLimit());
204 PatchpointValue* stackOverflowHandler = m_out.patchpoint(Void);
205 CallSiteIndex callSiteIndex = callSiteIndexForCodeOrigin(m_ftlState, CodeOrigin(0));
206 stackOverflowHandler->appendSomeRegister(m_callFrame);
207 stackOverflowHandler->clobber(RegisterSet::macroScratchRegisters());
208 stackOverflowHandler->numGPScratchRegisters = 1;
209 stackOverflowHandler->setGenerator(
210 [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
211 AllowMacroScratchRegisterUsage allowScratch(jit);
212 GPRReg fp = params[0].gpr();
213 GPRReg scratch = params.gpScratch(0);
215 unsigned ftlFrameSize = params.proc().frameSize();
217 jit.addPtr(MacroAssembler::TrustedImm32(-std::max(exitFrameSize, ftlFrameSize)), fp, scratch);
218 MacroAssembler::Jump stackOverflow = jit.branchPtr(MacroAssembler::Above, addressOfStackLimit, scratch);
220 params.addLatePath([=] (CCallHelpers& jit) {
221 AllowMacroScratchRegisterUsage allowScratch(jit);
223 stackOverflow.link(&jit);
225 MacroAssembler::TrustedImm32(callSiteIndex.bits()),
226 CCallHelpers::tagFor(VirtualRegister(CallFrameSlot::argumentCount)));
227 jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer();
229 jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
230 jit.move(CCallHelpers::TrustedImmPtr(jit.codeBlock()), GPRInfo::argumentGPR1);
231 CCallHelpers::Call throwCall = jit.call();
233 jit.move(CCallHelpers::TrustedImmPtr(jit.vm()), GPRInfo::argumentGPR0);
234 jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
235 CCallHelpers::Call lookupExceptionHandlerCall = jit.call();
236 jit.jumpToExceptionHandler();
239 [=] (LinkBuffer& linkBuffer) {
240 linkBuffer.link(throwCall, FunctionPtr(operationThrowStackOverflowError));
241 linkBuffer.link(lookupExceptionHandlerCall, FunctionPtr(lookupExceptionHandlerFromCallerFrame));
246 LBasicBlock firstDFGBasicBlock = lowBlock(m_graph.block(0));
248 availabilityMap().clear();
249 availabilityMap().m_locals = Operands<Availability>(codeBlock()->numParameters(), 0);
250 for (unsigned i = codeBlock()->numParameters(); i--;) {
251 availabilityMap().m_locals.argument(i) =
252 Availability(FlushedAt(FlushedJSValue, virtualRegisterForArgument(i)));
255 m_origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), true);
256 for (unsigned i = codeBlock()->numParameters(); i--;) {
257 Node* node = m_graph.m_arguments[i];
258 VirtualRegister operand = virtualRegisterForArgument(i);
260 LValue jsValue = m_out.load64(addressFor(operand));
263 DFG_ASSERT(m_graph, node, operand == node->stackAccessData()->machineLocal);
265 // This is a hack, but it's an effective one. It allows us to do CSE on the
266 // primordial load of arguments. This assumes that the GetLocal that got put in
267 // place of the original SetArgument doesn't have any effects before it. This
269 m_loadedArgumentValues.add(node, jsValue);
272 switch (m_graph.m_argumentFormats[i]) {
274 speculate(BadType, jsValueValue(jsValue), node, isNotInt32(jsValue));
277 speculate(BadType, jsValueValue(jsValue), node, isNotBoolean(jsValue));
280 speculate(BadType, jsValueValue(jsValue), node, isNotCell(jsValue));
285 DFG_CRASH(m_graph, node, "Bad flush format for argument");
289 m_out.jump(firstDFGBasicBlock);
291 m_out.appendTo(m_handleExceptions, firstDFGBasicBlock);
292 Box<CCallHelpers::Label> exceptionHandler = state->exceptionHandler;
293 m_out.patchpoint(Void)->setGenerator(
294 [=] (CCallHelpers& jit, const StackmapGenerationParams&) {
295 CCallHelpers::Jump jump = jit.jump();
297 [=] (LinkBuffer& linkBuffer) {
298 linkBuffer.link(jump, linkBuffer.locationOf(*exceptionHandler));
303 for (DFG::BasicBlock* block : preOrder)
306 // Make sure everything is decorated. This does a bunch of deferred decorating. This has
307 // to happen last because our abstract heaps are generated lazily. They have to be
308 // generated lazily because we have an infiniten number of numbered, indexed, and
309 // absolute heaps. We only become aware of the ones we actually mention while lowering.
310 m_heaps.computeRangesAndDecorateInstructions();
312 // We create all Phi's up front, but we may then decide not to compile the basic block
313 // that would have contained one of them. So this creates orphans, which triggers B3
314 // validation failures. Calling this fixes the issue.
316 // Note that you should avoid the temptation to make this call conditional upon
317 // validation being enabled. B3 makes no guarantees of any kind of correctness when
318 // dealing with IR that would have failed validation. For example, it would be valid to
319 // write a B3 phase that so aggressively assumes the lack of orphans that it would crash
320 // if any orphans were around. We might even have such phases already.
321 m_proc.deleteOrphans();
323 // We put the blocks into the B3 procedure in a super weird order. Now we reorder them.
324 m_out.applyBlockOrder();
329 void createPhiVariables()
331 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
332 DFG::BasicBlock* block = m_graph.block(blockIndex);
335 for (unsigned nodeIndex = block->size(); nodeIndex--;) {
336 Node* node = block->at(nodeIndex);
337 if (node->op() != DFG::Phi)
340 switch (node->flags() & NodeResultMask) {
341 case NodeResultDouble:
344 case NodeResultInt32:
347 case NodeResultInt52:
350 case NodeResultBoolean:
357 DFG_CRASH(m_graph, node, "Bad Phi node result type");
360 m_phis.add(node, m_proc.add<Value>(B3::Phi, type, Origin(node)));
365 void compileBlock(DFG::BasicBlock* block)
370 if (verboseCompilationEnabled())
371 dataLog("Compiling block ", *block, "\n");
375 // Make sure that any blocks created while lowering code in the high block have the frequency of
376 // the high block. This is appropriate because B3 doesn't need precise frequencies. It just needs
377 // something roughly approximate for things like register allocation.
378 m_out.setFrequency(m_highBlock->executionCount);
380 LBasicBlock lowBlock = m_blocks.get(m_highBlock);
383 for (BlockIndex nextBlockIndex = m_highBlock->index + 1; nextBlockIndex < m_graph.numBlocks(); ++nextBlockIndex) {
384 m_nextHighBlock = m_graph.block(nextBlockIndex);
388 m_nextLowBlock = m_nextHighBlock ? m_blocks.get(m_nextHighBlock) : 0;
390 // All of this effort to find the next block gives us the ability to keep the
391 // generated IR in roughly program order. This ought not affect the performance
392 // of the generated code (since we expect B3 to reorder things) but it will
393 // make IR dumps easier to read.
394 m_out.appendTo(lowBlock, m_nextLowBlock);
396 if (Options::ftlCrashes())
399 if (!m_highBlock->cfaHasVisited) {
400 if (verboseCompilationEnabled())
401 dataLog("Bailing because CFA didn't reach.\n");
402 crash(m_highBlock, nullptr);
406 m_availabilityCalculator.beginBlock(m_highBlock);
409 m_state.beginBasicBlock(m_highBlock);
411 for (m_nodeIndex = 0; m_nodeIndex < m_highBlock->size(); ++m_nodeIndex) {
412 if (!compileNode(m_nodeIndex))
417 void safelyInvalidateAfterTermination()
419 if (verboseCompilationEnabled())
420 dataLog("Bailing.\n");
423 // Invalidate dominated blocks. Under normal circumstances we would expect
424 // them to be invalidated already. But you can have the CFA become more
425 // precise over time because the structures of objects change on the main
426 // thread. Failing to do this would result in weird crashes due to a value
427 // being used but not defined. Race conditions FTW!
428 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
429 DFG::BasicBlock* target = m_graph.block(blockIndex);
432 if (m_graph.m_dominators->dominates(m_highBlock, target)) {
433 if (verboseCompilationEnabled())
434 dataLog("Block ", *target, " will bail also.\n");
435 target->cfaHasVisited = false;
440 bool compileNode(unsigned nodeIndex)
442 if (!m_state.isValid()) {
443 safelyInvalidateAfterTermination();
447 m_node = m_highBlock->at(nodeIndex);
448 m_origin = m_node->origin;
449 m_out.setOrigin(m_node);
451 if (verboseCompilationEnabled())
452 dataLog("Lowering ", m_node, "\n");
454 m_availableRecoveries.resize(0);
456 m_interpreter.startExecuting();
457 m_interpreter.executeKnownEdgeTypes(m_node);
459 switch (m_node->op()) {
469 compileDoubleConstant();
472 compileInt52Constant();
475 compileLazyJSConstant();
481 compileDoubleAsInt32();
490 compileValueToInt32();
492 case BooleanToNumber:
493 compileBooleanToNumber();
495 case ExtractOSREntryLocal:
496 compileExtractOSREntryLocal();
507 case CallObjectConstructor:
508 compileCallObjectConstructor();
521 compileArithAddOrSub();
537 compileArithMinOrMax();
555 compileArithRandom();
576 compileArithFRound();
579 compileArithNegate();
600 compileUInt32ToNumber();
603 compileCheckStructure();
609 compileCheckNotEmpty();
612 compileCheckBadCell();
614 case CheckStringIdent:
615 compileCheckStringIdent();
618 compileGetExecutable();
620 case ArrayifyToStructure:
621 compileArrayifyToStructure();
624 compilePutStructure();
627 compileGetById(AccessType::GetPure);
631 compileGetById(AccessType::Get);
633 case GetByIdWithThis:
634 compileGetByIdWithThis();
640 compileHasOwnProperty();
647 case PutByIdWithThis:
648 compilePutByIdWithThis();
652 compilePutAccessorById();
654 case PutGetterSetterById:
655 compilePutGetterSetterById();
659 compilePutAccessorByVal();
662 compileGetButterfly();
664 case ConstantStoragePointer:
665 compileConstantStoragePointer();
667 case GetIndexedPropertyStorage:
668 compileGetIndexedPropertyStorage();
674 compileGetArrayLength();
677 compileCheckInBounds();
682 case GetMyArgumentByVal:
683 case GetMyArgumentByValOutOfBounds:
684 compileGetMyArgumentByVal();
686 case GetByValWithThis:
687 compileGetByValWithThis();
694 case PutByValWithThis:
695 compilePutByValWithThis();
697 case DefineDataProperty:
698 compileDefineDataProperty();
700 case DefineAccessorProperty:
701 compileDefineAccessorProperty();
709 case CreateActivation:
710 compileCreateActivation();
713 case NewGeneratorFunction:
714 case NewAsyncFunction:
715 compileNewFunction();
717 case CreateDirectArguments:
718 compileCreateDirectArguments();
720 case CreateScopedArguments:
721 compileCreateScopedArguments();
723 case CreateClonedArguments:
724 compileCreateClonedArguments();
732 case NewArrayWithSpread:
733 compileNewArrayWithSpread();
739 compileNewArrayBuffer();
741 case NewArrayWithSize:
742 compileNewArrayWithSize();
745 compileNewTypedArray();
747 case GetTypedArrayByteOffset:
748 compileGetTypedArrayByteOffset();
750 case AllocatePropertyStorage:
751 compileAllocatePropertyStorage();
753 case ReallocatePropertyStorage:
754 compileReallocatePropertyStorage();
756 case NukeStructureAndSetButterfly:
757 compileNukeStructureAndSetButterfly();
763 case CallStringConstructor:
764 compileToStringOrCallStringConstructor();
767 compileToPrimitive();
773 compileStringCharAt();
775 case StringCharCodeAt:
776 compileStringCharCodeAt();
778 case StringFromCharCode:
779 compileStringFromCharCode();
782 case GetGetterSetterByOffset:
783 compileGetByOffset();
791 case MultiGetByOffset:
792 compileMultiGetByOffset();
795 compilePutByOffset();
797 case MultiPutByOffset:
798 compileMultiPutByOffset();
801 case GetGlobalLexicalVariable:
802 compileGetGlobalVariable();
804 case PutGlobalVariable:
805 compilePutGlobalVariable();
808 compileNotifyWrite();
813 case GetArgumentCountIncludingThis:
814 compileGetArgumentCountIncludingThis();
822 case GetGlobalObject:
823 compileGetGlobalObject();
826 compileGetClosureVar();
829 compilePutClosureVar();
831 case GetFromArguments:
832 compileGetFromArguments();
835 compilePutToArguments();
838 compileGetArgument();
843 case CompareStrictEq:
844 compileCompareStrictEq();
847 compileCompareLess();
850 compileCompareLessEq();
853 compileCompareGreater();
855 case CompareGreaterEq:
856 compileCompareGreaterEq();
859 compileCompareEqPtr();
865 case TailCallInlinedCaller:
867 compileCallOrConstruct();
870 case DirectTailCallInlinedCaller:
871 case DirectConstruct:
873 compileDirectCallOrConstruct();
879 case CallForwardVarargs:
880 case TailCallVarargs:
881 case TailCallVarargsInlinedCaller:
882 case TailCallForwardVarargs:
883 case TailCallForwardVarargsInlinedCaller:
884 case ConstructVarargs:
885 case ConstructForwardVarargs:
886 compileCallOrConstructVarargs();
892 compileLoadVarargs();
895 compileForwardVarargs();
910 compileForceOSRExit();
913 case ThrowStaticError:
916 case InvalidationPoint:
917 compileInvalidationPoint();
923 compileIsUndefined();
932 compileIsCellWithType();
938 compileGetMapBucket();
940 case LoadFromJSMapBucket:
941 compileLoadFromJSMapBucket();
943 case IsNonEmptyMapBucket:
944 compileIsNonEmptyMapBucket();
950 compileIsObjectOrNull();
955 case IsTypedArrayView:
956 compileIsTypedArrayView();
961 case CheckTypeInfoFlags:
962 compileCheckTypeInfoFlags();
964 case OverridesHasInstance:
965 compileOverridesHasInstance();
970 case InstanceOfCustom:
971 compileInstanceOfCustom();
974 compileCountExecution();
977 case FencedStoreBarrier:
978 compileStoreBarrier();
980 case HasIndexedProperty:
981 compileHasIndexedProperty();
983 case HasGenericProperty:
984 compileHasGenericProperty();
986 case HasStructureProperty:
987 compileHasStructureProperty();
990 compileGetDirectPname();
992 case GetEnumerableLength:
993 compileGetEnumerableLength();
995 case GetPropertyEnumerator:
996 compileGetPropertyEnumerator();
998 case GetEnumeratorStructurePname:
999 compileGetEnumeratorStructurePname();
1001 case GetEnumeratorGenericPname:
1002 compileGetEnumeratorGenericPname();
1005 compileToIndexString();
1007 case CheckStructureImmediate:
1008 compileCheckStructureImmediate();
1010 case MaterializeNewObject:
1011 compileMaterializeNewObject();
1013 case MaterializeCreateActivation:
1014 compileMaterializeCreateActivation();
1016 case CheckWatchdogTimer:
1017 compileCheckWatchdogTimer();
1020 compileCreateRest();
1023 compileGetRestLength();
1026 compileRegExpExec();
1029 compileRegExpTest();
1034 case SetFunctionName:
1035 compileSetFunctionName();
1038 case StringReplaceRegExp:
1039 compileStringReplace();
1041 case GetRegExpObjectLastIndex:
1042 compileGetRegExpObjectLastIndex();
1044 case SetRegExpObjectLastIndex:
1045 compileSetRegExpObjectLastIndex();
1047 case LogShadowChickenPrologue:
1048 compileLogShadowChickenPrologue();
1050 case LogShadowChickenTail:
1051 compileLogShadowChickenTail();
1053 case RecordRegExpCachedResult:
1054 compileRecordRegExpCachedResult();
1057 compileResolveScope();
1060 compileGetDynamicVar();
1063 compilePutDynamicVar();
1066 compileUnreachable();
1069 compileToLowerCase();
1078 compileCallDOMGetter();
1086 case PhantomNewObject:
1087 case PhantomNewFunction:
1088 case PhantomNewGeneratorFunction:
1089 case PhantomNewAsyncFunction:
1090 case PhantomCreateActivation:
1091 case PhantomDirectArguments:
1092 case PhantomCreateRest:
1094 case PhantomNewArrayWithSpread:
1095 case PhantomClonedArguments:
1101 DFG_CRASH(m_graph, m_node, "Unrecognized node in FTL backend");
1105 if (m_node->isTerminal())
1108 if (!m_state.isValid()) {
1109 safelyInvalidateAfterTermination();
1113 m_availabilityCalculator.executeNode(m_node);
1114 m_interpreter.executeEffects(nodeIndex);
1119 void compileUpsilon()
1121 LValue upsilonValue = nullptr;
1122 switch (m_node->child1().useKind()) {
1124 upsilonValue = lowDouble(m_node->child1());
1128 upsilonValue = lowInt32(m_node->child1());
1131 upsilonValue = lowInt52(m_node->child1());
1134 case KnownBooleanUse:
1135 upsilonValue = lowBoolean(m_node->child1());
1139 upsilonValue = lowCell(m_node->child1());
1142 upsilonValue = lowJSValue(m_node->child1());
1145 DFG_CRASH(m_graph, m_node, "Bad use kind");
1148 ValueFromBlock upsilon = m_out.anchor(upsilonValue);
1149 LValue phiNode = m_phis.get(m_node->phi());
1150 m_out.addIncomingToPhi(phiNode, upsilon);
1155 LValue phi = m_phis.get(m_node);
1156 m_out.m_block->append(phi);
1158 switch (m_node->flags() & NodeResultMask) {
1159 case NodeResultDouble:
1162 case NodeResultInt32:
1165 case NodeResultInt52:
1168 case NodeResultBoolean:
1175 DFG_CRASH(m_graph, m_node, "Bad use kind");
1180 void compileDoubleConstant()
1182 setDouble(m_out.constDouble(m_node->asNumber()));
1185 void compileInt52Constant()
1187 int64_t value = m_node->asAnyInt();
1189 setInt52(m_out.constInt64(value << JSValue::int52ShiftAmount));
1190 setStrictInt52(m_out.constInt64(value));
1193 void compileLazyJSConstant()
1195 PatchpointValue* patchpoint = m_out.patchpoint(Int64);
1196 LazyJSValue value = m_node->lazyJSValue();
1197 patchpoint->setGenerator(
1198 [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
1199 value.emit(jit, JSValueRegs(params[0].gpr()));
1201 patchpoint->effects = Effects::none();
1202 setJSValue(patchpoint);
1205 void compileDoubleRep()
1207 switch (m_node->child1().useKind()) {
1208 case RealNumberUse: {
1209 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
1211 LValue doubleValue = unboxDouble(value);
1213 LBasicBlock intCase = m_out.newBlock();
1214 LBasicBlock continuation = m_out.newBlock();
1216 ValueFromBlock fastResult = m_out.anchor(doubleValue);
1218 m_out.doubleEqual(doubleValue, doubleValue),
1219 usually(continuation), rarely(intCase));
1221 LBasicBlock lastNext = m_out.appendTo(intCase, continuation);
1224 jsValueValue(value), m_node->child1(), SpecBytecodeRealNumber,
1225 isNotInt32(value, provenType(m_node->child1()) & ~SpecDoubleReal));
1226 ValueFromBlock slowResult = m_out.anchor(m_out.intToDouble(unboxInt32(value)));
1227 m_out.jump(continuation);
1229 m_out.appendTo(continuation, lastNext);
1231 setDouble(m_out.phi(Double, fastResult, slowResult));
1237 bool shouldConvertNonNumber = m_node->child1().useKind() == NotCellUse;
1239 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
1241 LBasicBlock intCase = m_out.newBlock();
1242 LBasicBlock doubleTesting = m_out.newBlock();
1243 LBasicBlock doubleCase = m_out.newBlock();
1244 LBasicBlock nonDoubleCase = m_out.newBlock();
1245 LBasicBlock continuation = m_out.newBlock();
1248 isNotInt32(value, provenType(m_node->child1())),
1249 unsure(doubleTesting), unsure(intCase));
1251 LBasicBlock lastNext = m_out.appendTo(intCase, doubleTesting);
1253 ValueFromBlock intToDouble = m_out.anchor(
1254 m_out.intToDouble(unboxInt32(value)));
1255 m_out.jump(continuation);
1257 m_out.appendTo(doubleTesting, doubleCase);
1258 LValue valueIsNumber = isNumber(value, provenType(m_node->child1()));
1259 m_out.branch(valueIsNumber, usually(doubleCase), rarely(nonDoubleCase));
1261 m_out.appendTo(doubleCase, nonDoubleCase);
1262 ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(value));
1263 m_out.jump(continuation);
1265 if (shouldConvertNonNumber) {
1266 LBasicBlock undefinedCase = m_out.newBlock();
1267 LBasicBlock testNullCase = m_out.newBlock();
1268 LBasicBlock nullCase = m_out.newBlock();
1269 LBasicBlock testBooleanTrueCase = m_out.newBlock();
1270 LBasicBlock convertBooleanTrueCase = m_out.newBlock();
1271 LBasicBlock convertBooleanFalseCase = m_out.newBlock();
1273 m_out.appendTo(nonDoubleCase, undefinedCase);
1274 LValue valueIsUndefined = m_out.equal(value, m_out.constInt64(ValueUndefined));
1275 m_out.branch(valueIsUndefined, unsure(undefinedCase), unsure(testNullCase));
1277 m_out.appendTo(undefinedCase, testNullCase);
1278 ValueFromBlock convertedUndefined = m_out.anchor(m_out.constDouble(PNaN));
1279 m_out.jump(continuation);
1281 m_out.appendTo(testNullCase, nullCase);
1282 LValue valueIsNull = m_out.equal(value, m_out.constInt64(ValueNull));
1283 m_out.branch(valueIsNull, unsure(nullCase), unsure(testBooleanTrueCase));
1285 m_out.appendTo(nullCase, testBooleanTrueCase);
1286 ValueFromBlock convertedNull = m_out.anchor(m_out.constDouble(0));
1287 m_out.jump(continuation);
1289 m_out.appendTo(testBooleanTrueCase, convertBooleanTrueCase);
1290 LValue valueIsBooleanTrue = m_out.equal(value, m_out.constInt64(ValueTrue));
1291 m_out.branch(valueIsBooleanTrue, unsure(convertBooleanTrueCase), unsure(convertBooleanFalseCase));
1293 m_out.appendTo(convertBooleanTrueCase, convertBooleanFalseCase);
1294 ValueFromBlock convertedTrue = m_out.anchor(m_out.constDouble(1));
1295 m_out.jump(continuation);
1297 m_out.appendTo(convertBooleanFalseCase, continuation);
1299 LValue valueIsNotBooleanFalse = m_out.notEqual(value, m_out.constInt64(ValueFalse));
1300 FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), ~SpecCell, valueIsNotBooleanFalse);
1301 ValueFromBlock convertedFalse = m_out.anchor(m_out.constDouble(0));
1302 m_out.jump(continuation);
1304 m_out.appendTo(continuation, lastNext);
1305 setDouble(m_out.phi(Double, intToDouble, unboxedDouble, convertedUndefined, convertedNull, convertedTrue, convertedFalse));
1308 m_out.appendTo(nonDoubleCase, continuation);
1309 FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), SpecBytecodeNumber, m_out.booleanTrue);
1310 m_out.unreachable();
1312 m_out.appendTo(continuation, lastNext);
1314 setDouble(m_out.phi(Double, intToDouble, unboxedDouble));
1319 setDouble(strictInt52ToDouble(lowStrictInt52(m_node->child1())));
1324 DFG_CRASH(m_graph, m_node, "Bad use kind");
1328 void compileDoubleAsInt32()
1330 LValue integerValue = convertDoubleToInt32(lowDouble(m_node->child1()), shouldCheckNegativeZero(m_node->arithMode()));
1331 setInt32(integerValue);
1334 void compileValueRep()
1336 switch (m_node->child1().useKind()) {
1337 case DoubleRepUse: {
1338 LValue value = lowDouble(m_node->child1());
1340 if (m_interpreter.needsTypeCheck(m_node->child1(), ~SpecDoubleImpureNaN)) {
1341 value = m_out.select(
1342 m_out.doubleEqual(value, value), value, m_out.constDouble(PNaN));
1345 setJSValue(boxDouble(value));
1350 setJSValue(strictInt52ToJSValue(lowStrictInt52(m_node->child1())));
1355 DFG_CRASH(m_graph, m_node, "Bad use kind");
1359 void compileInt52Rep()
1361 switch (m_node->child1().useKind()) {
1363 setStrictInt52(m_out.signExt32To64(lowInt32(m_node->child1())));
1368 jsValueToStrictInt52(
1369 m_node->child1(), lowJSValue(m_node->child1(), ManualOperandSpeculation)));
1372 case DoubleRepAnyIntUse:
1374 doubleToStrictInt52(
1375 m_node->child1(), lowDouble(m_node->child1())));
1379 RELEASE_ASSERT_NOT_REACHED();
1383 void compileValueToInt32()
1385 switch (m_node->child1().useKind()) {
1387 setInt32(m_out.castToInt32(lowStrictInt52(m_node->child1())));
1391 setInt32(doubleToInt32(lowDouble(m_node->child1())));
1396 LoweredNodeValue value = m_int32Values.get(m_node->child1().node());
1397 if (isValid(value)) {
1398 setInt32(value.value());
1402 value = m_jsValueValues.get(m_node->child1().node());
1403 if (isValid(value)) {
1404 setInt32(numberOrNotCellToInt32(m_node->child1(), value.value()));
1408 // We'll basically just get here for constants. But it's good to have this
1409 // catch-all since we often add new representations into the mix.
1411 numberOrNotCellToInt32(
1413 lowJSValue(m_node->child1(), ManualOperandSpeculation)));
1418 DFG_CRASH(m_graph, m_node, "Bad use kind");
1423 void compileBooleanToNumber()
1425 switch (m_node->child1().useKind()) {
1427 setInt32(m_out.zeroExt(lowBoolean(m_node->child1()), Int32));
1432 LValue value = lowJSValue(m_node->child1());
1434 if (!m_interpreter.needsTypeCheck(m_node->child1(), SpecBoolInt32 | SpecBoolean)) {
1435 setInt32(m_out.bitAnd(m_out.castToInt32(value), m_out.int32One));
1439 LBasicBlock booleanCase = m_out.newBlock();
1440 LBasicBlock continuation = m_out.newBlock();
1442 ValueFromBlock notBooleanResult = m_out.anchor(value);
1444 isBoolean(value, provenType(m_node->child1())),
1445 unsure(booleanCase), unsure(continuation));
1447 LBasicBlock lastNext = m_out.appendTo(booleanCase, continuation);
1448 ValueFromBlock booleanResult = m_out.anchor(m_out.bitOr(
1449 m_out.zeroExt(unboxBoolean(value), Int64), m_tagTypeNumber));
1450 m_out.jump(continuation);
1452 m_out.appendTo(continuation, lastNext);
1453 setJSValue(m_out.phi(Int64, booleanResult, notBooleanResult));
1458 RELEASE_ASSERT_NOT_REACHED();
1463 void compileExtractOSREntryLocal()
1465 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(
1466 m_ftlState.jitCode->ftlForOSREntry()->entryBuffer()->dataBuffer());
1467 setJSValue(m_out.load64(m_out.absolute(buffer + m_node->unlinkedLocal().toLocal())));
1470 void compileGetStack()
1472 // GetLocals arise only for captured variables and arguments. For arguments, we might have
1473 // already loaded it.
1474 if (LValue value = m_loadedArgumentValues.get(m_node)) {
1479 StackAccessData* data = m_node->stackAccessData();
1480 AbstractValue& value = m_state.variables().operand(data->local);
1482 DFG_ASSERT(m_graph, m_node, isConcrete(data->format));
1483 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.
1485 if (isInt32Speculation(value.m_type))
1486 setInt32(m_out.load32(payloadFor(data->machineLocal)));
1488 setJSValue(m_out.load64(addressFor(data->machineLocal)));
1491 void compilePutStack()
1493 StackAccessData* data = m_node->stackAccessData();
1494 switch (data->format) {
1495 case FlushedJSValue: {
1496 LValue value = lowJSValue(m_node->child1());
1497 m_out.store64(value, addressFor(data->machineLocal));
1501 case FlushedDouble: {
1502 LValue value = lowDouble(m_node->child1());
1503 m_out.storeDouble(value, addressFor(data->machineLocal));
1507 case FlushedInt32: {
1508 LValue value = lowInt32(m_node->child1());
1509 m_out.store32(value, payloadFor(data->machineLocal));
1513 case FlushedInt52: {
1514 LValue value = lowInt52(m_node->child1());
1515 m_out.store64(value, addressFor(data->machineLocal));
1520 LValue value = lowCell(m_node->child1());
1521 m_out.store64(value, addressFor(data->machineLocal));
1525 case FlushedBoolean: {
1526 speculateBoolean(m_node->child1());
1528 lowJSValue(m_node->child1(), ManualOperandSpeculation),
1529 addressFor(data->machineLocal));
1534 DFG_CRASH(m_graph, m_node, "Bad flush format");
1541 DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, speculate);
1544 void compileCallObjectConstructor()
1546 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
1547 LValue value = lowJSValue(m_node->child1());
1549 LBasicBlock isCellCase = m_out.newBlock();
1550 LBasicBlock slowCase = m_out.newBlock();
1551 LBasicBlock continuation = m_out.newBlock();
1553 m_out.branch(isCell(value, provenType(m_node->child1())), usually(isCellCase), rarely(slowCase));
1555 LBasicBlock lastNext = m_out.appendTo(isCellCase, slowCase);
1556 ValueFromBlock fastResult = m_out.anchor(value);
1557 m_out.branch(isObject(value), usually(continuation), rarely(slowCase));
1559 m_out.appendTo(slowCase, continuation);
1560 ValueFromBlock slowResult = m_out.anchor(vmCall(Int64, m_out.operation(operationObjectConstructor), m_callFrame, m_out.constIntPtr(globalObject), value));
1561 m_out.jump(continuation);
1563 m_out.appendTo(continuation, lastNext);
1564 setJSValue(m_out.phi(Int64, fastResult, slowResult));
1567 void compileToThis()
1569 LValue value = lowJSValue(m_node->child1());
1571 LBasicBlock isCellCase = m_out.newBlock();
1572 LBasicBlock slowCase = m_out.newBlock();
1573 LBasicBlock continuation = m_out.newBlock();
1576 isCell(value, provenType(m_node->child1())), usually(isCellCase), rarely(slowCase));
1578 LBasicBlock lastNext = m_out.appendTo(isCellCase, slowCase);
1579 ValueFromBlock fastResult = m_out.anchor(value);
1582 m_out.load8ZeroExt32(value, m_heaps.JSCell_typeInfoFlags),
1583 m_out.constInt32(OverridesToThis)),
1584 usually(continuation), rarely(slowCase));
1586 m_out.appendTo(slowCase, continuation);
1587 J_JITOperation_EJ function;
1588 if (m_graph.isStrictModeFor(m_node->origin.semantic))
1589 function = operationToThisStrict;
1591 function = operationToThis;
1592 ValueFromBlock slowResult = m_out.anchor(
1593 vmCall(Int64, m_out.operation(function), m_callFrame, value));
1594 m_out.jump(continuation);
1596 m_out.appendTo(continuation, lastNext);
1597 setJSValue(m_out.phi(Int64, fastResult, slowResult));
1600 void compileValueAdd()
1602 ArithProfile* arithProfile = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic)->arithProfileForBytecodeOffset(m_node->origin.semantic.bytecodeIndex);
1603 JITAddIC* addIC = codeBlock()->addJITAddIC(arithProfile);
1604 auto repatchingFunction = operationValueAddOptimize;
1605 auto nonRepatchingFunction = operationValueAdd;
1606 compileMathIC(addIC, repatchingFunction, nonRepatchingFunction);
1609 template <typename Generator>
1610 void compileMathIC(JITUnaryMathIC<Generator>* mathIC, FunctionPtr repatchingFunction, FunctionPtr nonRepatchingFunction)
1612 Node* node = m_node;
1614 LValue operand = lowJSValue(node->child1());
1616 PatchpointValue* patchpoint = m_out.patchpoint(Int64);
1617 patchpoint->appendSomeRegister(operand);
1618 patchpoint->append(m_tagMask, ValueRep::lateReg(GPRInfo::tagMaskRegister));
1619 patchpoint->append(m_tagTypeNumber, ValueRep::lateReg(GPRInfo::tagTypeNumberRegister));
1620 RefPtr<PatchpointExceptionHandle> exceptionHandle = preparePatchpointForExceptions(patchpoint);
1621 patchpoint->numGPScratchRegisters = 1;
1622 patchpoint->clobber(RegisterSet::macroScratchRegisters());
1623 State* state = &m_ftlState;
1624 patchpoint->setGenerator(
1625 [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
1626 AllowMacroScratchRegisterUsage allowScratch(jit);
1628 Box<CCallHelpers::JumpList> exceptions =
1629 exceptionHandle->scheduleExitCreation(params)->jumps(jit);
1631 #if ENABLE(MATH_IC_STATS)
1632 auto inlineStart = jit.label();
1635 Box<MathICGenerationState> mathICGenerationState = Box<MathICGenerationState>::create();
1636 mathIC->m_generator = Generator(JSValueRegs(params[0].gpr()), JSValueRegs(params[1].gpr()), params.gpScratch(0));
1638 bool shouldEmitProfiling = false;
1639 bool generatedInline = mathIC->generateInline(jit, *mathICGenerationState, shouldEmitProfiling);
1641 if (generatedInline) {
1642 ASSERT(!mathICGenerationState->slowPathJumps.empty());
1643 auto done = jit.label();
1644 params.addLatePath([=] (CCallHelpers& jit) {
1645 AllowMacroScratchRegisterUsage allowScratch(jit);
1646 mathICGenerationState->slowPathJumps.link(&jit);
1647 mathICGenerationState->slowPathStart = jit.label();
1648 #if ENABLE(MATH_IC_STATS)
1649 auto slowPathStart = jit.label();
1652 if (mathICGenerationState->shouldSlowPathRepatch) {
1653 SlowPathCall call = callOperation(*state, params.unavailableRegisters(), jit, node->origin.semantic, exceptions.get(),
1654 repatchingFunction, params[0].gpr(), params[1].gpr(), CCallHelpers::TrustedImmPtr(mathIC));
1655 mathICGenerationState->slowPathCall = call.call();
1657 SlowPathCall call = callOperation(*state, params.unavailableRegisters(), jit, node->origin.semantic,
1658 exceptions.get(), nonRepatchingFunction, params[0].gpr(), params[1].gpr());
1659 mathICGenerationState->slowPathCall = call.call();
1661 jit.jump().linkTo(done, &jit);
1663 jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
1664 mathIC->finalizeInlineCode(*mathICGenerationState, linkBuffer);
1667 #if ENABLE(MATH_IC_STATS)
1668 auto slowPathEnd = jit.label();
1669 jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
1670 size_t size = static_cast<char*>(linkBuffer.locationOf(slowPathEnd).executableAddress()) - static_cast<char*>(linkBuffer.locationOf(slowPathStart).executableAddress());
1671 mathIC->m_generatedCodeSize += size;
1677 *state, params.unavailableRegisters(), jit, node->origin.semantic, exceptions.get(),
1678 nonRepatchingFunction, params[0].gpr(), params[1].gpr());
1681 #if ENABLE(MATH_IC_STATS)
1682 auto inlineEnd = jit.label();
1683 jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
1684 size_t size = static_cast<char*>(linkBuffer.locationOf(inlineEnd).executableAddress()) - static_cast<char*>(linkBuffer.locationOf(inlineStart).executableAddress());
1685 mathIC->m_generatedCodeSize += size;
1690 setJSValue(patchpoint);
1693 template <typename Generator>
1694 void compileMathIC(JITBinaryMathIC<Generator>* mathIC, FunctionPtr repatchingFunction, FunctionPtr nonRepatchingFunction)
1696 Node* node = m_node;
1698 LValue left = lowJSValue(node->child1());
1699 LValue right = lowJSValue(node->child2());
1701 SnippetOperand leftOperand(m_state.forNode(node->child1()).resultType());
1702 SnippetOperand rightOperand(m_state.forNode(node->child2()).resultType());
1704 PatchpointValue* patchpoint = m_out.patchpoint(Int64);
1705 patchpoint->appendSomeRegister(left);
1706 patchpoint->appendSomeRegister(right);
1707 patchpoint->append(m_tagMask, ValueRep::lateReg(GPRInfo::tagMaskRegister));
1708 patchpoint->append(m_tagTypeNumber, ValueRep::lateReg(GPRInfo::tagTypeNumberRegister));
1709 RefPtr<PatchpointExceptionHandle> exceptionHandle =
1710 preparePatchpointForExceptions(patchpoint);
1711 patchpoint->numGPScratchRegisters = 1;
1712 patchpoint->numFPScratchRegisters = 2;
1713 patchpoint->clobber(RegisterSet::macroScratchRegisters());
1714 State* state = &m_ftlState;
1715 patchpoint->setGenerator(
1716 [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
1717 AllowMacroScratchRegisterUsage allowScratch(jit);
1719 Box<CCallHelpers::JumpList> exceptions =
1720 exceptionHandle->scheduleExitCreation(params)->jumps(jit);
1722 #if ENABLE(MATH_IC_STATS)
1723 auto inlineStart = jit.label();
1726 Box<MathICGenerationState> mathICGenerationState = Box<MathICGenerationState>::create();
1727 mathIC->m_generator = Generator(leftOperand, rightOperand, JSValueRegs(params[0].gpr()),
1728 JSValueRegs(params[1].gpr()), JSValueRegs(params[2].gpr()), params.fpScratch(0),
1729 params.fpScratch(1), params.gpScratch(0), InvalidFPRReg);
1731 bool shouldEmitProfiling = false;
1732 bool generatedInline = mathIC->generateInline(jit, *mathICGenerationState, shouldEmitProfiling);
1734 if (generatedInline) {
1735 ASSERT(!mathICGenerationState->slowPathJumps.empty());
1736 auto done = jit.label();
1737 params.addLatePath([=] (CCallHelpers& jit) {
1738 AllowMacroScratchRegisterUsage allowScratch(jit);
1739 mathICGenerationState->slowPathJumps.link(&jit);
1740 mathICGenerationState->slowPathStart = jit.label();
1741 #if ENABLE(MATH_IC_STATS)
1742 auto slowPathStart = jit.label();
1745 if (mathICGenerationState->shouldSlowPathRepatch) {
1746 SlowPathCall call = callOperation(*state, params.unavailableRegisters(), jit, node->origin.semantic, exceptions.get(),
1747 repatchingFunction, params[0].gpr(), params[1].gpr(), params[2].gpr(), CCallHelpers::TrustedImmPtr(mathIC));
1748 mathICGenerationState->slowPathCall = call.call();
1750 SlowPathCall call = callOperation(*state, params.unavailableRegisters(), jit, node->origin.semantic,
1751 exceptions.get(), nonRepatchingFunction, params[0].gpr(), params[1].gpr(), params[2].gpr());
1752 mathICGenerationState->slowPathCall = call.call();
1754 jit.jump().linkTo(done, &jit);
1756 jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
1757 mathIC->finalizeInlineCode(*mathICGenerationState, linkBuffer);
1760 #if ENABLE(MATH_IC_STATS)
1761 auto slowPathEnd = jit.label();
1762 jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
1763 size_t size = static_cast<char*>(linkBuffer.locationOf(slowPathEnd).executableAddress()) - static_cast<char*>(linkBuffer.locationOf(slowPathStart).executableAddress());
1764 mathIC->m_generatedCodeSize += size;
1770 *state, params.unavailableRegisters(), jit, node->origin.semantic, exceptions.get(),
1771 nonRepatchingFunction, params[0].gpr(), params[1].gpr(), params[2].gpr());
1774 #if ENABLE(MATH_IC_STATS)
1775 auto inlineEnd = jit.label();
1776 jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
1777 size_t size = static_cast<char*>(linkBuffer.locationOf(inlineEnd).executableAddress()) - static_cast<char*>(linkBuffer.locationOf(inlineStart).executableAddress());
1778 mathIC->m_generatedCodeSize += size;
1783 setJSValue(patchpoint);
1786 void compileStrCat()
1789 if (m_node->child3()) {
1791 Int64, m_out.operation(operationStrCat3), m_callFrame,
1792 lowJSValue(m_node->child1(), ManualOperandSpeculation),
1793 lowJSValue(m_node->child2(), ManualOperandSpeculation),
1794 lowJSValue(m_node->child3(), ManualOperandSpeculation));
1797 Int64, m_out.operation(operationStrCat2), m_callFrame,
1798 lowJSValue(m_node->child1(), ManualOperandSpeculation),
1799 lowJSValue(m_node->child2(), ManualOperandSpeculation));
1804 void compileArithAddOrSub()
1806 bool isSub = m_node->op() == ArithSub;
1807 switch (m_node->binaryUseKind()) {
1809 LValue left = lowInt32(m_node->child1());
1810 LValue right = lowInt32(m_node->child2());
1812 if (!shouldCheckOverflow(m_node->arithMode())) {
1813 setInt32(isSub ? m_out.sub(left, right) : m_out.add(left, right));
1817 CheckValue* result =
1818 isSub ? m_out.speculateSub(left, right) : m_out.speculateAdd(left, right);
1819 blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
1825 if (!abstractValue(m_node->child1()).couldBeType(SpecInt52Only)
1826 && !abstractValue(m_node->child2()).couldBeType(SpecInt52Only)) {
1828 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1829 LValue right = lowInt52(m_node->child2(), kind);
1830 setInt52(isSub ? m_out.sub(left, right) : m_out.add(left, right), kind);
1834 LValue left = lowInt52(m_node->child1());
1835 LValue right = lowInt52(m_node->child2());
1836 CheckValue* result =
1837 isSub ? m_out.speculateSub(left, right) : m_out.speculateAdd(left, right);
1838 blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
1843 case DoubleRepUse: {
1844 LValue C1 = lowDouble(m_node->child1());
1845 LValue C2 = lowDouble(m_node->child2());
1847 setDouble(isSub ? m_out.doubleSub(C1, C2) : m_out.doubleAdd(C1, C2));
1853 DFG_CRASH(m_graph, m_node, "Bad use kind");
1857 ArithProfile* arithProfile = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic)->arithProfileForBytecodeOffset(m_node->origin.semantic.bytecodeIndex);
1858 JITSubIC* subIC = codeBlock()->addJITSubIC(arithProfile);
1859 auto repatchingFunction = operationValueSubOptimize;
1860 auto nonRepatchingFunction = operationValueSub;
1861 compileMathIC(subIC, repatchingFunction, nonRepatchingFunction);
1866 DFG_CRASH(m_graph, m_node, "Bad use kind");
1871 void compileArithClz32()
1873 if (m_node->child1().useKind() == Int32Use || m_node->child1().useKind() == KnownInt32Use) {
1874 LValue operand = lowInt32(m_node->child1());
1875 setInt32(m_out.ctlz32(operand));
1878 DFG_ASSERT(m_graph, m_node, m_node->child1().useKind() == UntypedUse);
1879 LValue argument = lowJSValue(m_node->child1());
1880 LValue result = vmCall(Int32, m_out.operation(operationArithClz32), m_callFrame, argument);
1884 void compileArithMul()
1886 switch (m_node->binaryUseKind()) {
1888 LValue left = lowInt32(m_node->child1());
1889 LValue right = lowInt32(m_node->child2());
1893 if (!shouldCheckOverflow(m_node->arithMode()))
1894 result = m_out.mul(left, right);
1896 CheckValue* speculation = m_out.speculateMul(left, right);
1897 blessSpeculation(speculation, Overflow, noValue(), nullptr, m_origin);
1898 result = speculation;
1901 if (shouldCheckNegativeZero(m_node->arithMode())) {
1902 LBasicBlock slowCase = m_out.newBlock();
1903 LBasicBlock continuation = m_out.newBlock();
1906 m_out.notZero32(result), usually(continuation), rarely(slowCase));
1908 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
1909 speculate(NegativeZero, noValue(), nullptr, m_out.lessThan(left, m_out.int32Zero));
1910 speculate(NegativeZero, noValue(), nullptr, m_out.lessThan(right, m_out.int32Zero));
1911 m_out.jump(continuation);
1912 m_out.appendTo(continuation, lastNext);
1921 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1922 LValue right = lowInt52(m_node->child2(), opposite(kind));
1924 CheckValue* result = m_out.speculateMul(left, right);
1925 blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
1927 if (shouldCheckNegativeZero(m_node->arithMode())) {
1928 LBasicBlock slowCase = m_out.newBlock();
1929 LBasicBlock continuation = m_out.newBlock();
1932 m_out.notZero64(result), usually(continuation), rarely(slowCase));
1934 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
1935 speculate(NegativeZero, noValue(), nullptr, m_out.lessThan(left, m_out.int64Zero));
1936 speculate(NegativeZero, noValue(), nullptr, m_out.lessThan(right, m_out.int64Zero));
1937 m_out.jump(continuation);
1938 m_out.appendTo(continuation, lastNext);
1945 case DoubleRepUse: {
1947 m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1952 ArithProfile* arithProfile = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic)->arithProfileForBytecodeOffset(m_node->origin.semantic.bytecodeIndex);
1953 JITMulIC* mulIC = codeBlock()->addJITMulIC(arithProfile);
1954 auto repatchingFunction = operationValueMulOptimize;
1955 auto nonRepatchingFunction = operationValueMul;
1956 compileMathIC(mulIC, repatchingFunction, nonRepatchingFunction);
1961 DFG_CRASH(m_graph, m_node, "Bad use kind");
1966 void compileArithDiv()
1968 switch (m_node->binaryUseKind()) {
1970 LValue numerator = lowInt32(m_node->child1());
1971 LValue denominator = lowInt32(m_node->child2());
1973 if (shouldCheckNegativeZero(m_node->arithMode())) {
1974 LBasicBlock zeroNumerator = m_out.newBlock();
1975 LBasicBlock numeratorContinuation = m_out.newBlock();
1978 m_out.isZero32(numerator),
1979 rarely(zeroNumerator), usually(numeratorContinuation));
1981 LBasicBlock innerLastNext = m_out.appendTo(zeroNumerator, numeratorContinuation);
1984 NegativeZero, noValue(), 0, m_out.lessThan(denominator, m_out.int32Zero));
1986 m_out.jump(numeratorContinuation);
1988 m_out.appendTo(numeratorContinuation, innerLastNext);
1991 if (shouldCheckOverflow(m_node->arithMode())) {
1992 LBasicBlock unsafeDenominator = m_out.newBlock();
1993 LBasicBlock continuation = m_out.newBlock();
1995 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
1997 m_out.above(adjustedDenominator, m_out.int32One),
1998 usually(continuation), rarely(unsafeDenominator));
2000 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
2001 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
2002 speculate(Overflow, noValue(), nullptr, m_out.isZero32(denominator));
2003 speculate(Overflow, noValue(), nullptr, m_out.equal(numerator, neg2ToThe31));
2004 m_out.jump(continuation);
2006 m_out.appendTo(continuation, lastNext);
2007 LValue result = m_out.div(numerator, denominator);
2009 Overflow, noValue(), 0,
2010 m_out.notEqual(m_out.mul(result, denominator), numerator));
2013 setInt32(m_out.chillDiv(numerator, denominator));
2018 case DoubleRepUse: {
2019 setDouble(m_out.doubleDiv(
2020 lowDouble(m_node->child1()), lowDouble(m_node->child2())));
2025 emitBinarySnippet<JITDivGenerator, NeedScratchFPR>(operationValueDiv);
2030 DFG_CRASH(m_graph, m_node, "Bad use kind");
2035 void compileArithMod()
2037 switch (m_node->binaryUseKind()) {
2039 LValue numerator = lowInt32(m_node->child1());
2040 LValue denominator = lowInt32(m_node->child2());
2043 if (shouldCheckOverflow(m_node->arithMode())) {
2044 LBasicBlock unsafeDenominator = m_out.newBlock();
2045 LBasicBlock continuation = m_out.newBlock();
2047 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
2049 m_out.above(adjustedDenominator, m_out.int32One),
2050 usually(continuation), rarely(unsafeDenominator));
2052 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
2053 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
2054 speculate(Overflow, noValue(), nullptr, m_out.isZero32(denominator));
2055 speculate(Overflow, noValue(), nullptr, m_out.equal(numerator, neg2ToThe31));
2056 m_out.jump(continuation);
2058 m_out.appendTo(continuation, lastNext);
2059 LValue result = m_out.mod(numerator, denominator);
2062 remainder = m_out.chillMod(numerator, denominator);
2064 if (shouldCheckNegativeZero(m_node->arithMode())) {
2065 LBasicBlock negativeNumerator = m_out.newBlock();
2066 LBasicBlock numeratorContinuation = m_out.newBlock();
2069 m_out.lessThan(numerator, m_out.int32Zero),
2070 unsure(negativeNumerator), unsure(numeratorContinuation));
2072 LBasicBlock innerLastNext = m_out.appendTo(negativeNumerator, numeratorContinuation);
2074 speculate(NegativeZero, noValue(), 0, m_out.isZero32(remainder));
2076 m_out.jump(numeratorContinuation);
2078 m_out.appendTo(numeratorContinuation, innerLastNext);
2081 setInt32(remainder);
2085 case DoubleRepUse: {
2087 m_out.doubleMod(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
2092 DFG_CRASH(m_graph, m_node, "Bad use kind");
2097 void compileArithMinOrMax()
2099 switch (m_node->binaryUseKind()) {
2101 LValue left = lowInt32(m_node->child1());
2102 LValue right = lowInt32(m_node->child2());
2106 m_node->op() == ArithMin
2107 ? m_out.lessThan(left, right)
2108 : m_out.lessThan(right, left),
2113 case DoubleRepUse: {
2114 LValue left = lowDouble(m_node->child1());
2115 LValue right = lowDouble(m_node->child2());
2117 LBasicBlock notLessThan = m_out.newBlock();
2118 LBasicBlock continuation = m_out.newBlock();
2120 Vector<ValueFromBlock, 2> results;
2122 results.append(m_out.anchor(left));
2124 m_node->op() == ArithMin
2125 ? m_out.doubleLessThan(left, right)
2126 : m_out.doubleGreaterThan(left, right),
2127 unsure(continuation), unsure(notLessThan));
2129 LBasicBlock lastNext = m_out.appendTo(notLessThan, continuation);
2130 results.append(m_out.anchor(m_out.select(
2131 m_node->op() == ArithMin
2132 ? m_out.doubleGreaterThanOrEqual(left, right)
2133 : m_out.doubleLessThanOrEqual(left, right),
2134 right, m_out.constDouble(PNaN))));
2135 m_out.jump(continuation);
2137 m_out.appendTo(continuation, lastNext);
2138 setDouble(m_out.phi(Double, results));
2143 DFG_CRASH(m_graph, m_node, "Bad use kind");
2148 void compileArithAbs()
2150 switch (m_node->child1().useKind()) {
2152 LValue value = lowInt32(m_node->child1());
2154 LValue mask = m_out.aShr(value, m_out.constInt32(31));
2155 LValue result = m_out.bitXor(mask, m_out.add(mask, value));
2157 if (shouldCheckOverflow(m_node->arithMode()))
2158 speculate(Overflow, noValue(), 0, m_out.lessThan(result, m_out.int32Zero));
2164 case DoubleRepUse: {
2165 setDouble(m_out.doubleAbs(lowDouble(m_node->child1())));
2170 DFG_ASSERT(m_graph, m_node, m_node->child1().useKind() == UntypedUse);
2171 LValue argument = lowJSValue(m_node->child1());
2172 LValue result = vmCall(Double, m_out.operation(operationArithAbs), m_callFrame, argument);
2179 void compileArithSin()
2181 if (m_node->child1().useKind() == DoubleRepUse) {
2182 setDouble(m_out.doubleSin(lowDouble(m_node->child1())));
2185 LValue argument = lowJSValue(m_node->child1());
2186 LValue result = vmCall(Double, m_out.operation(operationArithSin), m_callFrame, argument);
2190 void compileArithCos()
2192 if (m_node->child1().useKind() == DoubleRepUse) {
2193 setDouble(m_out.doubleCos(lowDouble(m_node->child1())));
2196 LValue argument = lowJSValue(m_node->child1());
2197 LValue result = vmCall(Double, m_out.operation(operationArithCos), m_callFrame, argument);
2201 void compileArithTan()
2203 if (m_node->child1().useKind() == DoubleRepUse) {
2204 setDouble(m_out.doubleTan(lowDouble(m_node->child1())));
2207 LValue argument = lowJSValue(m_node->child1());
2208 LValue result = vmCall(Double, m_out.operation(operationArithTan), m_callFrame, argument);
2212 void compileArithPow()
2214 if (m_node->child2().useKind() == Int32Use)
2215 setDouble(m_out.doublePowi(lowDouble(m_node->child1()), lowInt32(m_node->child2())));
2217 LValue base = lowDouble(m_node->child1());
2218 LValue exponent = lowDouble(m_node->child2());
2220 LBasicBlock integerExponentIsSmallBlock = m_out.newBlock();
2221 LBasicBlock integerExponentPowBlock = m_out.newBlock();
2222 LBasicBlock doubleExponentPowBlockEntry = m_out.newBlock();
2223 LBasicBlock nanExceptionBaseIsOne = m_out.newBlock();
2224 LBasicBlock nanExceptionExponentIsInfinity = m_out.newBlock();
2225 LBasicBlock testExponentIsOneHalf = m_out.newBlock();
2226 LBasicBlock handleBaseZeroExponentIsOneHalf = m_out.newBlock();
2227 LBasicBlock handleInfinityForExponentIsOneHalf = m_out.newBlock();
2228 LBasicBlock exponentIsOneHalfNormal = m_out.newBlock();
2229 LBasicBlock exponentIsOneHalfInfinity = m_out.newBlock();
2230 LBasicBlock testExponentIsNegativeOneHalf = m_out.newBlock();
2231 LBasicBlock testBaseZeroExponentIsNegativeOneHalf = m_out.newBlock();
2232 LBasicBlock handleBaseZeroExponentIsNegativeOneHalf = m_out.newBlock();
2233 LBasicBlock handleInfinityForExponentIsNegativeOneHalf = m_out.newBlock();
2234 LBasicBlock exponentIsNegativeOneHalfNormal = m_out.newBlock();
2235 LBasicBlock exponentIsNegativeOneHalfInfinity = m_out.newBlock();
2236 LBasicBlock powBlock = m_out.newBlock();
2237 LBasicBlock nanExceptionResultIsNaN = m_out.newBlock();
2238 LBasicBlock continuation = m_out.newBlock();
2240 LValue integerExponent = m_out.doubleToInt(exponent);
2241 LValue integerExponentConvertedToDouble = m_out.intToDouble(integerExponent);
2242 LValue exponentIsInteger = m_out.doubleEqual(exponent, integerExponentConvertedToDouble);
2243 m_out.branch(exponentIsInteger, unsure(integerExponentIsSmallBlock), unsure(doubleExponentPowBlockEntry));
2245 LBasicBlock lastNext = m_out.appendTo(integerExponentIsSmallBlock, integerExponentPowBlock);
2246 LValue integerExponentBelowMax = m_out.belowOrEqual(integerExponent, m_out.constInt32(maxExponentForIntegerMathPow));
2247 m_out.branch(integerExponentBelowMax, usually(integerExponentPowBlock), rarely(doubleExponentPowBlockEntry));
2249 m_out.appendTo(integerExponentPowBlock, doubleExponentPowBlockEntry);
2250 ValueFromBlock powDoubleIntResult = m_out.anchor(m_out.doublePowi(base, integerExponent));
2251 m_out.jump(continuation);
2253 // If y is NaN, the result is NaN.
2254 m_out.appendTo(doubleExponentPowBlockEntry, nanExceptionBaseIsOne);
2255 LValue exponentIsNaN;
2256 if (provenType(m_node->child2()) & SpecDoubleNaN)
2257 exponentIsNaN = m_out.doubleNotEqualOrUnordered(exponent, exponent);
2259 exponentIsNaN = m_out.booleanFalse;
2260 m_out.branch(exponentIsNaN, rarely(nanExceptionResultIsNaN), usually(nanExceptionBaseIsOne));
2262 // If abs(x) is 1 and y is +infinity, the result is NaN.
2263 // If abs(x) is 1 and y is -infinity, the result is NaN.
2265 // Test if base == 1.
2266 m_out.appendTo(nanExceptionBaseIsOne, nanExceptionExponentIsInfinity);
2267 LValue absoluteBase = m_out.doubleAbs(base);
2268 LValue absoluteBaseIsOne = m_out.doubleEqual(absoluteBase, m_out.constDouble(1));
2269 m_out.branch(absoluteBaseIsOne, rarely(nanExceptionExponentIsInfinity), usually(testExponentIsOneHalf));
2271 // Test if abs(y) == Infinity.
2272 m_out.appendTo(nanExceptionExponentIsInfinity, testExponentIsOneHalf);
2273 LValue absoluteExponent = m_out.doubleAbs(exponent);
2274 LValue absoluteExponentIsInfinity = m_out.doubleEqual(absoluteExponent, m_out.constDouble(std::numeric_limits<double>::infinity()));
2275 m_out.branch(absoluteExponentIsInfinity, rarely(nanExceptionResultIsNaN), usually(testExponentIsOneHalf));
2277 // If y == 0.5 or y == -0.5, handle it through SQRT.
2278 // We have be carefuly with -0 and -Infinity.
2281 m_out.appendTo(testExponentIsOneHalf, handleBaseZeroExponentIsOneHalf);
2282 LValue exponentIsOneHalf = m_out.doubleEqual(exponent, m_out.constDouble(0.5));
2283 m_out.branch(exponentIsOneHalf, rarely(handleBaseZeroExponentIsOneHalf), usually(testExponentIsNegativeOneHalf));
2286 m_out.appendTo(handleBaseZeroExponentIsOneHalf, handleInfinityForExponentIsOneHalf);
2287 LValue baseIsZeroExponentIsOneHalf = m_out.doubleEqual(base, m_out.doubleZero);
2288 ValueFromBlock zeroResultExponentIsOneHalf = m_out.anchor(m_out.doubleZero);
2289 m_out.branch(baseIsZeroExponentIsOneHalf, rarely(continuation), usually(handleInfinityForExponentIsOneHalf));
2291 // Test if abs(x) == Infinity.
2292 m_out.appendTo(handleInfinityForExponentIsOneHalf, exponentIsOneHalfNormal);
2293 LValue absoluteBaseIsInfinityOneHalf = m_out.doubleEqual(absoluteBase, m_out.constDouble(std::numeric_limits<double>::infinity()));
2294 m_out.branch(absoluteBaseIsInfinityOneHalf, rarely(exponentIsOneHalfInfinity), usually(exponentIsOneHalfNormal));
2296 // The exponent is 0.5, the base is finite or NaN, we can use SQRT.
2297 m_out.appendTo(exponentIsOneHalfNormal, exponentIsOneHalfInfinity);
2298 ValueFromBlock sqrtResult = m_out.anchor(m_out.doubleSqrt(base));
2299 m_out.jump(continuation);
2301 // The exponent is 0.5, the base is infinite, the result is always infinite.
2302 m_out.appendTo(exponentIsOneHalfInfinity, testExponentIsNegativeOneHalf);
2303 ValueFromBlock sqrtInfinityResult = m_out.anchor(m_out.constDouble(std::numeric_limits<double>::infinity()));
2304 m_out.jump(continuation);
2306 // Test if y == -0.5
2307 m_out.appendTo(testExponentIsNegativeOneHalf, testBaseZeroExponentIsNegativeOneHalf);
2308 LValue exponentIsNegativeOneHalf = m_out.doubleEqual(exponent, m_out.constDouble(-0.5));
2309 m_out.branch(exponentIsNegativeOneHalf, rarely(testBaseZeroExponentIsNegativeOneHalf), usually(powBlock));
2312 m_out.appendTo(testBaseZeroExponentIsNegativeOneHalf, handleBaseZeroExponentIsNegativeOneHalf);
2313 LValue baseIsZeroExponentIsNegativeOneHalf = m_out.doubleEqual(base, m_out.doubleZero);
2314 m_out.branch(baseIsZeroExponentIsNegativeOneHalf, rarely(handleBaseZeroExponentIsNegativeOneHalf), usually(handleInfinityForExponentIsNegativeOneHalf));
2316 m_out.appendTo(handleBaseZeroExponentIsNegativeOneHalf, handleInfinityForExponentIsNegativeOneHalf);
2317 ValueFromBlock oneOverSqrtZeroResult = m_out.anchor(m_out.constDouble(std::numeric_limits<double>::infinity()));
2318 m_out.jump(continuation);
2320 // Test if abs(x) == Infinity.
2321 m_out.appendTo(handleInfinityForExponentIsNegativeOneHalf, exponentIsNegativeOneHalfNormal);
2322 LValue absoluteBaseIsInfinityNegativeOneHalf = m_out.doubleEqual(absoluteBase, m_out.constDouble(std::numeric_limits<double>::infinity()));
2323 m_out.branch(absoluteBaseIsInfinityNegativeOneHalf, rarely(exponentIsNegativeOneHalfInfinity), usually(exponentIsNegativeOneHalfNormal));
2325 // The exponent is -0.5, the base is finite or NaN, we can use 1/SQRT.
2326 m_out.appendTo(exponentIsNegativeOneHalfNormal, exponentIsNegativeOneHalfInfinity);
2327 LValue sqrtBase = m_out.doubleSqrt(base);
2328 ValueFromBlock oneOverSqrtResult = m_out.anchor(m_out.div(m_out.constDouble(1.), sqrtBase));
2329 m_out.jump(continuation);
2331 // The exponent is -0.5, the base is infinite, the result is always zero.
2332 m_out.appendTo(exponentIsNegativeOneHalfInfinity, powBlock);
2333 ValueFromBlock oneOverSqrtInfinityResult = m_out.anchor(m_out.doubleZero);
2334 m_out.jump(continuation);
2336 m_out.appendTo(powBlock, nanExceptionResultIsNaN);
2337 ValueFromBlock powResult = m_out.anchor(m_out.doublePow(base, exponent));
2338 m_out.jump(continuation);
2340 m_out.appendTo(nanExceptionResultIsNaN, continuation);
2341 ValueFromBlock pureNan = m_out.anchor(m_out.constDouble(PNaN));
2342 m_out.jump(continuation);
2344 m_out.appendTo(continuation, lastNext);
2345 setDouble(m_out.phi(Double, powDoubleIntResult, zeroResultExponentIsOneHalf, sqrtResult, sqrtInfinityResult, oneOverSqrtZeroResult, oneOverSqrtResult, oneOverSqrtInfinityResult, powResult, pureNan));
2349 void compileArithRandom()
2351 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
2353 // Inlined WeakRandom::advance().
2354 // uint64_t x = m_low;
2355 void* lowAddress = reinterpret_cast<uint8_t*>(globalObject) + JSGlobalObject::weakRandomOffset() + WeakRandom::lowOffset();
2356 LValue low = m_out.load64(m_out.absolute(lowAddress));
2357 // uint64_t y = m_high;
2358 void* highAddress = reinterpret_cast<uint8_t*>(globalObject) + JSGlobalObject::weakRandomOffset() + WeakRandom::highOffset();
2359 LValue high = m_out.load64(m_out.absolute(highAddress));
2361 m_out.store64(high, m_out.absolute(lowAddress));
2364 LValue phase1 = m_out.bitXor(m_out.shl(low, m_out.constInt64(23)), low);
2367 LValue phase2 = m_out.bitXor(m_out.lShr(phase1, m_out.constInt64(17)), phase1);
2369 // x ^= y ^ (y >> 26);
2370 LValue phase3 = m_out.bitXor(m_out.bitXor(high, m_out.lShr(high, m_out.constInt64(26))), phase2);
2373 m_out.store64(phase3, m_out.absolute(highAddress));
2376 LValue random64 = m_out.add(phase3, high);
2378 // Extract random 53bit. [0, 53] bit is safe integer number ranges in double representation.
2379 LValue random53 = m_out.bitAnd(random64, m_out.constInt64((1ULL << 53) - 1));
2381 LValue double53Integer = m_out.intToDouble(random53);
2383 // Convert `(53bit double integer value) / (1 << 53)` to `(53bit double integer value) * (1.0 / (1 << 53))`.
2384 // In latter case, `1.0 / (1 << 53)` will become a double value represented as (mantissa = 0 & exp = 970, it means 1e-(2**54)).
2385 static const double scale = 1.0 / (1ULL << 53);
2387 // Multiplying 1e-(2**54) with the double integer does not change anything of the mantissa part of the double integer.
2388 // It just reduces the exp part of the given 53bit double integer.
2389 // (Except for 0.0. This is specially handled and in this case, exp just becomes 0.)
2390 // Now we get 53bit precision random double value in [0, 1).
2391 LValue result = m_out.doubleMul(double53Integer, m_out.constDouble(scale));
2396 void compileArithRound()
2398 if (m_node->child1().useKind() == DoubleRepUse) {
2399 LValue result = nullptr;
2400 if (producesInteger(m_node->arithRoundingMode()) && !shouldCheckNegativeZero(m_node->arithRoundingMode())) {
2401 LValue value = lowDouble(m_node->child1());
2402 result = m_out.doubleFloor(m_out.doubleAdd(value, m_out.constDouble(0.5)));
2404 LBasicBlock realPartIsMoreThanHalf = m_out.newBlock();
2405 LBasicBlock continuation = m_out.newBlock();
2407 LValue value = lowDouble(m_node->child1());
2408 LValue integerValue = m_out.doubleCeil(value);
2409 ValueFromBlock integerValueResult = m_out.anchor(integerValue);
2411 LValue realPart = m_out.doubleSub(integerValue, value);
2413 m_out.branch(m_out.doubleGreaterThanOrUnordered(realPart, m_out.constDouble(0.5)), unsure(realPartIsMoreThanHalf), unsure(continuation));
2415 LBasicBlock lastNext = m_out.appendTo(realPartIsMoreThanHalf, continuation);
2416 LValue integerValueRoundedDown = m_out.doubleSub(integerValue, m_out.constDouble(1));
2417 ValueFromBlock integerValueRoundedDownResult = m_out.anchor(integerValueRoundedDown);
2418 m_out.jump(continuation);
2419 m_out.appendTo(continuation, lastNext);
2421 result = m_out.phi(Double, integerValueResult, integerValueRoundedDownResult);
2424 if (producesInteger(m_node->arithRoundingMode())) {
2425 LValue integerValue = convertDoubleToInt32(result, shouldCheckNegativeZero(m_node->arithRoundingMode()));
2426 setInt32(integerValue);
2432 DFG_ASSERT(m_graph, m_node, m_node->child1().useKind() == UntypedUse);
2433 LValue argument = lowJSValue(m_node->child1());
2434 setJSValue(vmCall(Int64, m_out.operation(operationArithRound), m_callFrame, argument));
2437 void compileArithFloor()
2439 if (m_node->child1().useKind() == DoubleRepUse) {
2440 LValue value = lowDouble(m_node->child1());
2441 LValue integerValue = m_out.doubleFloor(value);
2442 if (producesInteger(m_node->arithRoundingMode()))
2443 setInt32(convertDoubleToInt32(integerValue, shouldCheckNegativeZero(m_node->arithRoundingMode())));
2445 setDouble(integerValue);
2448 DFG_ASSERT(m_graph, m_node, m_node->child1().useKind() == UntypedUse);
2449 LValue argument = lowJSValue(m_node->child1());
2450 setJSValue(vmCall(Int64, m_out.operation(operationArithFloor), m_callFrame, argument));
2453 void compileArithCeil()
2455 if (m_node->child1().useKind() == DoubleRepUse) {
2456 LValue value = lowDouble(m_node->child1());
2457 LValue integerValue = m_out.doubleCeil(value);
2458 if (producesInteger(m_node->arithRoundingMode()))
2459 setInt32(convertDoubleToInt32(integerValue, shouldCheckNegativeZero(m_node->arithRoundingMode())));
2461 setDouble(integerValue);
2464 DFG_ASSERT(m_graph, m_node, m_node->child1().useKind() == UntypedUse);
2465 LValue argument = lowJSValue(m_node->child1());
2466 setJSValue(vmCall(Int64, m_out.operation(operationArithCeil), m_callFrame, argument));
2469 void compileArithTrunc()
2471 if (m_node->child1().useKind() == DoubleRepUse) {
2472 LValue value = lowDouble(m_node->child1());
2473 LValue result = m_out.doubleTrunc(value);
2474 if (producesInteger(m_node->arithRoundingMode()))
2475 setInt32(convertDoubleToInt32(result, shouldCheckNegativeZero(m_node->arithRoundingMode())));
2480 DFG_ASSERT(m_graph, m_node, m_node->child1().useKind() == UntypedUse);
2481 LValue argument = lowJSValue(m_node->child1());
2482 setJSValue(vmCall(Int64, m_out.operation(operationArithTrunc), m_callFrame, argument));
2485 void compileArithSqrt()
2487 if (m_node->child1().useKind() == DoubleRepUse) {
2488 setDouble(m_out.doubleSqrt(lowDouble(m_node->child1())));
2491 LValue argument = lowJSValue(m_node->child1());
2492 LValue result = vmCall(Double, m_out.operation(operationArithSqrt), m_callFrame, argument);
2496 void compileArithLog()
2498 if (m_node->child1().useKind() == DoubleRepUse) {
2499 setDouble(m_out.doubleLog(lowDouble(m_node->child1())));
2502 LValue argument = lowJSValue(m_node->child1());
2503 LValue result = vmCall(Double, m_out.operation(operationArithLog), m_callFrame, argument);
2507 void compileArithFRound()
2509 if (m_node->child1().useKind() == DoubleRepUse) {
2510 setDouble(m_out.fround(lowDouble(m_node->child1())));
2513 LValue argument = lowJSValue(m_node->child1());
2514 LValue result = vmCall(Double, m_out.operation(operationArithFRound), m_callFrame, argument);
2518 void compileArithNegate()
2520 switch (m_node->child1().useKind()) {
2522 LValue value = lowInt32(m_node->child1());
2525 if (!shouldCheckOverflow(m_node->arithMode()))
2526 result = m_out.neg(value);
2527 else if (!shouldCheckNegativeZero(m_node->arithMode())) {
2528 CheckValue* check = m_out.speculateSub(m_out.int32Zero, value);
2529 blessSpeculation(check, Overflow, noValue(), nullptr, m_origin);
2532 speculate(Overflow, noValue(), 0, m_out.testIsZero32(value, m_out.constInt32(0x7fffffff)));
2533 result = m_out.neg(value);
2541 if (!abstractValue(m_node->child1()).couldBeType(SpecInt52Only)) {
2543 LValue value = lowWhicheverInt52(m_node->child1(), kind);
2544 LValue result = m_out.neg(value);
2545 if (shouldCheckNegativeZero(m_node->arithMode()))
2546 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
2547 setInt52(result, kind);
2551 LValue value = lowInt52(m_node->child1());
2552 CheckValue* result = m_out.speculateSub(m_out.int64Zero, value);
2553 blessSpeculation(result, Int52Overflow, noValue(), nullptr, m_origin);
2554 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
2559 case DoubleRepUse: {
2560 setDouble(m_out.doubleNeg(lowDouble(m_node->child1())));
2565 DFG_ASSERT(m_graph, m_node, m_node->child1().useKind() == UntypedUse);
2566 ArithProfile* arithProfile = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic)->arithProfileForBytecodeOffset(m_node->origin.semantic.bytecodeIndex);
2567 JITNegIC* negIC = codeBlock()->addJITNegIC(arithProfile);
2568 auto repatchingFunction = operationArithNegateOptimize;
2569 auto nonRepatchingFunction = operationArithNegate;
2570 compileMathIC(negIC, repatchingFunction, nonRepatchingFunction);
2575 void compileBitAnd()
2577 if (m_node->isBinaryUseKind(UntypedUse)) {
2578 emitBinaryBitOpSnippet<JITBitAndGenerator>(operationValueBitAnd);
2581 setInt32(m_out.bitAnd(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
2586 if (m_node->isBinaryUseKind(UntypedUse)) {
2587 emitBinaryBitOpSnippet<JITBitOrGenerator>(operationValueBitOr);
2590 setInt32(m_out.bitOr(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
2593 void compileBitXor()
2595 if (m_node->isBinaryUseKind(UntypedUse)) {
2596 emitBinaryBitOpSnippet<JITBitXorGenerator>(operationValueBitXor);
2599 setInt32(m_out.bitXor(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
2602 void compileBitRShift()
2604 if (m_node->isBinaryUseKind(UntypedUse)) {
2605 emitRightShiftSnippet(JITRightShiftGenerator::SignedShift);
2608 setInt32(m_out.aShr(
2609 lowInt32(m_node->child1()),
2610 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2613 void compileBitLShift()
2615 if (m_node->isBinaryUseKind(UntypedUse)) {
2616 emitBinaryBitOpSnippet<JITLeftShiftGenerator>(operationValueBitLShift);
2620 lowInt32(m_node->child1()),
2621 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2624 void compileBitURShift()
2626 if (m_node->isBinaryUseKind(UntypedUse)) {
2627 emitRightShiftSnippet(JITRightShiftGenerator::UnsignedShift);
2630 setInt32(m_out.lShr(
2631 lowInt32(m_node->child1()),
2632 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2635 void compileUInt32ToNumber()
2637 LValue value = lowInt32(m_node->child1());
2639 if (doesOverflow(m_node->arithMode())) {
2640 setStrictInt52(m_out.zeroExtPtr(value));
2644 speculate(Overflow, noValue(), 0, m_out.lessThan(value, m_out.int32Zero));
2648 void compileCheckStructure()
2651 if (m_node->child1()->hasConstant())
2652 exitKind = BadConstantCache;
2654 exitKind = BadCache;
2656 switch (m_node->child1().useKind()) {
2658 case KnownCellUse: {
2659 LValue cell = lowCell(m_node->child1());
2662 m_out.load32(cell, m_heaps.JSCell_structureID), jsValueValue(cell),
2663 exitKind, m_node->structureSet(),
2664 [&] (Structure* structure) {
2665 return weakStructureID(structure);
2670 case CellOrOtherUse: {
2671 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
2673 LBasicBlock cellCase = m_out.newBlock();
2674 LBasicBlock notCellCase = m_out.newBlock();
2675 LBasicBlock continuation = m_out.newBlock();
2678 isCell(value, provenType(m_node->child1())), unsure(cellCase), unsure(notCellCase));
2680 LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase);
2682 m_out.load32(value, m_heaps.JSCell_structureID), jsValueValue(value),
2683 exitKind, m_node->structureSet(),
2684 [&] (Structure* structure) {
2685 return weakStructureID(structure);
2687 m_out.jump(continuation);
2689 m_out.appendTo(notCellCase, continuation);
2690 FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), SpecCell | SpecOther, isNotOther(value));
2691 m_out.jump(continuation);
2693 m_out.appendTo(continuation, lastNext);
2698 DFG_CRASH(m_graph, m_node, "Bad use kind");
2703 void compileCheckCell()
2705 LValue cell = lowCell(m_node->child1());
2708 BadCell, jsValueValue(cell), m_node->child1().node(),
2709 m_out.notEqual(cell, weakPointer(m_node->cellOperand()->cell())));
2712 void compileCheckBadCell()
2717 void compileCheckNotEmpty()
2719 speculate(TDZFailure, noValue(), nullptr, m_out.isZero64(lowJSValue(m_node->child1())));
2722 void compileCheckStringIdent()
2724 UniquedStringImpl* uid = m_node->uidOperand();
2725 LValue stringImpl = lowStringIdent(m_node->child1());
2726 speculate(BadIdent, noValue(), nullptr, m_out.notEqual(stringImpl, m_out.constIntPtr(uid)));
2729 void compileGetExecutable()
2731 LValue cell = lowCell(m_node->child1());
2732 speculateFunction(m_node->child1(), cell);
2733 setJSValue(m_out.loadPtr(cell, m_heaps.JSFunction_executable));
2736 void compileArrayifyToStructure()
2738 LValue cell = lowCell(m_node->child1());
2739 LValue property = !!m_node->child2() ? lowInt32(m_node->child2()) : 0;
2741 LBasicBlock unexpectedStructure = m_out.newBlock();
2742 LBasicBlock continuation = m_out.newBlock();
2744 LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
2747 m_out.notEqual(structureID, weakStructureID(m_node->structure())),
2748 rarely(unexpectedStructure), usually(continuation));
2750 LBasicBlock lastNext = m_out.appendTo(unexpectedStructure, continuation);
2753 switch (m_node->arrayMode().type()) {
2756 case Array::Contiguous:
2758 Uncountable, noValue(), 0,
2759 m_out.aboveOrEqual(property, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)));
2766 switch (m_node->arrayMode().type()) {
2768 vmCall(Void, m_out.operation(operationEnsureInt32), m_callFrame, cell);
2771 vmCall(Void, m_out.operation(operationEnsureDouble), m_callFrame, cell);
2773 case Array::Contiguous:
2774 vmCall(Void, m_out.operation(operationEnsureContiguous), m_callFrame, cell);
2776 case Array::ArrayStorage:
2777 case Array::SlowPutArrayStorage:
2778 vmCall(Void, m_out.operation(operationEnsureArrayStorage), m_callFrame, cell);
2781 DFG_CRASH(m_graph, m_node, "Bad array type");
2785 structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
2787 BadIndexingType, jsValueValue(cell), 0,
2788 m_out.notEqual(structureID, weakStructureID(m_node->structure())));
2789 m_out.jump(continuation);
2791 m_out.appendTo(continuation, lastNext);
2794 void compilePutStructure()
2796 m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node);
2798 Structure* oldStructure = m_node->transition()->previous;
2799 Structure* newStructure = m_node->transition()->next;
2800 ASSERT_UNUSED(oldStructure, oldStructure->indexingType() == newStructure->indexingType());
2801 ASSERT(oldStructure->typeInfo().inlineTypeFlags() == newStructure->typeInfo().inlineTypeFlags());
2802 ASSERT(oldStructure->typeInfo().type() == newStructure->typeInfo().type());
2804 LValue cell = lowCell(m_node->child1());
2806 weakStructureID(newStructure),
2807 cell, m_heaps.JSCell_structureID);
2810 void compileGetById(AccessType type)
2812 ASSERT(type == AccessType::Get || type == AccessType::GetPure);
2813 switch (m_node->child1().useKind()) {
2815 setJSValue(getById(lowCell(m_node->child1()), type));
2820 // This is pretty weird, since we duplicate the slow path both here and in the
2821 // code generated by the IC. We should investigate making this less bad.
2822 // https://bugs.webkit.org/show_bug.cgi?id=127830
2823 LValue value = lowJSValue(m_node->child1());
2825 LBasicBlock cellCase = m_out.newBlock();
2826 LBasicBlock notCellCase = m_out.newBlock();
2827 LBasicBlock continuation = m_out.newBlock();
2830 isCell(value, provenType(m_node->child1())), unsure(cellCase), unsure(notCellCase));
2832 LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase);
2833 ValueFromBlock cellResult = m_out.anchor(getById(value, type));
2834 m_out.jump(continuation);
2836 J_JITOperation_EJI getByIdFunction;
2837 if (type == AccessType::Get)
2838 getByIdFunction = operationGetByIdGeneric;
2840 getByIdFunction = operationTryGetByIdGeneric;
2842 m_out.appendTo(notCellCase, continuation);
2843 ValueFromBlock notCellResult = m_out.anchor(vmCall(
2844 Int64, m_out.operation(getByIdFunction),
2846 m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()])));
2847 m_out.jump(continuation);
2849 m_out.appendTo(continuation, lastNext);
2850 setJSValue(m_out.phi(Int64, cellResult, notCellResult));
2855 DFG_CRASH(m_graph, m_node, "Bad use kind");
2860 void compileGetByIdWithThis()
2862 LValue base = lowJSValue(m_node->child1());
2863 LValue thisValue = lowJSValue(m_node->child2());
2864 LValue result = vmCall(Int64, m_out.operation(operationGetByIdWithThis), m_callFrame, base, thisValue, m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()]));
2868 void compileGetByValWithThis()
2870 LValue base = lowJSValue(m_node->child1());
2871 LValue thisValue = lowJSValue(m_node->child2());
2872 LValue subscript = lowJSValue(m_node->child3());
2874 LValue result = vmCall(Int64, m_out.operation(operationGetByValWithThis), m_callFrame, base, thisValue, subscript);
2878 void compilePutByIdWithThis()
2880 LValue base = lowJSValue(m_node->child1());
2881 LValue thisValue = lowJSValue(m_node->child2());
2882 LValue value = lowJSValue(m_node->child3());
2884 vmCall(Void, m_out.operation(m_graph.isStrictModeFor(m_node->origin.semantic) ? operationPutByIdWithThisStrict : operationPutByIdWithThis),
2885 m_callFrame, base, thisValue, value, m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()]));
2888 void compilePutByValWithThis()
2890 LValue base = lowJSValue(m_graph.varArgChild(m_node, 0));
2891 LValue thisValue = lowJSValue(m_graph.varArgChild(m_node, 1));
2892 LValue property = lowJSValue(m_graph.varArgChild(m_node, 2));
2893 LValue value = lowJSValue(m_graph.varArgChild(m_node, 3));
2895 vmCall(Void, m_out.operation(m_graph.isStrictModeFor(m_node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis),
2896 m_callFrame, base, thisValue, property, value);
2899 void compileDefineDataProperty()
2901 LValue base = lowCell(m_graph.varArgChild(m_node, 0));
2902 LValue value = lowJSValue(m_graph.varArgChild(m_node, 2));
2903 LValue attributes = lowInt32(m_graph.varArgChild(m_node, 3));
2904 Edge& propertyEdge = m_graph.varArgChild(m_node, 1);
2905 switch (propertyEdge.useKind()) {
2907 LValue property = lowString(propertyEdge);
2908 vmCall(Void, m_out.operation(operationDefineDataPropertyString), m_callFrame, base, property, value, attributes);
2911 case StringIdentUse: {
2912 LValue property = lowStringIdent(propertyEdge);
2913 vmCall(Void, m_out.operation(operationDefineDataPropertyStringIdent), m_callFrame, base, property, value, attributes);
2917 LValue property = lowSymbol(propertyEdge);
2918 vmCall(Void, m_out.operation(operationDefineDataPropertySymbol), m_callFrame, base, property, value, attributes);
2922 LValue property = lowJSValue(propertyEdge);
2923 vmCall(Void, m_out.operation(operationDefineDataProperty), m_callFrame, base, property, value, attributes);
2927 RELEASE_ASSERT_NOT_REACHED();
2931 void compileDefineAccessorProperty()
2933 LValue base = lowCell(m_graph.varArgChild(m_node, 0));
2934 LValue getter = lowCell(m_graph.varArgChild(m_node, 2));
2935 LValue setter = lowCell(m_graph.varArgChild(m_node, 3));
2936 LValue attributes = lowInt32(m_graph.varArgChild(m_node, 4));
2937 Edge& propertyEdge = m_graph.varArgChild(m_node, 1);
2938 switch (propertyEdge.useKind()) {
2940 LValue property = lowString(propertyEdge);
2941 vmCall(Void, m_out.operation(operationDefineAccessorPropertyString), m_callFrame, base, property, getter, setter, attributes);
2944 case StringIdentUse: {
2945 LValue property = lowStringIdent(propertyEdge);
2946 vmCall(Void, m_out.operation(operationDefineAccessorPropertyStringIdent), m_callFrame, base, property, getter, setter, attributes);
2950 LValue property = lowSymbol(propertyEdge);
2951 vmCall(Void, m_out.operation(operationDefineAccessorPropertySymbol), m_callFrame, base, property, getter, setter, attributes);
2955 LValue property = lowJSValue(propertyEdge);
2956 vmCall(Void, m_out.operation(operationDefineAccessorProperty), m_callFrame, base, property, getter, setter, attributes);
2960 RELEASE_ASSERT_NOT_REACHED();
2964 void compilePutById()
2966 DFG_ASSERT(m_graph, m_node, m_node->child1().useKind() == CellUse);
2968 Node* node = m_node;
2969 LValue base = lowCell(node->child1());
2970 LValue value = lowJSValue(node->child2());
2971 auto uid = m_graph.identifiers()[node->identifierNumber()];
2973 B3::PatchpointValue* patchpoint = m_out.patchpoint(Void);
2974 patchpoint->appendSomeRegister(base);
2975 patchpoint->appendSomeRegister(value);
2976 patchpoint->append(m_tagMask, ValueRep::reg(GPRInfo::tagMaskRegister));
2977 patchpoint->append(m_tagTypeNumber, ValueRep::reg(GPRInfo::tagTypeNumberRegister));
2978 patchpoint->clobber(RegisterSet::macroScratchRegisters());
2980 // FIXME: If this is a PutByIdFlush, we might want to late-clobber volatile registers.
2981 // https://bugs.webkit.org/show_bug.cgi?id=152848
2983 RefPtr<PatchpointExceptionHandle> exceptionHandle =
2984 preparePatchpointForExceptions(patchpoint);
2986 State* state = &m_ftlState;
2987 ECMAMode ecmaMode = m_graph.executableFor(node->origin.semantic)->ecmaMode();
2989 patchpoint->setGenerator(
2990 [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
2991 AllowMacroScratchRegisterUsage allowScratch(jit);
2993 CallSiteIndex callSiteIndex =
2994 state->jitCode->common.addUniqueCallSiteIndex(node->origin.semantic);
2996 Box<CCallHelpers::JumpList> exceptions =
2997 exceptionHandle->scheduleExitCreation(params)->jumps(jit);
2999 // JS setter call ICs generated by the PutById IC will need this.
3000 exceptionHandle->scheduleExitCreationForUnwind(params, callSiteIndex);
3002 auto generator = Box<JITPutByIdGenerator>::create(
3003 jit.codeBlock(), node->origin.semantic, callSiteIndex,
3004 params.unavailableRegisters(), JSValueRegs(params[0].gpr()),
3005 JSValueRegs(params[1].gpr()), GPRInfo::patchpointScratchRegister, ecmaMode,
3006 node->op() == PutByIdDirect ? Direct : NotDirect);
3008 generator->generateFastPath(jit);
3009 CCallHelpers::Label done = jit.label();
3012 [=] (CCallHelpers& jit) {
3013 AllowMacroScratchRegisterUsage allowScratch(jit);
3015 generator->slowPathJump().link(&jit);
3016 CCallHelpers::Label slowPathBegin = jit.label();
3017 CCallHelpers::Call slowPathCall = callOperation(
3018 *state, params.unavailableRegisters(), jit, node->origin.semantic,
3019 exceptions.get(), generator->slowPathFunction(), InvalidGPRReg,
3020 CCallHelpers::TrustedImmPtr(generator->stubInfo()), params[1].gpr(),
3021 params[0].gpr(), CCallHelpers::TrustedImmPtr(uid)).call();
3022 jit.jump().linkTo(done, &jit);
3024 generator->reportSlowPathCall(slowPathBegin, slowPathCall);
3027 [=] (LinkBuffer& linkBuffer) {
3028 generator->finalize(linkBuffer);
3034 void compileGetButterfly()
3036 setStorage(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSObject_butterfly));
3039 void compileConstantStoragePointer()
3041 setStorage(m_out.constIntPtr(m_node->storagePointer()));
3044 void compileGetIndexedPropertyStorage()
3046 LValue cell = lowCell(m_node->child1());
3048 if (m_node->arrayMode().type() == Array::String) {
3049 LBasicBlock slowPath = m_out.newBlock();
3050 LBasicBlock continuation = m_out.newBlock();
3052 LValue fastResultValue = m_out.loadPtr(cell, m_heaps.JSString_value);
3053 ValueFromBlock fastResult = m_out.anchor(fastResultValue);
3056 m_out.notNull(fastResultValue), usually(continuation), rarely(slowPath));
3058 LBasicBlock lastNext = m_out.appendTo(slowPath, continuation);
3060 ValueFromBlock slowResult = m_out.anchor(
3061 vmCall(pointerType(), m_out.operation(operationResolveRope), m_callFrame, cell));
3063 m_out.jump(continuation);
3065 m_out.appendTo(continuation, lastNext);
3067 setStorage(m_out.loadPtr(m_out.phi(pointerType(), fastResult, slowResult), m_heaps.StringImpl_data));
3071 DFG_ASSERT(m_graph, m_node, isTypedView(m_node->arrayMode().typedArrayType()));
3072 setStorage(m_out.loadPtr(cell, m_heaps.JSArrayBufferView_vector));
3075 void compileCheckArray()
3077 Edge edge = m_node->child1();
3078 LValue cell = lowCell(edge);
3080 if (m_node->arrayMode().alreadyChecked(m_graph, m_node, abstractValue(edge)))
3084 BadIndexingType, jsValueValue(cell), 0,
3085 m_out.logicalNot(isArrayType(cell, m_node->arrayMode())));
3088 void compileGetTypedArrayByteOffset()
3090 LValue basePtr = lowCell(m_node->child1());
3092 LBasicBlock simpleCase = m_out.newBlock();
3093 LBasicBlock wastefulCase = m_out.newBlock();
3094 LBasicBlock continuation = m_out.newBlock();
3096 LValue mode = m_out.load32(basePtr, m_heaps.JSArrayBufferView_mode);
3098 m_out.notEqual(mode, m_out.constInt32(WastefulTypedArray)),
3099 unsure(simpleCase), unsure(wastefulCase));
3101 LBasicBlock lastNext = m_out.appendTo(simpleCase, wastefulCase);
3103 ValueFromBlock simpleOut = m_out.anchor(m_out.constIntPtr(0));
3105 m_out.jump(continuation);
3107 m_out.appendTo(wastefulCase, continuation);
3109 LValue vectorPtr = m_out.loadPtr(basePtr, m_heaps.JSArrayBufferView_vector);
3110 LValue butterflyPtr = m_out.loadPtr(basePtr, m_heaps.JSObject_butterfly);
3111 LValue arrayBufferPtr = m_out.loadPtr(butterflyPtr, m_heaps.Butterfly_arrayBuffer);
3112 LValue dataPtr = m_out.loadPtr(arrayBufferPtr, m_heaps.ArrayBuffer_data);
3114 ValueFromBlock wastefulOut = m_out.anchor(m_out.sub(vectorPtr, dataPtr));
3116 m_out.jump(continuation);
3117 m_out.appendTo(continuation, lastNext);
3119 setInt32(m_out.castToInt32(m_out.phi(pointerType(), simpleOut, wastefulOut)));
3122 void compileGetArrayLength()
3124 switch (m_node->arrayMode().type()) {
3125 case Array::Undecided:
3128 case Array::Contiguous: {
3129 setInt32(m_out.load32NonNegative(lowStorage(m_node->child2()), m_heaps.Butterfly_publicLength));
3133 case Array::String: {
3134 LValue string = lowCell(m_node->child1());
3135 setInt32(m_out.load32NonNegative(string, m_heaps.JSString_length));
3139 case Array::DirectArguments: {
3140 LValue arguments = lowCell(m_node->child1());
3142 ExoticObjectMode, noValue(), nullptr,
3143 m_out.notNull(m_out.loadPtr(arguments, m_heaps.DirectArguments_overrides)));
3144 setInt32(m_out.load32NonNegative(arguments, m_heaps.DirectArguments_length));
3148 case Array::ScopedArguments: {
3149 LValue arguments = lowCell(m_node->child1());
3151 ExoticObjectMode, noValue(), nullptr,
3152 m_out.notZero32(m_out.load8ZeroExt32(arguments, m_heaps.ScopedArguments_overrodeThings)));
3153 setInt32(m_out.load32NonNegative(arguments, m_heaps.ScopedArguments_totalLength));
3158 if (m_node->arrayMode().isSomeTypedArrayView()) {
3160 m_out.load32NonNegative(lowCell(m_node->child1()), m_heaps.JSArrayBufferView_length));
3164 DFG_CRASH(m_graph, m_node, "Bad array type");
3169 void compileCheckInBounds()
3172 OutOfBounds, noValue(), 0,
3173 m_out.aboveOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
3176 void compileGetByVal()
3178 switch (m_node->arrayMode().type()) {
3180 case Array::Contiguous: {
3181 LValue index = lowInt32(m_node->child2());
3182 LValue storage = lowStorage(m_node->child3());
3184 IndexedAbstractHeap& heap = m_node->arrayMode().type() == Array::Int32 ?
3185 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties;
3187 if (m_node->arrayMode().isInBounds()) {
3188 LValue result = m_out.load64(baseIndex(heap, storage, index, m_node->child2()));
3189 LValue isHole = m_out.isZero64(result);
3190 if (m_node->arrayMode().isSaneChain()) {
3192 m_graph, m_node, m_node->arrayMode().type() == Array::Contiguous);
3193 result = m_out.select(
3194 isHole, m_out.constInt64(JSValue::encode(jsUndefined())), result);
3196 speculate(LoadFromHole, noValue(), 0, isHole);
3201 LValue base = lowCell(m_node->child1());
3203 LBasicBlock fastCase = m_out.newBlock();
3204 LBasicBlock slowCase = m_out.newBlock();
3205 LBasicBlock continuation = m_out.newBlock();
3209 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
3210 rarely(slowCase), usually(fastCase));
3212 LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
3214 LValue fastResultValue = m_out.load64(baseIndex(heap, storage, index, m_node->child2()));
3215 ValueFromBlock fastResult = m_out.anchor(fastResultValue);
3217 m_out.isZero64(fastResultValue), rarely(slowCase), usually(continuation));
3219 m_out.appendTo(slowCase, continuation);
3220 ValueFromBlock slowResult = m_out.anchor(
3221 vmCall(Int64, m_out.operation(operationGetByValArrayInt), m_callFrame, base, index));
3222 m_out.jump(continuation);
3224 m_out.appendTo(continuation, lastNext);
3225 setJSValue(m_out.phi(Int64, fastResult, slowResult));
3229 case Array::Double: {
3230 LValue index = lowInt32(m_node->child2());
3231 LValue storage = lowStorage(m_node->child3());
3233 IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties;
3235 if (m_node->arrayMode().isInBounds()) {
3236 LValue result = m_out.loadDouble(
3237 baseIndex(heap, storage, index, m_node->child2()));
3239 if (!m_node->arrayMode().isSaneChain()) {
3241 LoadFromHole, noValue(), 0,
3242 m_out.doubleNotEqualOrUnordered(result, result));
3248 LValue base = lowCell(m_node->child1());
3250 LBasicBlock inBounds = m_out.newBlock();
3251 LBasicBlock boxPath = m_out.newBlock();
3252 LBasicBlock slowCase = m_out.newBlock();
3253 LBasicBlock continuation = m_out.newBlock();
3257 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
3258 rarely(slowCase), usually(inBounds));
3260 LBasicBlock lastNext = m_out.appendTo(inBounds, boxPath);
3261 LValue doubleValue = m_out.loadDouble(
3262 baseIndex(heap, storage, index, m_node->child2()));
3264 m_out.doubleNotEqualOrUnordered(doubleValue, doubleValue),
3265 rarely(slowCase), usually(boxPath));
3267 m_out.appendTo(boxPath, slowCase);
3268 ValueFromBlock fastResult = m_out.anchor(boxDouble(doubleValue));
3269 m_out.jump(continuation);
3271 m_out.appendTo(slowCase, continuation);
3272 ValueFromBlock slowResult = m_out.anchor(
3273 vmCall(Int64, m_out.operation(operationGetByValArrayInt), m_callFrame, base, index));
3274 m_out.jump(continuation);
3276 m_out.appendTo(continuation, lastNext);
3277 setJSValue(m_out.phi(Int64, fastResult, slowResult));
3281 case Array::Undecided: {
3282 LValue index = lowInt32(m_node->child2());
3284 speculate(OutOfBounds, noValue(), m_node, m_out.lessThan(index, m_out.int32Zero));
3285 setJSValue(m_out.constInt64(ValueUndefined));
3289 case Array::DirectArguments: {
3290 LValue base = lowCell(m_node->child1());
3291 LValue index = lowInt32(m_node->child2());
3294 ExoticObjectMode, noValue(), nullptr,
3295 m_out.notNull(m_out.loadPtr(base, m_heaps.DirectArguments_overrides)));
3297 ExoticObjectMode, noValue(), nullptr,
3300 m_out.load32NonNegative(base, m_heaps.DirectArguments_length)));
3302 TypedPointer address = m_out.baseIndex(
3303 m_heaps.DirectArguments_storage, base, m_out.zeroExtPtr(index));
3304 setJSValue(m_out.load64(address));
3308 case Array::ScopedArguments: {
3309 LValue base = lowCell(m_node->child1());
3310 LValue index = lowInt32(m_node->child2());
3313 ExoticObjectMode, noValue(), nullptr,
3316 m_out.load32NonNegative(base, m_heaps.ScopedArguments_totalLength)));
3318 LValue table = m_out.loadPtr(base, m_heaps.ScopedArguments_table);
3319 LValue namedLength = m_out.load32(table, m_heaps.ScopedArgumentsTable_length);
3321 LBasicBlock namedCase = m_out.newBlock();
3322 LBasicBlock overflowCase = m_out.newBlock();
3323 LBasicBlock continuation = m_out.newBlock();
3326 m_out.aboveOrEqual(index, namedLength), unsure(overflowCase), unsure(namedCase));
3328 LBasicBlock lastNext = m_out.appendTo(namedCase, overflowCase);
3330 LValue scope = m_out.loadPtr(base, m_heaps.ScopedArguments_scope);
3331 LValue arguments = m_out.loadPtr(table, m_heaps.ScopedArgumentsTable_arguments);
3333 TypedPointer address = m_out.baseIndex(
3334 m_heaps.scopedArgumentsTableArguments, arguments, m_out.zeroExtPtr(index));
3335 LValue scopeOffset = m_out.load32(address);
3338 ExoticObjectMode, noValue(), nullptr,
3339 m_out.equal(scopeOffset, m_out.constInt32(ScopeOffset::invalidOffset)));
3341 address = m_out.baseIndex(
3342 m_heaps.JSEnvironmentRecord_variables, scope, m_out.zeroExtPtr(scopeOffset));
3343 ValueFromBlock namedResult = m_out.anchor(m_out.load64(address));
3344 m_out.jump(continuation);
3346 m_out.appendTo(overflowCase, continuation);
3348 address = m_out.baseIndex(
3349 m_heaps.ScopedArguments_overflowStorage, base,
3350 m_out.zeroExtPtr(m_out.sub(index, namedLength)));
3351 LValue overflowValue = m_out.load64(address);
3352 speculate(ExoticObjectMode, noValue(), nullptr, m_out.isZero64(overflowValue));
3353 ValueFromBlock overflowResult = m_out.anchor(overflowValue);
3354 m_out.jump(continuation);
3356 m_out.appendTo(continuation, lastNext);
3357 setJSValue(m_out.phi(Int64, namedResult, overflowResult));
3361 case Array::Generic: {
3363 Int64, m_out.operation(operationGetByVal), m_callFrame,
3364 lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));
3368 case Array::String: {
3369 compileStringCharAt();
3374 LValue index = lowInt32(m_node->child2());
3375 LValue storage = lowStorage(m_node->child3());
3377 TypedArrayType type = m_node->arrayMode().typedArrayType();
3379 if (isTypedView(type)) {
3380 TypedPointer pointer = TypedPointer(
3381 m_heaps.typedArrayProperties,
3385 m_out.zeroExtPtr(index),
3386 m_out.constIntPtr(logElementSize(type)))));
3390 switch (elementSize(type)) {
3392 result = isSigned(type) ? m_out.load8SignExt32(pointer) : m_out.load8ZeroExt32(pointer);
3395 result = isSigned(type) ? m_out.load16SignExt32(pointer) : m_out.load16ZeroExt32(pointer);
3398 result = m_out.load32(pointer);
3401 DFG_CRASH(m_graph, m_node, "Bad element size");
3404 if (elementSize(type) < 4 || isSigned(type)) {
3409 if (m_node->shouldSpeculateInt32()) {
3411 Overflow, noValue(), 0, m_out.lessThan(result, m_out.int32Zero));
3416 if (m_node->shouldSpeculateAnyInt()) {
3417 setStrictInt52(m_out.zeroExt(result, Int64));
3421 setDouble(m_out.unsignedToDouble(result));
3425 ASSERT(isFloat(type));
3430 result = m_out.floatToDouble(m_out.loadFloat(pointer));
3433 result = m_out.loadDouble(pointer);
3436 DFG_CRASH(m_graph, m_node, "Bad typed array type");
3443 DFG_CRASH(m_graph, m_node, "Bad array type");
3448 void compileGetMyArgumentByVal()
3450 InlineCallFrame* inlineCallFrame = m_node->child1()->origin.semantic.inlineCallFrame;
3452 LValue index = lowInt32(m_node->child2());
3453 if (m_node->numberOfArgumentsToSkip())
3454 index = m_out.add(index, m_out.constInt32(m_node->numberOfArgumentsToSkip()));
3457 if (inlineCallFrame && !inlineCallFrame->isVarargs())
3458 limit = m_out.constInt32(inlineCallFrame->arguments.size() - 1);
3460 VirtualRegister argumentCountRegister = AssemblyHelpers::argumentCount(inlineCallFrame);
3461 limit = m_out.sub(m_out.load32(payloadFor(argumentCountRegister)), m_out.int32One);
3464 LValue isOutOfBounds = m_out.aboveOrEqual(index, limit);
3465 LBasicBlock continuation = nullptr;
3466 LBasicBlock lastNext = nullptr;
3467 ValueFromBlock slowResult;
3468 if (m_node->op() == GetMyArgumentByValOutOfBounds) {
3469 LBasicBlock normalCase = m_out.newBlock();
3470 continuation = m_out.newBlock();
3472 slowResult = m_out.anchor(m_out.constInt64(JSValue::encode(jsUndefined())));
3473 m_out.branch(isOutOfBounds, unsure(continuation), unsure(normalCase));
3475 lastNext = m_out.appendTo(normalCase, continuation);
3477 speculate(ExoticObjectMode, noValue(), 0, isOutOfBounds);
3480 if (inlineCallFrame) {
3481 if (inlineCallFrame->arguments.size() > 1)
3482 base = addressFor(inlineCallFrame->arguments[1].virtualRegister());
3484 base = addressFor(virtualRegisterForArgument(1));
3488 LValue pointer = m_out.baseIndex(
3489 base.value(), m_out.zeroExt(index, pointerType()), ScaleEight);
3490 result = m_out.load64(TypedPointer(m_heaps.variables.atAnyIndex(), pointer));
3492 result = m_out.constInt64(JSValue::encode(jsUndefined()));
3494 if (m_node->op() == GetMyArgumentByValOutOfBounds) {
3495 ValueFromBlock normalResult = m_out.anchor(result);
3496 m_out.jump(continuation);
3498 m_out.appendTo(continuation, lastNext);
3499 result = m_out.phi(Int64, slowResult, normalResult);
3505 void compilePutByVal()
3507 Edge child1 = m_graph.varArgChild(m_node, 0);
3508 Edge child2 = m_graph.varArgChild(m_node, 1);
3509 Edge child3 = m_graph.varArgChild(m_node, 2);
3510 Edge child4 = m_graph.varArgChild(m_node, 3);
3511 Edge child5 = m_graph.varArgChild(m_node, 4);
3513 switch (m_node->arrayMode().type()) {
3514 case Array::Generic: {
3515 V_JITOperation_EJJJ operation;
3516 if (m_node->op() == PutByValDirect) {
3517 if (m_graph.isStrictModeFor(m_node->origin.semantic))
3518 operation = operationPutByValDirectStrict;
3520 operation = operationPutByValDirectNonStrict;
3522 if (m_graph.isStrictModeFor(m_node->origin.semantic))
3523 operation = operationPutByValStrict;
3525 operation = operationPutByValNonStrict;
3529 Void, m_out.operation(operation), m_callFrame,
3530 lowJSValue(child1), lowJSValue(child2), lowJSValue(child3));
3538 LValue base = lowCell(child1);
3539 LValue index = lowInt32(child2);
3540 LValue storage = lowStorage(child4);
3542 switch (m_node->arrayMode().type()) {
3545 case Array::Contiguous: {
3546 LBasicBlock continuation = m_out.newBlock();
3547 LBasicBlock outerLastNext = m_out.appendTo(m_out.m_block, continuation);
3549 switch (m_node->arrayMode().type()) {
3551 case Array::Contiguous: {
3552 LValue value = lowJSValue(child3, ManualOperandSpeculation);
3554 if (m_node->arrayMode().type() == Array::Int32)
3555 FTL_TYPE_CHECK(jsValueValue(value), child3, SpecInt32Only, isNotInt32(value));
3557 TypedPointer elementPointer = m_out.baseIndex(
3558 m_node->arrayMode().type() == Array::Int32 ?
3559 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties,
3560 storage, m_out.zeroExtPtr(index), provenValue(child2));
3562 if (m_node->op() == PutByValAlias) {
3563 m_out.store64(value, elementPointer);
3567 contiguousPutByValOutOfBounds(
3568 codeBlock()->isStrictMode()
3569 ? operationPutByValBeyondArrayBoundsStrict
3570 : operationPutByValBeyondArrayBoundsNonStrict,
3571 base, storage, index, value, continuation);
3573 m_out.store64(value, elementPointer);
3577 case Array::Double: {
3578 LValue value = lowDouble(child3);
3581 doubleValue(value), child3, SpecDoubleReal,
3582 m_out.doubleNotEqualOrUnordered(value, value));
3584 TypedPointer elementPointer = m_out.baseIndex(
3585 m_heaps.indexedDoubleProperties, storage, m_out.zeroExtPtr(index),
3586 provenValue(child2));
3588 if (m_node->op() == PutByValAlias) {
3589 m_out.storeDouble(value, elementPointer);
3593 contiguousPutByValOutOfBounds(
3594 codeBlock()->isStrictMode()
3595 ? operationPutDoubleByValBeyondArrayBoundsStrict
3596 : operationPutDoubleByValBeyondArrayBoundsNonStrict,
3597 base, storage, index, value, continuation);
3599 m_out.storeDouble(value, elementPointer);
3604 DFG_CRASH(m_graph, m_node, "Bad array type");