]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - ftl/FTLLowerDFGToLLVM.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / ftl / FTLLowerDFGToLLVM.cpp
... / ...
CommitLineData
1/*
2 * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "FTLLowerDFGToLLVM.h"
28
29#if ENABLE(FTL_JIT)
30
31#include "CodeBlockWithJITType.h"
32#include "DFGAbstractInterpreterInlines.h"
33#include "DFGInPlaceAbstractState.h"
34#include "DFGOSRAvailabilityAnalysisPhase.h"
35#include "DFGOSRExitFuzz.h"
36#include "DirectArguments.h"
37#include "FTLAbstractHeapRepository.h"
38#include "FTLAvailableRecovery.h"
39#include "FTLForOSREntryJITCode.h"
40#include "FTLFormattedValue.h"
41#include "FTLInlineCacheSize.h"
42#include "FTLLoweredNodeValue.h"
43#include "FTLOperations.h"
44#include "FTLOutput.h"
45#include "FTLThunks.h"
46#include "FTLWeightedTarget.h"
47#include "JSCInlines.h"
48#include "JSLexicalEnvironment.h"
49#include "OperandsInlines.h"
50#include "ScopedArguments.h"
51#include "ScopedArgumentsTable.h"
52#include "VirtualRegister.h"
53#include <atomic>
54#include <dlfcn.h>
55#include <llvm/InitializeLLVM.h>
56#include <unordered_set>
57#include <wtf/ProcessID.h>
58
59#if ENABLE(FTL_NATIVE_CALL_INLINING)
60#include "BundlePath.h"
61#endif
62
63namespace JSC { namespace FTL {
64
65using namespace DFG;
66
67namespace {
68
69std::atomic<int> compileCounter;
70
71#if ASSERT_DISABLED
72NO_RETURN_DUE_TO_CRASH static void ftlUnreachable()
73{
74 CRASH();
75}
76#else
77NO_RETURN_DUE_TO_CRASH static void ftlUnreachable(
78 CodeBlock* codeBlock, BlockIndex blockIndex, unsigned nodeIndex)
79{
80 dataLog("Crashing in thought-to-be-unreachable FTL-generated code for ", pointerDump(codeBlock), " at basic block #", blockIndex);
81 if (nodeIndex != UINT_MAX)
82 dataLog(", node @", nodeIndex);
83 dataLog(".\n");
84 CRASH();
85}
86#endif
87
88// Using this instead of typeCheck() helps to reduce the load on LLVM, by creating
89// significantly less dead code.
90#define FTL_TYPE_CHECK(lowValue, highValue, typesPassedThrough, failCondition) do { \
91 FormattedValue _ftc_lowValue = (lowValue); \
92 Edge _ftc_highValue = (highValue); \
93 SpeculatedType _ftc_typesPassedThrough = (typesPassedThrough); \
94 if (!m_interpreter.needsTypeCheck(_ftc_highValue, _ftc_typesPassedThrough)) \
95 break; \
96 typeCheck(_ftc_lowValue, _ftc_highValue, _ftc_typesPassedThrough, (failCondition)); \
97 } while (false)
98
99class LowerDFGToLLVM {
100public:
101 LowerDFGToLLVM(State& state)
102 : m_graph(state.graph)
103 , m_ftlState(state)
104 , m_heaps(state.context)
105 , m_out(state.context)
106 , m_state(state.graph)
107 , m_interpreter(state.graph, m_state)
108 , m_stackmapIDs(0)
109 , m_tbaaKind(mdKindID(state.context, "tbaa"))
110 , m_tbaaStructKind(mdKindID(state.context, "tbaa.struct"))
111 {
112 }
113
114 void lower()
115 {
116 CString name;
117 if (verboseCompilationEnabled()) {
118 name = toCString(
119 "jsBody_", ++compileCounter, "_", codeBlock()->inferredName(),
120 "_", codeBlock()->hash());
121 } else
122 name = "jsBody";
123
124 m_graph.m_dominators.computeIfNecessary(m_graph);
125
126 m_ftlState.module =
127 moduleCreateWithNameInContext(name.data(), m_ftlState.context);
128
129 m_ftlState.function = addFunction(
130 m_ftlState.module, name.data(), functionType(m_out.int64));
131 setFunctionCallingConv(m_ftlState.function, LLVMCCallConv);
132 if (isX86() && Options::llvmDisallowAVX()) {
133 // AVX makes V8/raytrace 80% slower. It makes Kraken/audio-oscillator 4.5x
134 // slower. It should be disabled.
135 addTargetDependentFunctionAttr(m_ftlState.function, "target-features", "-avx");
136 }
137
138 if (verboseCompilationEnabled())
139 dataLog("Function ready, beginning lowering.\n");
140
141 m_out.initialize(m_ftlState.module, m_ftlState.function, m_heaps);
142
143 m_prologue = FTL_NEW_BLOCK(m_out, ("Prologue"));
144 LBasicBlock stackOverflow = FTL_NEW_BLOCK(m_out, ("Stack overflow"));
145 m_handleExceptions = FTL_NEW_BLOCK(m_out, ("Handle Exceptions"));
146
147 LBasicBlock checkArguments = FTL_NEW_BLOCK(m_out, ("Check arguments"));
148
149 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
150 m_highBlock = m_graph.block(blockIndex);
151 if (!m_highBlock)
152 continue;
153 m_blocks.add(m_highBlock, FTL_NEW_BLOCK(m_out, ("Block ", *m_highBlock)));
154 }
155
156 m_out.appendTo(m_prologue, stackOverflow);
157 createPhiVariables();
158
159 auto preOrder = m_graph.blocksInPreOrder();
160
161 int maxNumberOfArguments = -1;
162 for (BasicBlock* block : preOrder) {
163 for (unsigned nodeIndex = block->size(); nodeIndex--; ) {
164 Node* node = block->at(nodeIndex);
165 switch (node->op()) {
166 case NativeCall:
167 case NativeConstruct: {
168 int numArgs = node->numChildren();
169 if (numArgs > maxNumberOfArguments)
170 maxNumberOfArguments = numArgs;
171 break;
172 }
173 default:
174 break;
175 }
176 }
177 }
178
179 if (maxNumberOfArguments >= 0) {
180 m_execState = m_out.alloca(arrayType(m_out.int64, JSStack::CallFrameHeaderSize + maxNumberOfArguments));
181 m_execStorage = m_out.ptrToInt(m_execState, m_out.intPtr);
182 }
183
184 LValue capturedAlloca = m_out.alloca(arrayType(m_out.int64, m_graph.m_nextMachineLocal));
185
186 m_captured = m_out.add(
187 m_out.ptrToInt(capturedAlloca, m_out.intPtr),
188 m_out.constIntPtr(m_graph.m_nextMachineLocal * sizeof(Register)));
189
190 m_ftlState.capturedStackmapID = m_stackmapIDs++;
191 m_out.call(
192 m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.capturedStackmapID),
193 m_out.int32Zero, capturedAlloca);
194
195 // If we have any CallVarargs then we nee to have a spill slot for it.
196 bool hasVarargs = false;
197 for (BasicBlock* block : preOrder) {
198 for (Node* node : *block) {
199 switch (node->op()) {
200 case CallVarargs:
201 case CallForwardVarargs:
202 case ConstructVarargs:
203 case ConstructForwardVarargs:
204 hasVarargs = true;
205 break;
206 default:
207 break;
208 }
209 }
210 }
211 if (hasVarargs) {
212 LValue varargsSpillSlots = m_out.alloca(
213 arrayType(m_out.int64, JSCallVarargs::numSpillSlotsNeeded()));
214 m_ftlState.varargsSpillSlotsStackmapID = m_stackmapIDs++;
215 m_out.call(
216 m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.varargsSpillSlotsStackmapID),
217 m_out.int32Zero, varargsSpillSlots);
218 }
219
220 // We should not create any alloca's after this point, since they will cease to
221 // be mem2reg candidates.
222
223 m_callFrame = m_out.ptrToInt(
224 m_out.call(m_out.frameAddressIntrinsic(), m_out.int32Zero), m_out.intPtr);
225 m_tagTypeNumber = m_out.constInt64(TagTypeNumber);
226 m_tagMask = m_out.constInt64(TagMask);
227
228 m_out.storePtr(m_out.constIntPtr(codeBlock()), addressFor(JSStack::CodeBlock));
229
230 m_out.branch(
231 didOverflowStack(), rarely(stackOverflow), usually(checkArguments));
232
233 m_out.appendTo(stackOverflow, m_handleExceptions);
234 m_out.call(m_out.operation(operationThrowStackOverflowError), m_callFrame, m_out.constIntPtr(codeBlock()));
235 m_ftlState.handleStackOverflowExceptionStackmapID = m_stackmapIDs++;
236 m_out.call(
237 m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.handleStackOverflowExceptionStackmapID),
238 m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
239 m_out.unreachable();
240
241 m_out.appendTo(m_handleExceptions, checkArguments);
242 m_ftlState.handleExceptionStackmapID = m_stackmapIDs++;
243 m_out.call(
244 m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.handleExceptionStackmapID),
245 m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
246 m_out.unreachable();
247
248 m_out.appendTo(checkArguments, lowBlock(m_graph.block(0)));
249 availabilityMap().clear();
250 availabilityMap().m_locals = Operands<Availability>(codeBlock()->numParameters(), 0);
251 for (unsigned i = codeBlock()->numParameters(); i--;) {
252 availabilityMap().m_locals.argument(i) =
253 Availability(FlushedAt(FlushedJSValue, virtualRegisterForArgument(i)));
254 }
255 m_codeOriginForExitTarget = CodeOrigin(0);
256 m_codeOriginForExitProfile = CodeOrigin(0);
257 m_node = nullptr;
258 for (unsigned i = codeBlock()->numParameters(); i--;) {
259 Node* node = m_graph.m_arguments[i];
260 VirtualRegister operand = virtualRegisterForArgument(i);
261
262 LValue jsValue = m_out.load64(addressFor(operand));
263
264 if (node) {
265 DFG_ASSERT(m_graph, node, operand == node->stackAccessData()->machineLocal);
266
267 // This is a hack, but it's an effective one. It allows us to do CSE on the
268 // primordial load of arguments. This assumes that the GetLocal that got put in
269 // place of the original SetArgument doesn't have any effects before it. This
270 // should hold true.
271 m_loadedArgumentValues.add(node, jsValue);
272 }
273
274 switch (m_graph.m_argumentFormats[i]) {
275 case FlushedInt32:
276 speculate(BadType, jsValueValue(jsValue), node, isNotInt32(jsValue));
277 break;
278 case FlushedBoolean:
279 speculate(BadType, jsValueValue(jsValue), node, isNotBoolean(jsValue));
280 break;
281 case FlushedCell:
282 speculate(BadType, jsValueValue(jsValue), node, isNotCell(jsValue));
283 break;
284 case FlushedJSValue:
285 break;
286 default:
287 DFG_CRASH(m_graph, node, "Bad flush format for argument");
288 break;
289 }
290 }
291 m_out.jump(lowBlock(m_graph.block(0)));
292
293 for (BasicBlock* block : preOrder)
294 compileBlock(block);
295
296 if (Options::dumpLLVMIR())
297 dumpModule(m_ftlState.module);
298
299 if (verboseCompilationEnabled())
300 m_ftlState.dumpState("after lowering");
301 if (validationEnabled())
302 verifyModule(m_ftlState.module);
303 }
304
305private:
306
307 void createPhiVariables()
308 {
309 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
310 BasicBlock* block = m_graph.block(blockIndex);
311 if (!block)
312 continue;
313 for (unsigned nodeIndex = block->size(); nodeIndex--;) {
314 Node* node = block->at(nodeIndex);
315 if (node->op() != Phi)
316 continue;
317 LType type;
318 switch (node->flags() & NodeResultMask) {
319 case NodeResultDouble:
320 type = m_out.doubleType;
321 break;
322 case NodeResultInt32:
323 type = m_out.int32;
324 break;
325 case NodeResultInt52:
326 type = m_out.int64;
327 break;
328 case NodeResultBoolean:
329 type = m_out.boolean;
330 break;
331 case NodeResultJS:
332 type = m_out.int64;
333 break;
334 default:
335 DFG_CRASH(m_graph, node, "Bad Phi node result type");
336 break;
337 }
338 m_phis.add(node, buildAlloca(m_out.m_builder, type));
339 }
340 }
341 }
342
343 void compileBlock(BasicBlock* block)
344 {
345 if (!block)
346 return;
347
348 if (verboseCompilationEnabled())
349 dataLog("Compiling block ", *block, "\n");
350
351 m_highBlock = block;
352
353 LBasicBlock lowBlock = m_blocks.get(m_highBlock);
354
355 m_nextHighBlock = 0;
356 for (BlockIndex nextBlockIndex = m_highBlock->index + 1; nextBlockIndex < m_graph.numBlocks(); ++nextBlockIndex) {
357 m_nextHighBlock = m_graph.block(nextBlockIndex);
358 if (m_nextHighBlock)
359 break;
360 }
361 m_nextLowBlock = m_nextHighBlock ? m_blocks.get(m_nextHighBlock) : 0;
362
363 // All of this effort to find the next block gives us the ability to keep the
364 // generated IR in roughly program order. This ought not affect the performance
365 // of the generated code (since we expect LLVM to reorder things) but it will
366 // make IR dumps easier to read.
367 m_out.appendTo(lowBlock, m_nextLowBlock);
368
369 if (Options::ftlCrashes())
370 m_out.trap();
371
372 if (!m_highBlock->cfaHasVisited) {
373 if (verboseCompilationEnabled())
374 dataLog("Bailing because CFA didn't reach.\n");
375 crash(m_highBlock->index, UINT_MAX);
376 return;
377 }
378
379 m_availabilityCalculator.beginBlock(m_highBlock);
380
381 m_state.reset();
382 m_state.beginBasicBlock(m_highBlock);
383
384 for (m_nodeIndex = 0; m_nodeIndex < m_highBlock->size(); ++m_nodeIndex) {
385 if (!compileNode(m_nodeIndex))
386 break;
387 }
388 }
389
390 void safelyInvalidateAfterTermination()
391 {
392 if (verboseCompilationEnabled())
393 dataLog("Bailing.\n");
394 crash();
395
396 // Invalidate dominated blocks. Under normal circumstances we would expect
397 // them to be invalidated already. But you can have the CFA become more
398 // precise over time because the structures of objects change on the main
399 // thread. Failing to do this would result in weird crashes due to a value
400 // being used but not defined. Race conditions FTW!
401 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
402 BasicBlock* target = m_graph.block(blockIndex);
403 if (!target)
404 continue;
405 if (m_graph.m_dominators.dominates(m_highBlock, target)) {
406 if (verboseCompilationEnabled())
407 dataLog("Block ", *target, " will bail also.\n");
408 target->cfaHasVisited = false;
409 }
410 }
411 }
412
413 bool compileNode(unsigned nodeIndex)
414 {
415 if (!m_state.isValid()) {
416 safelyInvalidateAfterTermination();
417 return false;
418 }
419
420 m_node = m_highBlock->at(nodeIndex);
421 m_codeOriginForExitProfile = m_node->origin.semantic;
422 m_codeOriginForExitTarget = m_node->origin.forExit;
423
424 if (verboseCompilationEnabled())
425 dataLog("Lowering ", m_node, "\n");
426
427 m_availableRecoveries.resize(0);
428
429 m_interpreter.startExecuting();
430
431 switch (m_node->op()) {
432 case Upsilon:
433 compileUpsilon();
434 break;
435 case Phi:
436 compilePhi();
437 break;
438 case JSConstant:
439 break;
440 case DoubleConstant:
441 compileDoubleConstant();
442 break;
443 case Int52Constant:
444 compileInt52Constant();
445 break;
446 case DoubleRep:
447 compileDoubleRep();
448 break;
449 case DoubleAsInt32:
450 compileDoubleAsInt32();
451 break;
452 case ValueRep:
453 compileValueRep();
454 break;
455 case Int52Rep:
456 compileInt52Rep();
457 break;
458 case ValueToInt32:
459 compileValueToInt32();
460 break;
461 case BooleanToNumber:
462 compileBooleanToNumber();
463 break;
464 case ExtractOSREntryLocal:
465 compileExtractOSREntryLocal();
466 break;
467 case GetStack:
468 compileGetStack();
469 break;
470 case PutStack:
471 compilePutStack();
472 break;
473 case Check:
474 compileNoOp();
475 break;
476 case ToThis:
477 compileToThis();
478 break;
479 case ValueAdd:
480 compileValueAdd();
481 break;
482 case ArithAdd:
483 case ArithSub:
484 compileArithAddOrSub();
485 break;
486 case ArithClz32:
487 compileArithClz32();
488 break;
489 case ArithMul:
490 compileArithMul();
491 break;
492 case ArithDiv:
493 compileArithDiv();
494 break;
495 case ArithMod:
496 compileArithMod();
497 break;
498 case ArithMin:
499 case ArithMax:
500 compileArithMinOrMax();
501 break;
502 case ArithAbs:
503 compileArithAbs();
504 break;
505 case ArithSin:
506 compileArithSin();
507 break;
508 case ArithCos:
509 compileArithCos();
510 break;
511 case ArithPow:
512 compileArithPow();
513 break;
514 case ArithRound:
515 compileArithRound();
516 break;
517 case ArithSqrt:
518 compileArithSqrt();
519 break;
520 case ArithLog:
521 compileArithLog();
522 break;
523 case ArithFRound:
524 compileArithFRound();
525 break;
526 case ArithNegate:
527 compileArithNegate();
528 break;
529 case BitAnd:
530 compileBitAnd();
531 break;
532 case BitOr:
533 compileBitOr();
534 break;
535 case BitXor:
536 compileBitXor();
537 break;
538 case BitRShift:
539 compileBitRShift();
540 break;
541 case BitLShift:
542 compileBitLShift();
543 break;
544 case BitURShift:
545 compileBitURShift();
546 break;
547 case UInt32ToNumber:
548 compileUInt32ToNumber();
549 break;
550 case CheckStructure:
551 compileCheckStructure();
552 break;
553 case CheckCell:
554 compileCheckCell();
555 break;
556 case CheckNotEmpty:
557 compileCheckNotEmpty();
558 break;
559 case CheckBadCell:
560 compileCheckBadCell();
561 break;
562 case GetExecutable:
563 compileGetExecutable();
564 break;
565 case ArrayifyToStructure:
566 compileArrayifyToStructure();
567 break;
568 case PutStructure:
569 compilePutStructure();
570 break;
571 case GetById:
572 compileGetById();
573 break;
574 case In:
575 compileIn();
576 break;
577 case PutById:
578 case PutByIdDirect:
579 compilePutById();
580 break;
581 case GetButterfly:
582 compileGetButterfly();
583 break;
584 case ConstantStoragePointer:
585 compileConstantStoragePointer();
586 break;
587 case GetIndexedPropertyStorage:
588 compileGetIndexedPropertyStorage();
589 break;
590 case CheckArray:
591 compileCheckArray();
592 break;
593 case GetArrayLength:
594 compileGetArrayLength();
595 break;
596 case CheckInBounds:
597 compileCheckInBounds();
598 break;
599 case GetByVal:
600 compileGetByVal();
601 break;
602 case GetMyArgumentByVal:
603 compileGetMyArgumentByVal();
604 break;
605 case PutByVal:
606 case PutByValAlias:
607 case PutByValDirect:
608 compilePutByVal();
609 break;
610 case ArrayPush:
611 compileArrayPush();
612 break;
613 case ArrayPop:
614 compileArrayPop();
615 break;
616 case CreateActivation:
617 compileCreateActivation();
618 break;
619 case NewFunction:
620 compileNewFunction();
621 break;
622 case CreateDirectArguments:
623 compileCreateDirectArguments();
624 break;
625 case CreateScopedArguments:
626 compileCreateScopedArguments();
627 break;
628 case CreateClonedArguments:
629 compileCreateClonedArguments();
630 break;
631 case NewObject:
632 compileNewObject();
633 break;
634 case NewArray:
635 compileNewArray();
636 break;
637 case NewArrayBuffer:
638 compileNewArrayBuffer();
639 break;
640 case NewArrayWithSize:
641 compileNewArrayWithSize();
642 break;
643 case GetTypedArrayByteOffset:
644 compileGetTypedArrayByteOffset();
645 break;
646 case AllocatePropertyStorage:
647 compileAllocatePropertyStorage();
648 break;
649 case ReallocatePropertyStorage:
650 compileReallocatePropertyStorage();
651 break;
652 case ToString:
653 case CallStringConstructor:
654 compileToStringOrCallStringConstructor();
655 break;
656 case ToPrimitive:
657 compileToPrimitive();
658 break;
659 case MakeRope:
660 compileMakeRope();
661 break;
662 case StringCharAt:
663 compileStringCharAt();
664 break;
665 case StringCharCodeAt:
666 compileStringCharCodeAt();
667 break;
668 case GetByOffset:
669 case GetGetterSetterByOffset:
670 compileGetByOffset();
671 break;
672 case GetGetter:
673 compileGetGetter();
674 break;
675 case GetSetter:
676 compileGetSetter();
677 break;
678 case MultiGetByOffset:
679 compileMultiGetByOffset();
680 break;
681 case PutByOffset:
682 compilePutByOffset();
683 break;
684 case MultiPutByOffset:
685 compileMultiPutByOffset();
686 break;
687 case GetGlobalVar:
688 compileGetGlobalVar();
689 break;
690 case PutGlobalVar:
691 compilePutGlobalVar();
692 break;
693 case NotifyWrite:
694 compileNotifyWrite();
695 break;
696 case GetCallee:
697 compileGetCallee();
698 break;
699 case GetArgumentCount:
700 compileGetArgumentCount();
701 break;
702 case GetScope:
703 compileGetScope();
704 break;
705 case SkipScope:
706 compileSkipScope();
707 break;
708 case GetClosureVar:
709 compileGetClosureVar();
710 break;
711 case PutClosureVar:
712 compilePutClosureVar();
713 break;
714 case GetFromArguments:
715 compileGetFromArguments();
716 break;
717 case PutToArguments:
718 compilePutToArguments();
719 break;
720 case CompareEq:
721 compileCompareEq();
722 break;
723 case CompareEqConstant:
724 compileCompareEqConstant();
725 break;
726 case CompareStrictEq:
727 compileCompareStrictEq();
728 break;
729 case CompareLess:
730 compileCompareLess();
731 break;
732 case CompareLessEq:
733 compileCompareLessEq();
734 break;
735 case CompareGreater:
736 compileCompareGreater();
737 break;
738 case CompareGreaterEq:
739 compileCompareGreaterEq();
740 break;
741 case LogicalNot:
742 compileLogicalNot();
743 break;
744 case Call:
745 case Construct:
746 compileCallOrConstruct();
747 break;
748 case CallVarargs:
749 case CallForwardVarargs:
750 case ConstructVarargs:
751 case ConstructForwardVarargs:
752 compileCallOrConstructVarargs();
753 break;
754 case LoadVarargs:
755 compileLoadVarargs();
756 break;
757 case ForwardVarargs:
758 compileForwardVarargs();
759 break;
760#if ENABLE(FTL_NATIVE_CALL_INLINING)
761 case NativeCall:
762 case NativeConstruct:
763 compileNativeCallOrConstruct();
764 break;
765#endif
766 case Jump:
767 compileJump();
768 break;
769 case Branch:
770 compileBranch();
771 break;
772 case Switch:
773 compileSwitch();
774 break;
775 case Return:
776 compileReturn();
777 break;
778 case ForceOSRExit:
779 compileForceOSRExit();
780 break;
781 case Throw:
782 case ThrowReferenceError:
783 compileThrow();
784 break;
785 case InvalidationPoint:
786 compileInvalidationPoint();
787 break;
788 case IsUndefined:
789 compileIsUndefined();
790 break;
791 case IsBoolean:
792 compileIsBoolean();
793 break;
794 case IsNumber:
795 compileIsNumber();
796 break;
797 case IsString:
798 compileIsString();
799 break;
800 case IsObject:
801 compileIsObject();
802 break;
803 case IsObjectOrNull:
804 compileIsObjectOrNull();
805 break;
806 case IsFunction:
807 compileIsFunction();
808 break;
809 case TypeOf:
810 compileTypeOf();
811 break;
812 case CheckHasInstance:
813 compileCheckHasInstance();
814 break;
815 case InstanceOf:
816 compileInstanceOf();
817 break;
818 case CountExecution:
819 compileCountExecution();
820 break;
821 case StoreBarrier:
822 compileStoreBarrier();
823 break;
824 case HasIndexedProperty:
825 compileHasIndexedProperty();
826 break;
827 case HasGenericProperty:
828 compileHasGenericProperty();
829 break;
830 case HasStructureProperty:
831 compileHasStructureProperty();
832 break;
833 case GetDirectPname:
834 compileGetDirectPname();
835 break;
836 case GetEnumerableLength:
837 compileGetEnumerableLength();
838 break;
839 case GetPropertyEnumerator:
840 compileGetPropertyEnumerator();
841 break;
842 case GetEnumeratorStructurePname:
843 compileGetEnumeratorStructurePname();
844 break;
845 case GetEnumeratorGenericPname:
846 compileGetEnumeratorGenericPname();
847 break;
848 case ToIndexString:
849 compileToIndexString();
850 break;
851 case CheckStructureImmediate:
852 compileCheckStructureImmediate();
853 break;
854 case MaterializeNewObject:
855 compileMaterializeNewObject();
856 break;
857 case MaterializeCreateActivation:
858 compileMaterializeCreateActivation();
859 break;
860
861 case PhantomLocal:
862 case LoopHint:
863 case MovHint:
864 case ZombieHint:
865 case PhantomNewObject:
866 case PhantomNewFunction:
867 case PhantomCreateActivation:
868 case PhantomDirectArguments:
869 case PhantomClonedArguments:
870 case PutHint:
871 case BottomValue:
872 case KillStack:
873 break;
874 default:
875 DFG_CRASH(m_graph, m_node, "Unrecognized node in FTL backend");
876 break;
877 }
878
879 if (m_node->isTerminal())
880 return false;
881
882 if (!m_state.isValid()) {
883 safelyInvalidateAfterTermination();
884 return false;
885 }
886
887 m_availabilityCalculator.executeNode(m_node);
888 m_interpreter.executeEffects(nodeIndex);
889
890 return true;
891 }
892
893 void compileUpsilon()
894 {
895 LValue destination = m_phis.get(m_node->phi());
896
897 switch (m_node->child1().useKind()) {
898 case DoubleRepUse:
899 m_out.set(lowDouble(m_node->child1()), destination);
900 break;
901 case Int32Use:
902 m_out.set(lowInt32(m_node->child1()), destination);
903 break;
904 case Int52RepUse:
905 m_out.set(lowInt52(m_node->child1()), destination);
906 break;
907 case BooleanUse:
908 m_out.set(lowBoolean(m_node->child1()), destination);
909 break;
910 case CellUse:
911 m_out.set(lowCell(m_node->child1()), destination);
912 break;
913 case UntypedUse:
914 m_out.set(lowJSValue(m_node->child1()), destination);
915 break;
916 default:
917 DFG_CRASH(m_graph, m_node, "Bad use kind");
918 break;
919 }
920 }
921
922 void compilePhi()
923 {
924 LValue source = m_phis.get(m_node);
925
926 switch (m_node->flags() & NodeResultMask) {
927 case NodeResultDouble:
928 setDouble(m_out.get(source));
929 break;
930 case NodeResultInt32:
931 setInt32(m_out.get(source));
932 break;
933 case NodeResultInt52:
934 setInt52(m_out.get(source));
935 break;
936 case NodeResultBoolean:
937 setBoolean(m_out.get(source));
938 break;
939 case NodeResultJS:
940 setJSValue(m_out.get(source));
941 break;
942 default:
943 DFG_CRASH(m_graph, m_node, "Bad use kind");
944 break;
945 }
946 }
947
948 void compileDoubleConstant()
949 {
950 setDouble(m_out.constDouble(m_node->asNumber()));
951 }
952
953 void compileInt52Constant()
954 {
955 int64_t value = m_node->asMachineInt();
956
957 setInt52(m_out.constInt64(value << JSValue::int52ShiftAmount));
958 setStrictInt52(m_out.constInt64(value));
959 }
960
961 void compileDoubleRep()
962 {
963 switch (m_node->child1().useKind()) {
964 case RealNumberUse: {
965 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
966
967 LValue doubleValue = unboxDouble(value);
968
969 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("DoubleRep RealNumberUse int case"));
970 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("DoubleRep continuation"));
971
972 ValueFromBlock fastResult = m_out.anchor(doubleValue);
973 m_out.branch(
974 m_out.doubleEqual(doubleValue, doubleValue),
975 usually(continuation), rarely(intCase));
976
977 LBasicBlock lastNext = m_out.appendTo(intCase, continuation);
978
979 FTL_TYPE_CHECK(
980 jsValueValue(value), m_node->child1(), SpecBytecodeRealNumber,
981 isNotInt32(value, provenType(m_node->child1()) & ~SpecFullDouble));
982 ValueFromBlock slowResult = m_out.anchor(m_out.intToDouble(unboxInt32(value)));
983 m_out.jump(continuation);
984
985 m_out.appendTo(continuation, lastNext);
986
987 setDouble(m_out.phi(m_out.doubleType, fastResult, slowResult));
988 return;
989 }
990
991 case NotCellUse:
992 case NumberUse: {
993 bool shouldConvertNonNumber = m_node->child1().useKind() == NotCellUse;
994
995 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
996
997 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing int case"));
998 LBasicBlock doubleTesting = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing double case"));
999 LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing double case"));
1000 LBasicBlock nonDoubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing undefined case"));
1001 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing continuation"));
1002
1003 m_out.branch(
1004 isNotInt32(value, provenType(m_node->child1())),
1005 unsure(doubleTesting), unsure(intCase));
1006
1007 LBasicBlock lastNext = m_out.appendTo(intCase, doubleTesting);
1008
1009 ValueFromBlock intToDouble = m_out.anchor(
1010 m_out.intToDouble(unboxInt32(value)));
1011 m_out.jump(continuation);
1012
1013 m_out.appendTo(doubleTesting, doubleCase);
1014 LValue valueIsNumber = isNumber(value, provenType(m_node->child1()));
1015 m_out.branch(valueIsNumber, usually(doubleCase), rarely(nonDoubleCase));
1016
1017 m_out.appendTo(doubleCase, nonDoubleCase);
1018 ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(value));
1019 m_out.jump(continuation);
1020
1021 if (shouldConvertNonNumber) {
1022 LBasicBlock undefinedCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble converting undefined case"));
1023 LBasicBlock testNullCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing null case"));
1024 LBasicBlock nullCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble converting null case"));
1025 LBasicBlock testBooleanTrueCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing boolean true case"));
1026 LBasicBlock convertBooleanTrueCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble convert boolean true case"));
1027 LBasicBlock convertBooleanFalseCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble convert boolean false case"));
1028
1029 m_out.appendTo(nonDoubleCase, undefinedCase);
1030 LValue valueIsUndefined = m_out.equal(value, m_out.constInt64(ValueUndefined));
1031 m_out.branch(valueIsUndefined, unsure(undefinedCase), unsure(testNullCase));
1032
1033 m_out.appendTo(undefinedCase, testNullCase);
1034 ValueFromBlock convertedUndefined = m_out.anchor(m_out.constDouble(PNaN));
1035 m_out.jump(continuation);
1036
1037 m_out.appendTo(testNullCase, nullCase);
1038 LValue valueIsNull = m_out.equal(value, m_out.constInt64(ValueNull));
1039 m_out.branch(valueIsNull, unsure(nullCase), unsure(testBooleanTrueCase));
1040
1041 m_out.appendTo(nullCase, testBooleanTrueCase);
1042 ValueFromBlock convertedNull = m_out.anchor(m_out.constDouble(0));
1043 m_out.jump(continuation);
1044
1045 m_out.appendTo(testBooleanTrueCase, convertBooleanTrueCase);
1046 LValue valueIsBooleanTrue = m_out.equal(value, m_out.constInt64(ValueTrue));
1047 m_out.branch(valueIsBooleanTrue, unsure(convertBooleanTrueCase), unsure(convertBooleanFalseCase));
1048
1049 m_out.appendTo(convertBooleanTrueCase, convertBooleanFalseCase);
1050 ValueFromBlock convertedTrue = m_out.anchor(m_out.constDouble(1));
1051 m_out.jump(continuation);
1052
1053 m_out.appendTo(convertBooleanFalseCase, continuation);
1054
1055 LValue valueIsNotBooleanFalse = m_out.notEqual(value, m_out.constInt64(ValueFalse));
1056 FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), ~SpecCell, valueIsNotBooleanFalse);
1057 ValueFromBlock convertedFalse = m_out.anchor(m_out.constDouble(0));
1058 m_out.jump(continuation);
1059
1060 m_out.appendTo(continuation, lastNext);
1061 setDouble(m_out.phi(m_out.doubleType, intToDouble, unboxedDouble, convertedUndefined, convertedNull, convertedTrue, convertedFalse));
1062 return;
1063 }
1064 m_out.appendTo(nonDoubleCase, continuation);
1065 FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), SpecBytecodeNumber, m_out.booleanTrue);
1066 m_out.unreachable();
1067
1068 m_out.appendTo(continuation, lastNext);
1069
1070 setDouble(m_out.phi(m_out.doubleType, intToDouble, unboxedDouble));
1071 return;
1072 }
1073
1074 case Int52RepUse: {
1075 setDouble(strictInt52ToDouble(lowStrictInt52(m_node->child1())));
1076 return;
1077 }
1078
1079 default:
1080 DFG_CRASH(m_graph, m_node, "Bad use kind");
1081 }
1082 }
1083
1084 void compileDoubleAsInt32()
1085 {
1086 LValue integerValue = convertDoubleToInt32(lowDouble(m_node->child1()), shouldCheckNegativeZero(m_node->arithMode()));
1087 setInt32(integerValue);
1088 }
1089
1090 void compileValueRep()
1091 {
1092 switch (m_node->child1().useKind()) {
1093 case DoubleRepUse: {
1094 LValue value = lowDouble(m_node->child1());
1095
1096 if (m_interpreter.needsTypeCheck(m_node->child1(), ~SpecDoubleImpureNaN)) {
1097 value = m_out.select(
1098 m_out.doubleEqual(value, value), value, m_out.constDouble(PNaN));
1099 }
1100
1101 setJSValue(boxDouble(value));
1102 return;
1103 }
1104
1105 case Int52RepUse: {
1106 setJSValue(strictInt52ToJSValue(lowStrictInt52(m_node->child1())));
1107 return;
1108 }
1109
1110 default:
1111 DFG_CRASH(m_graph, m_node, "Bad use kind");
1112 }
1113 }
1114
1115 void compileInt52Rep()
1116 {
1117 switch (m_node->child1().useKind()) {
1118 case Int32Use:
1119 setStrictInt52(m_out.signExt(lowInt32(m_node->child1()), m_out.int64));
1120 return;
1121
1122 case MachineIntUse:
1123 setStrictInt52(
1124 jsValueToStrictInt52(
1125 m_node->child1(), lowJSValue(m_node->child1(), ManualOperandSpeculation)));
1126 return;
1127
1128 case DoubleRepMachineIntUse:
1129 setStrictInt52(
1130 doubleToStrictInt52(
1131 m_node->child1(), lowDouble(m_node->child1())));
1132 return;
1133
1134 default:
1135 RELEASE_ASSERT_NOT_REACHED();
1136 }
1137 }
1138
1139 void compileValueToInt32()
1140 {
1141 switch (m_node->child1().useKind()) {
1142 case Int52RepUse:
1143 setInt32(m_out.castToInt32(lowStrictInt52(m_node->child1())));
1144 break;
1145
1146 case DoubleRepUse:
1147 setInt32(doubleToInt32(lowDouble(m_node->child1())));
1148 break;
1149
1150 case NumberUse:
1151 case NotCellUse: {
1152 LoweredNodeValue value = m_int32Values.get(m_node->child1().node());
1153 if (isValid(value)) {
1154 setInt32(value.value());
1155 break;
1156 }
1157
1158 value = m_jsValueValues.get(m_node->child1().node());
1159 if (isValid(value)) {
1160 setInt32(numberOrNotCellToInt32(m_node->child1(), value.value()));
1161 break;
1162 }
1163
1164 // We'll basically just get here for constants. But it's good to have this
1165 // catch-all since we often add new representations into the mix.
1166 setInt32(
1167 numberOrNotCellToInt32(
1168 m_node->child1(),
1169 lowJSValue(m_node->child1(), ManualOperandSpeculation)));
1170 break;
1171 }
1172
1173 default:
1174 DFG_CRASH(m_graph, m_node, "Bad use kind");
1175 break;
1176 }
1177 }
1178
1179 void compileBooleanToNumber()
1180 {
1181 switch (m_node->child1().useKind()) {
1182 case BooleanUse: {
1183 setInt32(m_out.zeroExt(lowBoolean(m_node->child1()), m_out.int32));
1184 return;
1185 }
1186
1187 case UntypedUse: {
1188 LValue value = lowJSValue(m_node->child1());
1189
1190 if (!m_interpreter.needsTypeCheck(m_node->child1(), SpecBoolInt32 | SpecBoolean)) {
1191 setInt32(m_out.bitAnd(m_out.castToInt32(value), m_out.int32One));
1192 return;
1193 }
1194
1195 LBasicBlock booleanCase = FTL_NEW_BLOCK(m_out, ("BooleanToNumber boolean case"));
1196 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("BooleanToNumber continuation"));
1197
1198 ValueFromBlock notBooleanResult = m_out.anchor(value);
1199 m_out.branch(
1200 isBoolean(value, provenType(m_node->child1())),
1201 unsure(booleanCase), unsure(continuation));
1202
1203 LBasicBlock lastNext = m_out.appendTo(booleanCase, continuation);
1204 ValueFromBlock booleanResult = m_out.anchor(m_out.bitOr(
1205 m_out.zeroExt(unboxBoolean(value), m_out.int64), m_tagTypeNumber));
1206 m_out.jump(continuation);
1207
1208 m_out.appendTo(continuation, lastNext);
1209 setJSValue(m_out.phi(m_out.int64, booleanResult, notBooleanResult));
1210 return;
1211 }
1212
1213 default:
1214 RELEASE_ASSERT_NOT_REACHED();
1215 return;
1216 }
1217 }
1218
1219 void compileExtractOSREntryLocal()
1220 {
1221 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(
1222 m_ftlState.jitCode->ftlForOSREntry()->entryBuffer()->dataBuffer());
1223 setJSValue(m_out.load64(m_out.absolute(buffer + m_node->unlinkedLocal().toLocal())));
1224 }
1225
1226 void compileGetStack()
1227 {
1228 // GetLocals arise only for captured variables and arguments. For arguments, we might have
1229 // already loaded it.
1230 if (LValue value = m_loadedArgumentValues.get(m_node)) {
1231 setJSValue(value);
1232 return;
1233 }
1234
1235 StackAccessData* data = m_node->stackAccessData();
1236 AbstractValue& value = m_state.variables().operand(data->local);
1237
1238 DFG_ASSERT(m_graph, m_node, isConcrete(data->format));
1239 DFG_ASSERT(m_graph, m_node, data->format != FlushedDouble); // This just happens to not arise for GetStacks, right now. It would be trivial to support.
1240
1241 if (isInt32Speculation(value.m_type))
1242 setInt32(m_out.load32(payloadFor(data->machineLocal)));
1243 else
1244 setJSValue(m_out.load64(addressFor(data->machineLocal)));
1245 }
1246
1247 void compilePutStack()
1248 {
1249 StackAccessData* data = m_node->stackAccessData();
1250 switch (data->format) {
1251 case FlushedJSValue: {
1252 LValue value = lowJSValue(m_node->child1());
1253 m_out.store64(value, addressFor(data->machineLocal));
1254 break;
1255 }
1256
1257 case FlushedDouble: {
1258 LValue value = lowDouble(m_node->child1());
1259 m_out.storeDouble(value, addressFor(data->machineLocal));
1260 break;
1261 }
1262
1263 case FlushedInt32: {
1264 LValue value = lowInt32(m_node->child1());
1265 m_out.store32(value, payloadFor(data->machineLocal));
1266 break;
1267 }
1268
1269 case FlushedInt52: {
1270 LValue value = lowInt52(m_node->child1());
1271 m_out.store64(value, addressFor(data->machineLocal));
1272 break;
1273 }
1274
1275 case FlushedCell: {
1276 LValue value = lowCell(m_node->child1());
1277 m_out.store64(value, addressFor(data->machineLocal));
1278 break;
1279 }
1280
1281 case FlushedBoolean: {
1282 speculateBoolean(m_node->child1());
1283 m_out.store64(
1284 lowJSValue(m_node->child1(), ManualOperandSpeculation),
1285 addressFor(data->machineLocal));
1286 break;
1287 }
1288
1289 default:
1290 DFG_CRASH(m_graph, m_node, "Bad flush format");
1291 break;
1292 }
1293 }
1294
1295 void compileNoOp()
1296 {
1297 DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, speculate);
1298 }
1299
1300 void compileToThis()
1301 {
1302 LValue value = lowJSValue(m_node->child1());
1303
1304 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("ToThis is cell case"));
1305 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ToThis slow case"));
1306 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToThis continuation"));
1307
1308 m_out.branch(
1309 isCell(value, provenType(m_node->child1())), usually(isCellCase), rarely(slowCase));
1310
1311 LBasicBlock lastNext = m_out.appendTo(isCellCase, slowCase);
1312 ValueFromBlock fastResult = m_out.anchor(value);
1313 m_out.branch(isType(value, FinalObjectType), usually(continuation), rarely(slowCase));
1314
1315 m_out.appendTo(slowCase, continuation);
1316 J_JITOperation_EJ function;
1317 if (m_graph.isStrictModeFor(m_node->origin.semantic))
1318 function = operationToThisStrict;
1319 else
1320 function = operationToThis;
1321 ValueFromBlock slowResult = m_out.anchor(
1322 vmCall(m_out.operation(function), m_callFrame, value));
1323 m_out.jump(continuation);
1324
1325 m_out.appendTo(continuation, lastNext);
1326 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
1327 }
1328
1329 void compileValueAdd()
1330 {
1331 J_JITOperation_EJJ operation;
1332 if (!(provenType(m_node->child1()) & SpecFullNumber)
1333 && !(provenType(m_node->child2()) & SpecFullNumber))
1334 operation = operationValueAddNotNumber;
1335 else
1336 operation = operationValueAdd;
1337 setJSValue(vmCall(
1338 m_out.operation(operation), m_callFrame,
1339 lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));
1340 }
1341
1342 void compileArithAddOrSub()
1343 {
1344 bool isSub = m_node->op() == ArithSub;
1345 switch (m_node->binaryUseKind()) {
1346 case Int32Use: {
1347 LValue left = lowInt32(m_node->child1());
1348 LValue right = lowInt32(m_node->child2());
1349
1350 if (!shouldCheckOverflow(m_node->arithMode())) {
1351 setInt32(isSub ? m_out.sub(left, right) : m_out.add(left, right));
1352 break;
1353 }
1354
1355 LValue result;
1356 if (!isSub) {
1357 result = m_out.addWithOverflow32(left, right);
1358
1359 if (doesKill(m_node->child2())) {
1360 addAvailableRecovery(
1361 m_node->child2(), SubRecovery,
1362 m_out.extractValue(result, 0), left, ValueFormatInt32);
1363 } else if (doesKill(m_node->child1())) {
1364 addAvailableRecovery(
1365 m_node->child1(), SubRecovery,
1366 m_out.extractValue(result, 0), right, ValueFormatInt32);
1367 }
1368 } else {
1369 result = m_out.subWithOverflow32(left, right);
1370
1371 if (doesKill(m_node->child2())) {
1372 // result = left - right
1373 // result - left = -right
1374 // right = left - result
1375 addAvailableRecovery(
1376 m_node->child2(), SubRecovery,
1377 left, m_out.extractValue(result, 0), ValueFormatInt32);
1378 } else if (doesKill(m_node->child1())) {
1379 // result = left - right
1380 // result + right = left
1381 addAvailableRecovery(
1382 m_node->child1(), AddRecovery,
1383 m_out.extractValue(result, 0), right, ValueFormatInt32);
1384 }
1385 }
1386
1387 speculate(Overflow, noValue(), 0, m_out.extractValue(result, 1));
1388 setInt32(m_out.extractValue(result, 0));
1389 break;
1390 }
1391
1392 case Int52RepUse: {
1393 if (!abstractValue(m_node->child1()).couldBeType(SpecInt52)
1394 && !abstractValue(m_node->child2()).couldBeType(SpecInt52)) {
1395 Int52Kind kind;
1396 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1397 LValue right = lowInt52(m_node->child2(), kind);
1398 setInt52(isSub ? m_out.sub(left, right) : m_out.add(left, right), kind);
1399 break;
1400 }
1401
1402 LValue left = lowInt52(m_node->child1());
1403 LValue right = lowInt52(m_node->child2());
1404
1405 LValue result;
1406 if (!isSub) {
1407 result = m_out.addWithOverflow64(left, right);
1408
1409 if (doesKill(m_node->child2())) {
1410 addAvailableRecovery(
1411 m_node->child2(), SubRecovery,
1412 m_out.extractValue(result, 0), left, ValueFormatInt52);
1413 } else if (doesKill(m_node->child1())) {
1414 addAvailableRecovery(
1415 m_node->child1(), SubRecovery,
1416 m_out.extractValue(result, 0), right, ValueFormatInt52);
1417 }
1418 } else {
1419 result = m_out.subWithOverflow64(left, right);
1420
1421 if (doesKill(m_node->child2())) {
1422 // result = left - right
1423 // result - left = -right
1424 // right = left - result
1425 addAvailableRecovery(
1426 m_node->child2(), SubRecovery,
1427 left, m_out.extractValue(result, 0), ValueFormatInt52);
1428 } else if (doesKill(m_node->child1())) {
1429 // result = left - right
1430 // result + right = left
1431 addAvailableRecovery(
1432 m_node->child1(), AddRecovery,
1433 m_out.extractValue(result, 0), right, ValueFormatInt52);
1434 }
1435 }
1436
1437 speculate(Int52Overflow, noValue(), 0, m_out.extractValue(result, 1));
1438 setInt52(m_out.extractValue(result, 0));
1439 break;
1440 }
1441
1442 case DoubleRepUse: {
1443 LValue C1 = lowDouble(m_node->child1());
1444 LValue C2 = lowDouble(m_node->child2());
1445
1446 setDouble(isSub ? m_out.doubleSub(C1, C2) : m_out.doubleAdd(C1, C2));
1447 break;
1448 }
1449
1450 default:
1451 DFG_CRASH(m_graph, m_node, "Bad use kind");
1452 break;
1453 }
1454 }
1455
1456 void compileArithClz32()
1457 {
1458 LValue operand = lowInt32(m_node->child1());
1459 LValue isZeroUndef = m_out.booleanFalse;
1460 setInt32(m_out.ctlz32(operand, isZeroUndef));
1461 }
1462
1463 void compileArithMul()
1464 {
1465 switch (m_node->binaryUseKind()) {
1466 case Int32Use: {
1467 LValue left = lowInt32(m_node->child1());
1468 LValue right = lowInt32(m_node->child2());
1469
1470 LValue result;
1471
1472 if (!shouldCheckOverflow(m_node->arithMode()))
1473 result = m_out.mul(left, right);
1474 else {
1475 LValue overflowResult = m_out.mulWithOverflow32(left, right);
1476 speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1477 result = m_out.extractValue(overflowResult, 0);
1478 }
1479
1480 if (shouldCheckNegativeZero(m_node->arithMode())) {
1481 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
1482 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation"));
1483
1484 m_out.branch(
1485 m_out.notZero32(result), usually(continuation), rarely(slowCase));
1486
1487 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
1488 LValue cond = m_out.bitOr(m_out.lessThan(left, m_out.int32Zero), m_out.lessThan(right, m_out.int32Zero));
1489 speculate(NegativeZero, noValue(), 0, cond);
1490 m_out.jump(continuation);
1491 m_out.appendTo(continuation, lastNext);
1492 }
1493
1494 setInt32(result);
1495 break;
1496 }
1497
1498 case Int52RepUse: {
1499 Int52Kind kind;
1500 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1501 LValue right = lowInt52(m_node->child2(), opposite(kind));
1502
1503 LValue overflowResult = m_out.mulWithOverflow64(left, right);
1504 speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1505 LValue result = m_out.extractValue(overflowResult, 0);
1506
1507 if (shouldCheckNegativeZero(m_node->arithMode())) {
1508 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
1509 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation"));
1510
1511 m_out.branch(
1512 m_out.notZero64(result), usually(continuation), rarely(slowCase));
1513
1514 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
1515 LValue cond = m_out.bitOr(m_out.lessThan(left, m_out.int64Zero), m_out.lessThan(right, m_out.int64Zero));
1516 speculate(NegativeZero, noValue(), 0, cond);
1517 m_out.jump(continuation);
1518 m_out.appendTo(continuation, lastNext);
1519 }
1520
1521 setInt52(result);
1522 break;
1523 }
1524
1525 case DoubleRepUse: {
1526 setDouble(
1527 m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1528 break;
1529 }
1530
1531 default:
1532 DFG_CRASH(m_graph, m_node, "Bad use kind");
1533 break;
1534 }
1535 }
1536
1537 void compileArithDiv()
1538 {
1539 switch (m_node->binaryUseKind()) {
1540 case Int32Use: {
1541 LValue numerator = lowInt32(m_node->child1());
1542 LValue denominator = lowInt32(m_node->child2());
1543
1544 LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithDiv unsafe denominator"));
1545 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithDiv continuation"));
1546 LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithDiv done"));
1547
1548 Vector<ValueFromBlock, 3> results;
1549
1550 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
1551
1552 m_out.branch(
1553 m_out.above(adjustedDenominator, m_out.int32One),
1554 usually(continuation), rarely(unsafeDenominator));
1555
1556 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
1557
1558 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
1559
1560 if (shouldCheckOverflow(m_node->arithMode())) {
1561 LValue cond = m_out.bitOr(m_out.isZero32(denominator), m_out.equal(numerator, neg2ToThe31));
1562 speculate(Overflow, noValue(), 0, cond);
1563 m_out.jump(continuation);
1564 } else {
1565 // This is the case where we convert the result to an int after we're done. So,
1566 // if the denominator is zero, then the result should be zero.
1567 // If the denominator is not zero (i.e. it's -1 because we're guarded by the
1568 // check above) and the numerator is -2^31 then the result should be -2^31.
1569
1570 LBasicBlock divByZero = FTL_NEW_BLOCK(m_out, ("ArithDiv divide by zero"));
1571 LBasicBlock notDivByZero = FTL_NEW_BLOCK(m_out, ("ArithDiv not divide by zero"));
1572 LBasicBlock neg2ToThe31ByNeg1 = FTL_NEW_BLOCK(m_out, ("ArithDiv -2^31/-1"));
1573
1574 m_out.branch(
1575 m_out.isZero32(denominator), rarely(divByZero), usually(notDivByZero));
1576
1577 m_out.appendTo(divByZero, notDivByZero);
1578 results.append(m_out.anchor(m_out.int32Zero));
1579 m_out.jump(done);
1580
1581 m_out.appendTo(notDivByZero, neg2ToThe31ByNeg1);
1582 m_out.branch(
1583 m_out.equal(numerator, neg2ToThe31),
1584 rarely(neg2ToThe31ByNeg1), usually(continuation));
1585
1586 m_out.appendTo(neg2ToThe31ByNeg1, continuation);
1587 results.append(m_out.anchor(neg2ToThe31));
1588 m_out.jump(done);
1589 }
1590
1591 m_out.appendTo(continuation, done);
1592
1593 if (shouldCheckNegativeZero(m_node->arithMode())) {
1594 LBasicBlock zeroNumerator = FTL_NEW_BLOCK(m_out, ("ArithDiv zero numerator"));
1595 LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithDiv numerator continuation"));
1596
1597 m_out.branch(
1598 m_out.isZero32(numerator),
1599 rarely(zeroNumerator), usually(numeratorContinuation));
1600
1601 LBasicBlock innerLastNext = m_out.appendTo(zeroNumerator, numeratorContinuation);
1602
1603 speculate(
1604 NegativeZero, noValue(), 0, m_out.lessThan(denominator, m_out.int32Zero));
1605
1606 m_out.jump(numeratorContinuation);
1607
1608 m_out.appendTo(numeratorContinuation, innerLastNext);
1609 }
1610
1611 LValue result = m_out.div(numerator, denominator);
1612
1613 if (shouldCheckOverflow(m_node->arithMode())) {
1614 speculate(
1615 Overflow, noValue(), 0,
1616 m_out.notEqual(m_out.mul(result, denominator), numerator));
1617 }
1618
1619 results.append(m_out.anchor(result));
1620 m_out.jump(done);
1621
1622 m_out.appendTo(done, lastNext);
1623
1624 setInt32(m_out.phi(m_out.int32, results));
1625 break;
1626 }
1627
1628 case DoubleRepUse: {
1629 setDouble(m_out.doubleDiv(
1630 lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1631 break;
1632 }
1633
1634 default:
1635 DFG_CRASH(m_graph, m_node, "Bad use kind");
1636 break;
1637 }
1638 }
1639
1640 void compileArithMod()
1641 {
1642 switch (m_node->binaryUseKind()) {
1643 case Int32Use: {
1644 LValue numerator = lowInt32(m_node->child1());
1645 LValue denominator = lowInt32(m_node->child2());
1646
1647 LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithMod unsafe denominator"));
1648 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMod continuation"));
1649 LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithMod done"));
1650
1651 Vector<ValueFromBlock, 3> results;
1652
1653 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
1654
1655 m_out.branch(
1656 m_out.above(adjustedDenominator, m_out.int32One),
1657 usually(continuation), rarely(unsafeDenominator));
1658
1659 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
1660
1661 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
1662
1663 // FIXME: -2^31 / -1 will actually yield negative zero, so we could have a
1664 // separate case for that. But it probably doesn't matter so much.
1665 if (shouldCheckOverflow(m_node->arithMode())) {
1666 LValue cond = m_out.bitOr(m_out.isZero32(denominator), m_out.equal(numerator, neg2ToThe31));
1667 speculate(Overflow, noValue(), 0, cond);
1668 m_out.jump(continuation);
1669 } else {
1670 // This is the case where we convert the result to an int after we're done. So,
1671 // if the denominator is zero, then the result should be result should be zero.
1672 // If the denominator is not zero (i.e. it's -1 because we're guarded by the
1673 // check above) and the numerator is -2^31 then the result should be -2^31.
1674
1675 LBasicBlock modByZero = FTL_NEW_BLOCK(m_out, ("ArithMod modulo by zero"));
1676 LBasicBlock notModByZero = FTL_NEW_BLOCK(m_out, ("ArithMod not modulo by zero"));
1677 LBasicBlock neg2ToThe31ByNeg1 = FTL_NEW_BLOCK(m_out, ("ArithMod -2^31/-1"));
1678
1679 m_out.branch(
1680 m_out.isZero32(denominator), rarely(modByZero), usually(notModByZero));
1681
1682 m_out.appendTo(modByZero, notModByZero);
1683 results.append(m_out.anchor(m_out.int32Zero));
1684 m_out.jump(done);
1685
1686 m_out.appendTo(notModByZero, neg2ToThe31ByNeg1);
1687 m_out.branch(
1688 m_out.equal(numerator, neg2ToThe31),
1689 rarely(neg2ToThe31ByNeg1), usually(continuation));
1690
1691 m_out.appendTo(neg2ToThe31ByNeg1, continuation);
1692 results.append(m_out.anchor(m_out.int32Zero));
1693 m_out.jump(done);
1694 }
1695
1696 m_out.appendTo(continuation, done);
1697
1698 LValue remainder = m_out.rem(numerator, denominator);
1699
1700 if (shouldCheckNegativeZero(m_node->arithMode())) {
1701 LBasicBlock negativeNumerator = FTL_NEW_BLOCK(m_out, ("ArithMod negative numerator"));
1702 LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithMod numerator continuation"));
1703
1704 m_out.branch(
1705 m_out.lessThan(numerator, m_out.int32Zero),
1706 unsure(negativeNumerator), unsure(numeratorContinuation));
1707
1708 LBasicBlock innerLastNext = m_out.appendTo(negativeNumerator, numeratorContinuation);
1709
1710 speculate(NegativeZero, noValue(), 0, m_out.isZero32(remainder));
1711
1712 m_out.jump(numeratorContinuation);
1713
1714 m_out.appendTo(numeratorContinuation, innerLastNext);
1715 }
1716
1717 results.append(m_out.anchor(remainder));
1718 m_out.jump(done);
1719
1720 m_out.appendTo(done, lastNext);
1721
1722 setInt32(m_out.phi(m_out.int32, results));
1723 break;
1724 }
1725
1726 case DoubleRepUse: {
1727 setDouble(
1728 m_out.doubleRem(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1729 break;
1730 }
1731
1732 default:
1733 DFG_CRASH(m_graph, m_node, "Bad use kind");
1734 break;
1735 }
1736 }
1737
1738 void compileArithMinOrMax()
1739 {
1740 switch (m_node->binaryUseKind()) {
1741 case Int32Use: {
1742 LValue left = lowInt32(m_node->child1());
1743 LValue right = lowInt32(m_node->child2());
1744
1745 setInt32(
1746 m_out.select(
1747 m_node->op() == ArithMin
1748 ? m_out.lessThan(left, right)
1749 : m_out.lessThan(right, left),
1750 left, right));
1751 break;
1752 }
1753
1754 case DoubleRepUse: {
1755 LValue left = lowDouble(m_node->child1());
1756 LValue right = lowDouble(m_node->child2());
1757
1758 LBasicBlock notLessThan = FTL_NEW_BLOCK(m_out, ("ArithMin/ArithMax not less than"));
1759 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMin/ArithMax continuation"));
1760
1761 Vector<ValueFromBlock, 2> results;
1762
1763 results.append(m_out.anchor(left));
1764 m_out.branch(
1765 m_node->op() == ArithMin
1766 ? m_out.doubleLessThan(left, right)
1767 : m_out.doubleGreaterThan(left, right),
1768 unsure(continuation), unsure(notLessThan));
1769
1770 LBasicBlock lastNext = m_out.appendTo(notLessThan, continuation);
1771 results.append(m_out.anchor(m_out.select(
1772 m_node->op() == ArithMin
1773 ? m_out.doubleGreaterThanOrEqual(left, right)
1774 : m_out.doubleLessThanOrEqual(left, right),
1775 right, m_out.constDouble(PNaN))));
1776 m_out.jump(continuation);
1777
1778 m_out.appendTo(continuation, lastNext);
1779 setDouble(m_out.phi(m_out.doubleType, results));
1780 break;
1781 }
1782
1783 default:
1784 DFG_CRASH(m_graph, m_node, "Bad use kind");
1785 break;
1786 }
1787 }
1788
1789 void compileArithAbs()
1790 {
1791 switch (m_node->child1().useKind()) {
1792 case Int32Use: {
1793 LValue value = lowInt32(m_node->child1());
1794
1795 LValue mask = m_out.aShr(value, m_out.constInt32(31));
1796 LValue result = m_out.bitXor(mask, m_out.add(mask, value));
1797
1798 speculate(Overflow, noValue(), 0, m_out.equal(result, m_out.constInt32(1 << 31)));
1799
1800 setInt32(result);
1801 break;
1802 }
1803
1804 case DoubleRepUse: {
1805 setDouble(m_out.doubleAbs(lowDouble(m_node->child1())));
1806 break;
1807 }
1808
1809 default:
1810 DFG_CRASH(m_graph, m_node, "Bad use kind");
1811 break;
1812 }
1813 }
1814
1815 void compileArithSin() { setDouble(m_out.doubleSin(lowDouble(m_node->child1()))); }
1816
1817 void compileArithCos() { setDouble(m_out.doubleCos(lowDouble(m_node->child1()))); }
1818
1819 void compileArithPow()
1820 {
1821 // FIXME: investigate llvm.powi to better understand its performance characteristics.
1822 // It might be better to have the inline loop in DFG too.
1823 if (m_node->child2().useKind() == Int32Use)
1824 setDouble(m_out.doublePowi(lowDouble(m_node->child1()), lowInt32(m_node->child2())));
1825 else {
1826 LValue base = lowDouble(m_node->child1());
1827 LValue exponent = lowDouble(m_node->child2());
1828
1829 LBasicBlock integerExponentIsSmallBlock = FTL_NEW_BLOCK(m_out, ("ArithPow test integer exponent is small."));
1830 LBasicBlock integerExponentPowBlock = FTL_NEW_BLOCK(m_out, ("ArithPow pow(double, (int)double)."));
1831 LBasicBlock doubleExponentPowBlockEntry = FTL_NEW_BLOCK(m_out, ("ArithPow pow(double, double)."));
1832 LBasicBlock nanExceptionExponentIsInfinity = FTL_NEW_BLOCK(m_out, ("ArithPow NaN Exception, check exponent is infinity."));
1833 LBasicBlock nanExceptionBaseIsOne = FTL_NEW_BLOCK(m_out, ("ArithPow NaN Exception, check base is one."));
1834 LBasicBlock powBlock = FTL_NEW_BLOCK(m_out, ("ArithPow regular pow"));
1835 LBasicBlock nanExceptionResultIsNaN = FTL_NEW_BLOCK(m_out, ("ArithPow NaN Exception, result is NaN."));
1836 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithPow continuation"));
1837
1838 LValue integerExponent = m_out.fpToInt32(exponent);
1839 LValue integerExponentConvertedToDouble = m_out.intToDouble(integerExponent);
1840 LValue exponentIsInteger = m_out.doubleEqual(exponent, integerExponentConvertedToDouble);
1841 m_out.branch(exponentIsInteger, unsure(integerExponentIsSmallBlock), unsure(doubleExponentPowBlockEntry));
1842
1843 LBasicBlock lastNext = m_out.appendTo(integerExponentIsSmallBlock, integerExponentPowBlock);
1844 LValue integerExponentBelow1000 = m_out.below(integerExponent, m_out.constInt32(1000));
1845 m_out.branch(integerExponentBelow1000, usually(integerExponentPowBlock), rarely(doubleExponentPowBlockEntry));
1846
1847 m_out.appendTo(integerExponentPowBlock, doubleExponentPowBlockEntry);
1848 ValueFromBlock powDoubleIntResult = m_out.anchor(m_out.doublePowi(base, integerExponent));
1849 m_out.jump(continuation);
1850
1851 // If y is NaN, the result is NaN.
1852 m_out.appendTo(doubleExponentPowBlockEntry, nanExceptionExponentIsInfinity);
1853 LValue exponentIsNaN;
1854 if (provenType(m_node->child2()) & SpecDoubleNaN)
1855 exponentIsNaN = m_out.doubleNotEqualOrUnordered(exponent, exponent);
1856 else
1857 exponentIsNaN = m_out.booleanFalse;
1858 m_out.branch(exponentIsNaN, rarely(nanExceptionResultIsNaN), usually(nanExceptionExponentIsInfinity));
1859
1860 // If abs(x) is 1 and y is +infinity, the result is NaN.
1861 // If abs(x) is 1 and y is -infinity, the result is NaN.
1862 m_out.appendTo(nanExceptionExponentIsInfinity, nanExceptionBaseIsOne);
1863 LValue absoluteExponent = m_out.doubleAbs(exponent);
1864 LValue absoluteExponentIsInfinity = m_out.doubleEqual(absoluteExponent, m_out.constDouble(std::numeric_limits<double>::infinity()));
1865 m_out.branch(absoluteExponentIsInfinity, rarely(nanExceptionBaseIsOne), usually(powBlock));
1866
1867 m_out.appendTo(nanExceptionBaseIsOne, powBlock);
1868 LValue absoluteBase = m_out.doubleAbs(base);
1869 LValue absoluteBaseIsOne = m_out.doubleEqual(absoluteBase, m_out.constDouble(1));
1870 m_out.branch(absoluteBaseIsOne, unsure(nanExceptionResultIsNaN), unsure(powBlock));
1871
1872 m_out.appendTo(powBlock, nanExceptionResultIsNaN);
1873 ValueFromBlock powResult = m_out.anchor(m_out.doublePow(base, exponent));
1874 m_out.jump(continuation);
1875
1876 m_out.appendTo(nanExceptionResultIsNaN, continuation);
1877 ValueFromBlock pureNan = m_out.anchor(m_out.constDouble(PNaN));
1878 m_out.jump(continuation);
1879
1880 m_out.appendTo(continuation, lastNext);
1881 setDouble(m_out.phi(m_out.doubleType, powDoubleIntResult, powResult, pureNan));
1882 }
1883 }
1884
1885 void compileArithRound()
1886 {
1887 LBasicBlock realPartIsMoreThanHalf = FTL_NEW_BLOCK(m_out, ("ArithRound should round down"));
1888 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithRound continuation"));
1889
1890 LValue value = lowDouble(m_node->child1());
1891 LValue integerValue = m_out.ceil64(value);
1892 ValueFromBlock integerValueResult = m_out.anchor(integerValue);
1893
1894 LValue realPart = m_out.doubleSub(integerValue, value);
1895
1896 m_out.branch(m_out.doubleGreaterThanOrUnordered(realPart, m_out.constDouble(0.5)), unsure(realPartIsMoreThanHalf), unsure(continuation));
1897
1898 LBasicBlock lastNext = m_out.appendTo(realPartIsMoreThanHalf, continuation);
1899 LValue integerValueRoundedDown = m_out.doubleSub(integerValue, m_out.constDouble(1));
1900 ValueFromBlock integerValueRoundedDownResult = m_out.anchor(integerValueRoundedDown);
1901 m_out.jump(continuation);
1902 m_out.appendTo(continuation, lastNext);
1903
1904 LValue result = m_out.phi(m_out.doubleType, integerValueResult, integerValueRoundedDownResult);
1905
1906 if (producesInteger(m_node->arithRoundingMode())) {
1907 LValue integerValue = convertDoubleToInt32(result, shouldCheckNegativeZero(m_node->arithRoundingMode()));
1908 setInt32(integerValue);
1909 } else
1910 setDouble(result);
1911 }
1912
1913 void compileArithSqrt() { setDouble(m_out.doubleSqrt(lowDouble(m_node->child1()))); }
1914
1915 void compileArithLog() { setDouble(m_out.doubleLog(lowDouble(m_node->child1()))); }
1916
1917 void compileArithFRound()
1918 {
1919 LValue floatValue = m_out.fpCast(lowDouble(m_node->child1()), m_out.floatType);
1920 setDouble(m_out.fpCast(floatValue, m_out.doubleType));
1921 }
1922
1923 void compileArithNegate()
1924 {
1925 switch (m_node->child1().useKind()) {
1926 case Int32Use: {
1927 LValue value = lowInt32(m_node->child1());
1928
1929 LValue result;
1930 if (!shouldCheckOverflow(m_node->arithMode()))
1931 result = m_out.neg(value);
1932 else if (!shouldCheckNegativeZero(m_node->arithMode())) {
1933 // We don't have a negate-with-overflow intrinsic. Hopefully this
1934 // does the trick, though.
1935 LValue overflowResult = m_out.subWithOverflow32(m_out.int32Zero, value);
1936 speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1937 result = m_out.extractValue(overflowResult, 0);
1938 } else {
1939 speculate(Overflow, noValue(), 0, m_out.testIsZero32(value, m_out.constInt32(0x7fffffff)));
1940 result = m_out.neg(value);
1941 }
1942
1943 setInt32(result);
1944 break;
1945 }
1946
1947 case Int52RepUse: {
1948 if (!abstractValue(m_node->child1()).couldBeType(SpecInt52)) {
1949 Int52Kind kind;
1950 LValue value = lowWhicheverInt52(m_node->child1(), kind);
1951 LValue result = m_out.neg(value);
1952 if (shouldCheckNegativeZero(m_node->arithMode()))
1953 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
1954 setInt52(result, kind);
1955 break;
1956 }
1957
1958 LValue value = lowInt52(m_node->child1());
1959 LValue overflowResult = m_out.subWithOverflow64(m_out.int64Zero, value);
1960 speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1961 LValue result = m_out.extractValue(overflowResult, 0);
1962 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
1963 setInt52(result);
1964 break;
1965 }
1966
1967 case DoubleRepUse: {
1968 setDouble(m_out.doubleNeg(lowDouble(m_node->child1())));
1969 break;
1970 }
1971
1972 default:
1973 DFG_CRASH(m_graph, m_node, "Bad use kind");
1974 break;
1975 }
1976 }
1977
1978 void compileBitAnd()
1979 {
1980 setInt32(m_out.bitAnd(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1981 }
1982
1983 void compileBitOr()
1984 {
1985 setInt32(m_out.bitOr(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1986 }
1987
1988 void compileBitXor()
1989 {
1990 setInt32(m_out.bitXor(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1991 }
1992
1993 void compileBitRShift()
1994 {
1995 setInt32(m_out.aShr(
1996 lowInt32(m_node->child1()),
1997 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
1998 }
1999
2000 void compileBitLShift()
2001 {
2002 setInt32(m_out.shl(
2003 lowInt32(m_node->child1()),
2004 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2005 }
2006
2007 void compileBitURShift()
2008 {
2009 setInt32(m_out.lShr(
2010 lowInt32(m_node->child1()),
2011 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2012 }
2013
2014 void compileUInt32ToNumber()
2015 {
2016 LValue value = lowInt32(m_node->child1());
2017
2018 if (doesOverflow(m_node->arithMode())) {
2019 setDouble(m_out.unsignedToDouble(value));
2020 return;
2021 }
2022
2023 speculate(Overflow, noValue(), 0, m_out.lessThan(value, m_out.int32Zero));
2024 setInt32(value);
2025 }
2026
2027 void compileCheckStructure()
2028 {
2029 LValue cell = lowCell(m_node->child1());
2030
2031 ExitKind exitKind;
2032 if (m_node->child1()->hasConstant())
2033 exitKind = BadConstantCache;
2034 else
2035 exitKind = BadCache;
2036
2037 LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
2038
2039 checkStructure(
2040 structureID, jsValueValue(cell), exitKind, m_node->structureSet(),
2041 [this] (Structure* structure) {
2042 return weakStructureID(structure);
2043 });
2044 }
2045
2046 void compileCheckCell()
2047 {
2048 LValue cell = lowCell(m_node->child1());
2049
2050 speculate(
2051 BadCell, jsValueValue(cell), m_node->child1().node(),
2052 m_out.notEqual(cell, weakPointer(m_node->cellOperand()->cell())));
2053 }
2054
2055 void compileCheckBadCell()
2056 {
2057 terminate(BadCell);
2058 }
2059
2060 void compileCheckNotEmpty()
2061 {
2062 speculate(TDZFailure, noValue(), nullptr, m_out.isZero64(lowJSValue(m_node->child1())));
2063 }
2064
2065 void compileGetExecutable()
2066 {
2067 LValue cell = lowCell(m_node->child1());
2068 speculateFunction(m_node->child1(), cell);
2069 setJSValue(m_out.loadPtr(cell, m_heaps.JSFunction_executable));
2070 }
2071
2072 void compileArrayifyToStructure()
2073 {
2074 LValue cell = lowCell(m_node->child1());
2075 LValue property = !!m_node->child2() ? lowInt32(m_node->child2()) : 0;
2076
2077 LBasicBlock unexpectedStructure = FTL_NEW_BLOCK(m_out, ("ArrayifyToStructure unexpected structure"));
2078 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArrayifyToStructure continuation"));
2079
2080 LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
2081
2082 m_out.branch(
2083 m_out.notEqual(structureID, weakStructureID(m_node->structure())),
2084 rarely(unexpectedStructure), usually(continuation));
2085
2086 LBasicBlock lastNext = m_out.appendTo(unexpectedStructure, continuation);
2087
2088 if (property) {
2089 switch (m_node->arrayMode().type()) {
2090 case Array::Int32:
2091 case Array::Double:
2092 case Array::Contiguous:
2093 speculate(
2094 Uncountable, noValue(), 0,
2095 m_out.aboveOrEqual(property, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)));
2096 break;
2097 default:
2098 break;
2099 }
2100 }
2101
2102 switch (m_node->arrayMode().type()) {
2103 case Array::Int32:
2104 vmCall(m_out.operation(operationEnsureInt32), m_callFrame, cell);
2105 break;
2106 case Array::Double:
2107 vmCall(m_out.operation(operationEnsureDouble), m_callFrame, cell);
2108 break;
2109 case Array::Contiguous:
2110 vmCall(m_out.operation(operationEnsureContiguous), m_callFrame, cell);
2111 break;
2112 case Array::ArrayStorage:
2113 case Array::SlowPutArrayStorage:
2114 vmCall(m_out.operation(operationEnsureArrayStorage), m_callFrame, cell);
2115 break;
2116 default:
2117 DFG_CRASH(m_graph, m_node, "Bad array type");
2118 break;
2119 }
2120
2121 structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
2122 speculate(
2123 BadIndexingType, jsValueValue(cell), 0,
2124 m_out.notEqual(structureID, weakStructureID(m_node->structure())));
2125 m_out.jump(continuation);
2126
2127 m_out.appendTo(continuation, lastNext);
2128 }
2129
2130 void compilePutStructure()
2131 {
2132 m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node);
2133
2134 Structure* oldStructure = m_node->transition()->previous;
2135 Structure* newStructure = m_node->transition()->next;
2136 ASSERT_UNUSED(oldStructure, oldStructure->indexingType() == newStructure->indexingType());
2137 ASSERT(oldStructure->typeInfo().inlineTypeFlags() == newStructure->typeInfo().inlineTypeFlags());
2138 ASSERT(oldStructure->typeInfo().type() == newStructure->typeInfo().type());
2139
2140 LValue cell = lowCell(m_node->child1());
2141 m_out.store32(
2142 weakStructureID(newStructure),
2143 cell, m_heaps.JSCell_structureID);
2144 }
2145
2146 void compileGetById()
2147 {
2148 // Pretty much the only reason why we don't also support GetByIdFlush is because:
2149 // https://bugs.webkit.org/show_bug.cgi?id=125711
2150
2151 switch (m_node->child1().useKind()) {
2152 case CellUse: {
2153 setJSValue(getById(lowCell(m_node->child1())));
2154 return;
2155 }
2156
2157 case UntypedUse: {
2158 // This is pretty weird, since we duplicate the slow path both here and in the
2159 // code generated by the IC. We should investigate making this less bad.
2160 // https://bugs.webkit.org/show_bug.cgi?id=127830
2161 LValue value = lowJSValue(m_node->child1());
2162
2163 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("GetById untyped cell case"));
2164 LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("GetById untyped not cell case"));
2165 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetById untyped continuation"));
2166
2167 m_out.branch(
2168 isCell(value, provenType(m_node->child1())), unsure(cellCase), unsure(notCellCase));
2169
2170 LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase);
2171 ValueFromBlock cellResult = m_out.anchor(getById(value));
2172 m_out.jump(continuation);
2173
2174 m_out.appendTo(notCellCase, continuation);
2175 ValueFromBlock notCellResult = m_out.anchor(vmCall(
2176 m_out.operation(operationGetByIdGeneric),
2177 m_callFrame, value,
2178 m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()])));
2179 m_out.jump(continuation);
2180
2181 m_out.appendTo(continuation, lastNext);
2182 setJSValue(m_out.phi(m_out.int64, cellResult, notCellResult));
2183 return;
2184 }
2185
2186 default:
2187 DFG_CRASH(m_graph, m_node, "Bad use kind");
2188 return;
2189 }
2190 }
2191
2192 void compilePutById()
2193 {
2194 // See above; CellUse is easier so we do only that for now.
2195 ASSERT(m_node->child1().useKind() == CellUse);
2196
2197 LValue base = lowCell(m_node->child1());
2198 LValue value = lowJSValue(m_node->child2());
2199 auto uid = m_graph.identifiers()[m_node->identifierNumber()];
2200
2201 // Arguments: id, bytes, target, numArgs, args...
2202 unsigned stackmapID = m_stackmapIDs++;
2203
2204 if (verboseCompilationEnabled())
2205 dataLog(" Emitting PutById patchpoint with stackmap #", stackmapID, "\n");
2206
2207 LValue call = m_out.call(
2208 m_out.patchpointVoidIntrinsic(),
2209 m_out.constInt64(stackmapID), m_out.constInt32(sizeOfPutById()),
2210 constNull(m_out.ref8), m_out.constInt32(2), base, value);
2211 setInstructionCallingConvention(call, LLVMAnyRegCallConv);
2212
2213 m_ftlState.putByIds.append(PutByIdDescriptor(
2214 stackmapID, m_node->origin.semantic, uid,
2215 m_graph.executableFor(m_node->origin.semantic)->ecmaMode(),
2216 m_node->op() == PutByIdDirect ? Direct : NotDirect));
2217 }
2218
2219 void compileGetButterfly()
2220 {
2221 setStorage(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSObject_butterfly));
2222 }
2223
2224 void compileConstantStoragePointer()
2225 {
2226 setStorage(m_out.constIntPtr(m_node->storagePointer()));
2227 }
2228
2229 void compileGetIndexedPropertyStorage()
2230 {
2231 LValue cell = lowCell(m_node->child1());
2232
2233 if (m_node->arrayMode().type() == Array::String) {
2234 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("GetIndexedPropertyStorage String slow case"));
2235 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetIndexedPropertyStorage String continuation"));
2236
2237 ValueFromBlock fastResult = m_out.anchor(
2238 m_out.loadPtr(cell, m_heaps.JSString_value));
2239
2240 m_out.branch(
2241 m_out.notNull(fastResult.value()), usually(continuation), rarely(slowPath));
2242
2243 LBasicBlock lastNext = m_out.appendTo(slowPath, continuation);
2244
2245 ValueFromBlock slowResult = m_out.anchor(
2246 vmCall(m_out.operation(operationResolveRope), m_callFrame, cell));
2247
2248 m_out.jump(continuation);
2249
2250 m_out.appendTo(continuation, lastNext);
2251
2252 setStorage(m_out.loadPtr(m_out.phi(m_out.intPtr, fastResult, slowResult), m_heaps.StringImpl_data));
2253 return;
2254 }
2255
2256 setStorage(m_out.loadPtr(cell, m_heaps.JSArrayBufferView_vector));
2257 }
2258
2259 void compileCheckArray()
2260 {
2261 Edge edge = m_node->child1();
2262 LValue cell = lowCell(edge);
2263
2264 if (m_node->arrayMode().alreadyChecked(m_graph, m_node, abstractValue(edge)))
2265 return;
2266
2267 speculate(
2268 BadIndexingType, jsValueValue(cell), 0,
2269 m_out.bitNot(isArrayType(cell, m_node->arrayMode())));
2270 }
2271
2272 void compileGetTypedArrayByteOffset()
2273 {
2274 LValue basePtr = lowCell(m_node->child1());
2275
2276 LBasicBlock simpleCase = FTL_NEW_BLOCK(m_out, ("wasteless typed array"));
2277 LBasicBlock wastefulCase = FTL_NEW_BLOCK(m_out, ("wasteful typed array"));
2278 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("continuation branch"));
2279
2280 LValue mode = m_out.load32(basePtr, m_heaps.JSArrayBufferView_mode);
2281 m_out.branch(
2282 m_out.notEqual(mode, m_out.constInt32(WastefulTypedArray)),
2283 unsure(simpleCase), unsure(wastefulCase));
2284
2285 // begin simple case
2286 LBasicBlock lastNext = m_out.appendTo(simpleCase, wastefulCase);
2287
2288 ValueFromBlock simpleOut = m_out.anchor(m_out.constIntPtr(0));
2289
2290 m_out.jump(continuation);
2291
2292 // begin wasteful case
2293 m_out.appendTo(wastefulCase, continuation);
2294
2295 LValue vectorPtr = m_out.loadPtr(basePtr, m_heaps.JSArrayBufferView_vector);
2296 LValue butterflyPtr = m_out.loadPtr(basePtr, m_heaps.JSObject_butterfly);
2297 LValue arrayBufferPtr = m_out.loadPtr(butterflyPtr, m_heaps.Butterfly_arrayBuffer);
2298 LValue dataPtr = m_out.loadPtr(arrayBufferPtr, m_heaps.ArrayBuffer_data);
2299
2300 ValueFromBlock wastefulOut = m_out.anchor(m_out.sub(vectorPtr, dataPtr));
2301
2302 m_out.jump(continuation);
2303 m_out.appendTo(continuation, lastNext);
2304
2305 // output
2306 setInt32(m_out.castToInt32(m_out.phi(m_out.intPtr, simpleOut, wastefulOut)));
2307 }
2308
2309 void compileGetArrayLength()
2310 {
2311 switch (m_node->arrayMode().type()) {
2312 case Array::Int32:
2313 case Array::Double:
2314 case Array::Contiguous: {
2315 setInt32(m_out.load32NonNegative(lowStorage(m_node->child2()), m_heaps.Butterfly_publicLength));
2316 return;
2317 }
2318
2319 case Array::String: {
2320 LValue string = lowCell(m_node->child1());
2321 setInt32(m_out.load32NonNegative(string, m_heaps.JSString_length));
2322 return;
2323 }
2324
2325 case Array::DirectArguments: {
2326 LValue arguments = lowCell(m_node->child1());
2327 speculate(
2328 ExoticObjectMode, noValue(), nullptr,
2329 m_out.notNull(m_out.loadPtr(arguments, m_heaps.DirectArguments_overrides)));
2330 setInt32(m_out.load32NonNegative(arguments, m_heaps.DirectArguments_length));
2331 return;
2332 }
2333
2334 case Array::ScopedArguments: {
2335 LValue arguments = lowCell(m_node->child1());
2336 speculate(
2337 ExoticObjectMode, noValue(), nullptr,
2338 m_out.notZero8(m_out.load8(arguments, m_heaps.ScopedArguments_overrodeThings)));
2339 setInt32(m_out.load32NonNegative(arguments, m_heaps.ScopedArguments_totalLength));
2340 return;
2341 }
2342
2343 default:
2344 if (isTypedView(m_node->arrayMode().typedArrayType())) {
2345 setInt32(
2346 m_out.load32NonNegative(lowCell(m_node->child1()), m_heaps.JSArrayBufferView_length));
2347 return;
2348 }
2349
2350 DFG_CRASH(m_graph, m_node, "Bad array type");
2351 return;
2352 }
2353 }
2354
2355 void compileCheckInBounds()
2356 {
2357 speculate(
2358 OutOfBounds, noValue(), 0,
2359 m_out.aboveOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
2360 }
2361
2362 void compileGetByVal()
2363 {
2364 switch (m_node->arrayMode().type()) {
2365 case Array::Int32:
2366 case Array::Contiguous: {
2367 LValue index = lowInt32(m_node->child2());
2368 LValue storage = lowStorage(m_node->child3());
2369
2370 IndexedAbstractHeap& heap = m_node->arrayMode().type() == Array::Int32 ?
2371 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties;
2372
2373 if (m_node->arrayMode().isInBounds()) {
2374 LValue result = m_out.load64(baseIndex(heap, storage, index, m_node->child2()));
2375 LValue isHole = m_out.isZero64(result);
2376 if (m_node->arrayMode().isSaneChain()) {
2377 DFG_ASSERT(
2378 m_graph, m_node, m_node->arrayMode().type() == Array::Contiguous);
2379 result = m_out.select(
2380 isHole, m_out.constInt64(JSValue::encode(jsUndefined())), result);
2381 } else
2382 speculate(LoadFromHole, noValue(), 0, isHole);
2383 setJSValue(result);
2384 return;
2385 }
2386
2387 LValue base = lowCell(m_node->child1());
2388
2389 LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous fast case"));
2390 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous slow case"));
2391 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous continuation"));
2392
2393 m_out.branch(
2394 m_out.aboveOrEqual(
2395 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
2396 rarely(slowCase), usually(fastCase));
2397
2398 LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
2399
2400 ValueFromBlock fastResult = m_out.anchor(
2401 m_out.load64(baseIndex(heap, storage, index, m_node->child2())));
2402 m_out.branch(
2403 m_out.isZero64(fastResult.value()), rarely(slowCase), usually(continuation));
2404
2405 m_out.appendTo(slowCase, continuation);
2406 ValueFromBlock slowResult = m_out.anchor(
2407 vmCall(m_out.operation(operationGetByValArrayInt), m_callFrame, base, index));
2408 m_out.jump(continuation);
2409
2410 m_out.appendTo(continuation, lastNext);
2411 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
2412 return;
2413 }
2414
2415 case Array::Double: {
2416 LValue index = lowInt32(m_node->child2());
2417 LValue storage = lowStorage(m_node->child3());
2418
2419 IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties;
2420
2421 if (m_node->arrayMode().isInBounds()) {
2422 LValue result = m_out.loadDouble(
2423 baseIndex(heap, storage, index, m_node->child2()));
2424
2425 if (!m_node->arrayMode().isSaneChain()) {
2426 speculate(
2427 LoadFromHole, noValue(), 0,
2428 m_out.doubleNotEqualOrUnordered(result, result));
2429 }
2430 setDouble(result);
2431 break;
2432 }
2433
2434 LValue base = lowCell(m_node->child1());
2435
2436 LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetByVal double in bounds"));
2437 LBasicBlock boxPath = FTL_NEW_BLOCK(m_out, ("GetByVal double boxing"));
2438 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetByVal double slow case"));
2439 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal double continuation"));
2440
2441 m_out.branch(
2442 m_out.aboveOrEqual(
2443 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
2444 rarely(slowCase), usually(inBounds));
2445
2446 LBasicBlock lastNext = m_out.appendTo(inBounds, boxPath);
2447 LValue doubleValue = m_out.loadDouble(
2448 baseIndex(heap, storage, index, m_node->child2()));
2449 m_out.branch(
2450 m_out.doubleNotEqualOrUnordered(doubleValue, doubleValue),
2451 rarely(slowCase), usually(boxPath));
2452
2453 m_out.appendTo(boxPath, slowCase);
2454 ValueFromBlock fastResult = m_out.anchor(boxDouble(doubleValue));
2455 m_out.jump(continuation);
2456
2457 m_out.appendTo(slowCase, continuation);
2458 ValueFromBlock slowResult = m_out.anchor(
2459 vmCall(m_out.operation(operationGetByValArrayInt), m_callFrame, base, index));
2460 m_out.jump(continuation);
2461
2462 m_out.appendTo(continuation, lastNext);
2463 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
2464 return;
2465 }
2466
2467 case Array::DirectArguments: {
2468 LValue base = lowCell(m_node->child1());
2469 LValue index = lowInt32(m_node->child2());
2470
2471 speculate(
2472 ExoticObjectMode, noValue(), nullptr,
2473 m_out.notNull(m_out.loadPtr(base, m_heaps.DirectArguments_overrides)));
2474 speculate(
2475 ExoticObjectMode, noValue(), nullptr,
2476 m_out.aboveOrEqual(
2477 index,
2478 m_out.load32NonNegative(base, m_heaps.DirectArguments_length)));
2479
2480 TypedPointer address = m_out.baseIndex(
2481 m_heaps.DirectArguments_storage, base, m_out.zeroExtPtr(index));
2482 setJSValue(m_out.load64(address));
2483 return;
2484 }
2485
2486 case Array::ScopedArguments: {
2487 LValue base = lowCell(m_node->child1());
2488 LValue index = lowInt32(m_node->child2());
2489
2490 speculate(
2491 ExoticObjectMode, noValue(), nullptr,
2492 m_out.aboveOrEqual(
2493 index,
2494 m_out.load32NonNegative(base, m_heaps.ScopedArguments_totalLength)));
2495
2496 LValue table = m_out.loadPtr(base, m_heaps.ScopedArguments_table);
2497 LValue namedLength = m_out.load32(table, m_heaps.ScopedArgumentsTable_length);
2498
2499 LBasicBlock namedCase = FTL_NEW_BLOCK(m_out, ("GetByVal ScopedArguments named case"));
2500 LBasicBlock overflowCase = FTL_NEW_BLOCK(m_out, ("GetByVal ScopedArguments overflow case"));
2501 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal ScopedArguments continuation"));
2502
2503 m_out.branch(
2504 m_out.aboveOrEqual(index, namedLength), unsure(overflowCase), unsure(namedCase));
2505
2506 LBasicBlock lastNext = m_out.appendTo(namedCase, overflowCase);
2507
2508 LValue scope = m_out.loadPtr(base, m_heaps.ScopedArguments_scope);
2509 LValue arguments = m_out.loadPtr(table, m_heaps.ScopedArgumentsTable_arguments);
2510
2511 TypedPointer address = m_out.baseIndex(
2512 m_heaps.scopedArgumentsTableArguments, arguments, m_out.zeroExtPtr(index));
2513 LValue scopeOffset = m_out.load32(address);
2514
2515 speculate(
2516 ExoticObjectMode, noValue(), nullptr,
2517 m_out.equal(scopeOffset, m_out.constInt32(ScopeOffset::invalidOffset)));
2518
2519 address = m_out.baseIndex(
2520 m_heaps.JSEnvironmentRecord_variables, scope, m_out.zeroExtPtr(scopeOffset));
2521 ValueFromBlock namedResult = m_out.anchor(m_out.load64(address));
2522 m_out.jump(continuation);
2523
2524 m_out.appendTo(overflowCase, continuation);
2525
2526 address = m_out.baseIndex(
2527 m_heaps.ScopedArguments_overflowStorage, base,
2528 m_out.zeroExtPtr(m_out.sub(index, namedLength)));
2529 LValue overflowValue = m_out.load64(address);
2530 speculate(ExoticObjectMode, noValue(), nullptr, m_out.isZero64(overflowValue));
2531 ValueFromBlock overflowResult = m_out.anchor(overflowValue);
2532 m_out.jump(continuation);
2533
2534 m_out.appendTo(continuation, lastNext);
2535 setJSValue(m_out.phi(m_out.int64, namedResult, overflowResult));
2536 return;
2537 }
2538
2539 case Array::Generic: {
2540 setJSValue(vmCall(
2541 m_out.operation(operationGetByVal), m_callFrame,
2542 lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));
2543 return;
2544 }
2545
2546 case Array::String: {
2547 compileStringCharAt();
2548 return;
2549 }
2550
2551 default: {
2552 LValue index = lowInt32(m_node->child2());
2553 LValue storage = lowStorage(m_node->child3());
2554
2555 TypedArrayType type = m_node->arrayMode().typedArrayType();
2556
2557 if (isTypedView(type)) {
2558 TypedPointer pointer = TypedPointer(
2559 m_heaps.typedArrayProperties,
2560 m_out.add(
2561 storage,
2562 m_out.shl(
2563 m_out.zeroExtPtr(index),
2564 m_out.constIntPtr(logElementSize(type)))));
2565
2566 if (isInt(type)) {
2567 LValue result;
2568 switch (elementSize(type)) {
2569 case 1:
2570 result = m_out.load8(pointer);
2571 break;
2572 case 2:
2573 result = m_out.load16(pointer);
2574 break;
2575 case 4:
2576 result = m_out.load32(pointer);
2577 break;
2578 default:
2579 DFG_CRASH(m_graph, m_node, "Bad element size");
2580 }
2581
2582 if (elementSize(type) < 4) {
2583 if (isSigned(type))
2584 result = m_out.signExt(result, m_out.int32);
2585 else
2586 result = m_out.zeroExt(result, m_out.int32);
2587 setInt32(result);
2588 return;
2589 }
2590
2591 if (isSigned(type)) {
2592 setInt32(result);
2593 return;
2594 }
2595
2596 if (m_node->shouldSpeculateInt32()) {
2597 speculate(
2598 Overflow, noValue(), 0, m_out.lessThan(result, m_out.int32Zero));
2599 setInt32(result);
2600 return;
2601 }
2602
2603 if (m_node->shouldSpeculateMachineInt()) {
2604 setStrictInt52(m_out.zeroExt(result, m_out.int64));
2605 return;
2606 }
2607
2608 setDouble(m_out.unsignedToFP(result, m_out.doubleType));
2609 return;
2610 }
2611
2612 ASSERT(isFloat(type));
2613
2614 LValue result;
2615 switch (type) {
2616 case TypeFloat32:
2617 result = m_out.fpCast(m_out.loadFloat(pointer), m_out.doubleType);
2618 break;
2619 case TypeFloat64:
2620 result = m_out.loadDouble(pointer);
2621 break;
2622 default:
2623 DFG_CRASH(m_graph, m_node, "Bad typed array type");
2624 }
2625
2626 setDouble(result);
2627 return;
2628 }
2629
2630 DFG_CRASH(m_graph, m_node, "Bad array type");
2631 return;
2632 } }
2633 }
2634
2635 void compileGetMyArgumentByVal()
2636 {
2637 InlineCallFrame* inlineCallFrame = m_node->child1()->origin.semantic.inlineCallFrame;
2638
2639 LValue index = lowInt32(m_node->child2());
2640
2641 LValue limit;
2642 if (inlineCallFrame && !inlineCallFrame->isVarargs())
2643 limit = m_out.constInt32(inlineCallFrame->arguments.size() - 1);
2644 else {
2645 VirtualRegister argumentCountRegister;
2646 if (!inlineCallFrame)
2647 argumentCountRegister = VirtualRegister(JSStack::ArgumentCount);
2648 else
2649 argumentCountRegister = inlineCallFrame->argumentCountRegister;
2650 limit = m_out.sub(m_out.load32(payloadFor(argumentCountRegister)), m_out.int32One);
2651 }
2652
2653 speculate(ExoticObjectMode, noValue(), 0, m_out.aboveOrEqual(index, limit));
2654
2655 TypedPointer base;
2656 if (inlineCallFrame) {
2657 if (inlineCallFrame->arguments.size() <= 1) {
2658 // We should have already exited due to the bounds check, above. Just tell the
2659 // compiler that anything dominated by this instruction is not reachable, so
2660 // that we don't waste time generating such code. This will also plant some
2661 // kind of crashing instruction so that if by some fluke the bounds check didn't
2662 // work, we'll crash in an easy-to-see way.
2663 didAlreadyTerminate();
2664 return;
2665 }
2666 base = addressFor(inlineCallFrame->arguments[1].virtualRegister());
2667 } else
2668 base = addressFor(virtualRegisterForArgument(1));
2669
2670 LValue pointer = m_out.baseIndex(
2671 base.value(), m_out.zeroExt(index, m_out.intPtr), ScaleEight);
2672 setJSValue(m_out.load64(TypedPointer(m_heaps.variables.atAnyIndex(), pointer)));
2673 }
2674
2675 void compilePutByVal()
2676 {
2677 Edge child1 = m_graph.varArgChild(m_node, 0);
2678 Edge child2 = m_graph.varArgChild(m_node, 1);
2679 Edge child3 = m_graph.varArgChild(m_node, 2);
2680 Edge child4 = m_graph.varArgChild(m_node, 3);
2681 Edge child5 = m_graph.varArgChild(m_node, 4);
2682
2683 switch (m_node->arrayMode().type()) {
2684 case Array::Generic: {
2685 V_JITOperation_EJJJ operation;
2686 if (m_node->op() == PutByValDirect) {
2687 if (m_graph.isStrictModeFor(m_node->origin.semantic))
2688 operation = operationPutByValDirectStrict;
2689 else
2690 operation = operationPutByValDirectNonStrict;
2691 } else {
2692 if (m_graph.isStrictModeFor(m_node->origin.semantic))
2693 operation = operationPutByValStrict;
2694 else
2695 operation = operationPutByValNonStrict;
2696 }
2697
2698 vmCall(
2699 m_out.operation(operation), m_callFrame,
2700 lowJSValue(child1), lowJSValue(child2), lowJSValue(child3));
2701 return;
2702 }
2703
2704 default:
2705 break;
2706 }
2707
2708 LValue base = lowCell(child1);
2709 LValue index = lowInt32(child2);
2710 LValue storage = lowStorage(child4);
2711
2712 switch (m_node->arrayMode().type()) {
2713 case Array::Int32:
2714 case Array::Double:
2715 case Array::Contiguous: {
2716 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal continuation"));
2717 LBasicBlock outerLastNext = m_out.appendTo(m_out.m_block, continuation);
2718
2719 switch (m_node->arrayMode().type()) {
2720 case Array::Int32:
2721 case Array::Contiguous: {
2722 LValue value = lowJSValue(child3, ManualOperandSpeculation);
2723
2724 if (m_node->arrayMode().type() == Array::Int32)
2725 FTL_TYPE_CHECK(jsValueValue(value), child3, SpecInt32, isNotInt32(value));
2726
2727 TypedPointer elementPointer = m_out.baseIndex(
2728 m_node->arrayMode().type() == Array::Int32 ?
2729 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties,
2730 storage, m_out.zeroExtPtr(index), provenValue(child2));
2731
2732 if (m_node->op() == PutByValAlias) {
2733 m_out.store64(value, elementPointer);
2734 break;
2735 }
2736
2737 contiguousPutByValOutOfBounds(
2738 codeBlock()->isStrictMode()
2739 ? operationPutByValBeyondArrayBoundsStrict
2740 : operationPutByValBeyondArrayBoundsNonStrict,
2741 base, storage, index, value, continuation);
2742
2743 m_out.store64(value, elementPointer);
2744 break;
2745 }
2746
2747 case Array::Double: {
2748 LValue value = lowDouble(child3);
2749
2750 FTL_TYPE_CHECK(
2751 doubleValue(value), child3, SpecDoubleReal,
2752 m_out.doubleNotEqualOrUnordered(value, value));
2753
2754 TypedPointer elementPointer = m_out.baseIndex(
2755 m_heaps.indexedDoubleProperties, storage, m_out.zeroExtPtr(index),
2756 provenValue(child2));
2757
2758 if (m_node->op() == PutByValAlias) {
2759 m_out.storeDouble(value, elementPointer);
2760 break;
2761 }
2762
2763 contiguousPutByValOutOfBounds(
2764 codeBlock()->isStrictMode()
2765 ? operationPutDoubleByValBeyondArrayBoundsStrict
2766 : operationPutDoubleByValBeyondArrayBoundsNonStrict,
2767 base, storage, index, value, continuation);
2768
2769 m_out.storeDouble(value, elementPointer);
2770 break;
2771 }
2772
2773 default:
2774 DFG_CRASH(m_graph, m_node, "Bad array type");
2775 }
2776
2777 m_out.jump(continuation);
2778 m_out.appendTo(continuation, outerLastNext);
2779 return;
2780 }
2781
2782 default:
2783 TypedArrayType type = m_node->arrayMode().typedArrayType();
2784
2785 if (isTypedView(type)) {
2786 TypedPointer pointer = TypedPointer(
2787 m_heaps.typedArrayProperties,
2788 m_out.add(
2789 storage,
2790 m_out.shl(
2791 m_out.zeroExt(index, m_out.intPtr),
2792 m_out.constIntPtr(logElementSize(type)))));
2793
2794 LType refType;
2795 LValue valueToStore;
2796
2797 if (isInt(type)) {
2798 LValue intValue;
2799 switch (child3.useKind()) {
2800 case Int52RepUse:
2801 case Int32Use: {
2802 if (child3.useKind() == Int32Use)
2803 intValue = lowInt32(child3);
2804 else
2805 intValue = m_out.castToInt32(lowStrictInt52(child3));
2806
2807 if (isClamped(type)) {
2808 ASSERT(elementSize(type) == 1);
2809
2810 LBasicBlock atLeastZero = FTL_NEW_BLOCK(m_out, ("PutByVal int clamp atLeastZero"));
2811 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal int clamp continuation"));
2812
2813 Vector<ValueFromBlock, 2> intValues;
2814 intValues.append(m_out.anchor(m_out.int32Zero));
2815 m_out.branch(
2816 m_out.lessThan(intValue, m_out.int32Zero),
2817 unsure(continuation), unsure(atLeastZero));
2818
2819 LBasicBlock lastNext = m_out.appendTo(atLeastZero, continuation);
2820
2821 intValues.append(m_out.anchor(m_out.select(
2822 m_out.greaterThan(intValue, m_out.constInt32(255)),
2823 m_out.constInt32(255),
2824 intValue)));
2825 m_out.jump(continuation);
2826
2827 m_out.appendTo(continuation, lastNext);
2828 intValue = m_out.phi(m_out.int32, intValues);
2829 }
2830 break;
2831 }
2832
2833 case DoubleRepUse: {
2834 LValue doubleValue = lowDouble(child3);
2835
2836 if (isClamped(type)) {
2837 ASSERT(elementSize(type) == 1);
2838
2839 LBasicBlock atLeastZero = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp atLeastZero"));
2840 LBasicBlock withinRange = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp withinRange"));
2841 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp continuation"));
2842
2843 Vector<ValueFromBlock, 3> intValues;
2844 intValues.append(m_out.anchor(m_out.int32Zero));
2845 m_out.branch(
2846 m_out.doubleLessThanOrUnordered(doubleValue, m_out.doubleZero),
2847 unsure(continuation), unsure(atLeastZero));
2848
2849 LBasicBlock lastNext = m_out.appendTo(atLeastZero, withinRange);
2850 intValues.append(m_out.anchor(m_out.constInt32(255)));
2851 m_out.branch(
2852 m_out.doubleGreaterThan(doubleValue, m_out.constDouble(255)),
2853 unsure(continuation), unsure(withinRange));
2854
2855 m_out.appendTo(withinRange, continuation);
2856 intValues.append(m_out.anchor(m_out.fpToInt32(doubleValue)));
2857 m_out.jump(continuation);
2858
2859 m_out.appendTo(continuation, lastNext);
2860 intValue = m_out.phi(m_out.int32, intValues);
2861 } else
2862 intValue = doubleToInt32(doubleValue);
2863 break;
2864 }
2865
2866 default:
2867 DFG_CRASH(m_graph, m_node, "Bad use kind");
2868 }
2869
2870 switch (elementSize(type)) {
2871 case 1:
2872 valueToStore = m_out.intCast(intValue, m_out.int8);
2873 refType = m_out.ref8;
2874 break;
2875 case 2:
2876 valueToStore = m_out.intCast(intValue, m_out.int16);
2877 refType = m_out.ref16;
2878 break;
2879 case 4:
2880 valueToStore = intValue;
2881 refType = m_out.ref32;
2882 break;
2883 default:
2884 DFG_CRASH(m_graph, m_node, "Bad element size");
2885 }
2886 } else /* !isInt(type) */ {
2887 LValue value = lowDouble(child3);
2888 switch (type) {
2889 case TypeFloat32:
2890 valueToStore = m_out.fpCast(value, m_out.floatType);
2891 refType = m_out.refFloat;
2892 break;
2893 case TypeFloat64:
2894 valueToStore = value;
2895 refType = m_out.refDouble;
2896 break;
2897 default:
2898 DFG_CRASH(m_graph, m_node, "Bad typed array type");
2899 }
2900 }
2901
2902 if (m_node->arrayMode().isInBounds() || m_node->op() == PutByValAlias)
2903 m_out.store(valueToStore, pointer, refType);
2904 else {
2905 LBasicBlock isInBounds = FTL_NEW_BLOCK(m_out, ("PutByVal typed array in bounds case"));
2906 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal typed array continuation"));
2907
2908 m_out.branch(
2909 m_out.aboveOrEqual(index, lowInt32(child5)),
2910 unsure(continuation), unsure(isInBounds));
2911
2912 LBasicBlock lastNext = m_out.appendTo(isInBounds, continuation);
2913 m_out.store(valueToStore, pointer, refType);
2914 m_out.jump(continuation);
2915
2916 m_out.appendTo(continuation, lastNext);
2917 }
2918
2919 return;
2920 }
2921
2922 DFG_CRASH(m_graph, m_node, "Bad array type");
2923 break;
2924 }
2925 }
2926
2927 void compileArrayPush()
2928 {
2929 LValue base = lowCell(m_node->child1());
2930 LValue storage = lowStorage(m_node->child3());
2931
2932 switch (m_node->arrayMode().type()) {
2933 case Array::Int32:
2934 case Array::Contiguous:
2935 case Array::Double: {
2936 LValue value;
2937 LType refType;
2938
2939 if (m_node->arrayMode().type() != Array::Double) {
2940 value = lowJSValue(m_node->child2(), ManualOperandSpeculation);
2941 if (m_node->arrayMode().type() == Array::Int32) {
2942 FTL_TYPE_CHECK(
2943 jsValueValue(value), m_node->child2(), SpecInt32, isNotInt32(value));
2944 }
2945 refType = m_out.ref64;
2946 } else {
2947 value = lowDouble(m_node->child2());
2948 FTL_TYPE_CHECK(
2949 doubleValue(value), m_node->child2(), SpecDoubleReal,
2950 m_out.doubleNotEqualOrUnordered(value, value));
2951 refType = m_out.refDouble;
2952 }
2953
2954 IndexedAbstractHeap& heap = m_heaps.forArrayType(m_node->arrayMode().type());
2955
2956 LValue prevLength = m_out.load32(storage, m_heaps.Butterfly_publicLength);
2957
2958 LBasicBlock fastPath = FTL_NEW_BLOCK(m_out, ("ArrayPush fast path"));
2959 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("ArrayPush slow path"));
2960 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArrayPush continuation"));
2961
2962 m_out.branch(
2963 m_out.aboveOrEqual(
2964 prevLength, m_out.load32(storage, m_heaps.Butterfly_vectorLength)),
2965 rarely(slowPath), usually(fastPath));
2966
2967 LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
2968 m_out.store(
2969 value, m_out.baseIndex(heap, storage, m_out.zeroExtPtr(prevLength)), refType);
2970 LValue newLength = m_out.add(prevLength, m_out.int32One);
2971 m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength);
2972
2973 ValueFromBlock fastResult = m_out.anchor(boxInt32(newLength));
2974 m_out.jump(continuation);
2975
2976 m_out.appendTo(slowPath, continuation);
2977 LValue operation;
2978 if (m_node->arrayMode().type() != Array::Double)
2979 operation = m_out.operation(operationArrayPush);
2980 else
2981 operation = m_out.operation(operationArrayPushDouble);
2982 ValueFromBlock slowResult = m_out.anchor(
2983 vmCall(operation, m_callFrame, value, base));
2984 m_out.jump(continuation);
2985
2986 m_out.appendTo(continuation, lastNext);
2987 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
2988 return;
2989 }
2990
2991 default:
2992 DFG_CRASH(m_graph, m_node, "Bad array type");
2993 return;
2994 }
2995 }
2996
2997 void compileArrayPop()
2998 {
2999 LValue base = lowCell(m_node->child1());
3000 LValue storage = lowStorage(m_node->child2());
3001
3002 switch (m_node->arrayMode().type()) {
3003 case Array::Int32:
3004 case Array::Double:
3005 case Array::Contiguous: {
3006 IndexedAbstractHeap& heap = m_heaps.forArrayType(m_node->arrayMode().type());
3007
3008 LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("ArrayPop fast case"));
3009 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArrayPop slow case"));
3010 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArrayPop continuation"));
3011
3012 LValue prevLength = m_out.load32(storage, m_heaps.Butterfly_publicLength);
3013
3014 Vector<ValueFromBlock, 3> results;
3015 results.append(m_out.anchor(m_out.constInt64(JSValue::encode(jsUndefined()))));
3016 m_out.branch(
3017 m_out.isZero32(prevLength), rarely(continuation), usually(fastCase));
3018
3019 LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
3020 LValue newLength = m_out.sub(prevLength, m_out.int32One);
3021 m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength);
3022 TypedPointer pointer = m_out.baseIndex(heap, storage, m_out.zeroExtPtr(newLength));
3023 if (m_node->arrayMode().type() != Array::Double) {
3024 LValue result = m_out.load64(pointer);
3025 m_out.store64(m_out.int64Zero, pointer);
3026 results.append(m_out.anchor(result));
3027 m_out.branch(
3028 m_out.notZero64(result), usually(continuation), rarely(slowCase));
3029 } else {
3030 LValue result = m_out.loadDouble(pointer);
3031 m_out.store64(m_out.constInt64(bitwise_cast<int64_t>(PNaN)), pointer);
3032 results.append(m_out.anchor(boxDouble(result)));
3033 m_out.branch(
3034 m_out.doubleEqual(result, result),
3035 usually(continuation), rarely(slowCase));
3036 }
3037
3038 m_out.appendTo(slowCase, continuation);
3039 results.append(m_out.anchor(vmCall(
3040 m_out.operation(operationArrayPopAndRecoverLength), m_callFrame, base)));
3041 m_out.jump(continuation);
3042
3043 m_out.appendTo(continuation, lastNext);
3044 setJSValue(m_out.phi(m_out.int64, results));
3045 return;
3046 }
3047
3048 default:
3049 DFG_CRASH(m_graph, m_node, "Bad array type");
3050 return;
3051 }
3052 }
3053
3054 void compileCreateActivation()
3055 {
3056 LValue scope = lowCell(m_node->child1());
3057 SymbolTable* table = m_node->castOperand<SymbolTable*>();
3058 Structure* structure = m_graph.globalObjectFor(m_node->origin.semantic)->activationStructure();
3059
3060 if (table->singletonScope()->isStillValid()) {
3061 LValue callResult = vmCall(
3062 m_out.operation(operationCreateActivationDirect), m_callFrame, weakPointer(structure),
3063 scope, weakPointer(table));
3064 setJSValue(callResult);
3065 return;
3066 }
3067
3068 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("CreateActivation slow path"));
3069 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CreateActivation continuation"));
3070
3071 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
3072
3073 LValue fastObject = allocateObject<JSLexicalEnvironment>(
3074 JSLexicalEnvironment::allocationSize(table), structure, m_out.intPtrZero, slowPath);
3075
3076 // We don't need memory barriers since we just fast-created the activation, so the
3077 // activation must be young.
3078 m_out.storePtr(scope, fastObject, m_heaps.JSScope_next);
3079 m_out.storePtr(weakPointer(table), fastObject, m_heaps.JSSymbolTableObject_symbolTable);
3080
3081 for (unsigned i = 0; i < table->scopeSize(); ++i) {
3082 m_out.store64(
3083 m_out.constInt64(JSValue::encode(jsUndefined())),
3084 fastObject, m_heaps.JSEnvironmentRecord_variables[i]);
3085 }
3086
3087 ValueFromBlock fastResult = m_out.anchor(fastObject);
3088 m_out.jump(continuation);
3089
3090 m_out.appendTo(slowPath, continuation);
3091 LValue callResult = vmCall(
3092 m_out.operation(operationCreateActivationDirect), m_callFrame, weakPointer(structure),
3093 scope, weakPointer(table));
3094 ValueFromBlock slowResult = m_out.anchor(callResult);
3095 m_out.jump(continuation);
3096
3097 m_out.appendTo(continuation, lastNext);
3098 setJSValue(m_out.phi(m_out.intPtr, fastResult, slowResult));
3099 }
3100
3101 void compileNewFunction()
3102 {
3103 LValue scope = lowCell(m_node->child1());
3104 FunctionExecutable* executable = m_node->castOperand<FunctionExecutable*>();
3105 if (executable->singletonFunction()->isStillValid()) {
3106 LValue callResult = vmCall(
3107 m_out.operation(operationNewFunction), m_callFrame, scope, weakPointer(executable));
3108 setJSValue(callResult);
3109 return;
3110 }
3111
3112 Structure* structure = m_graph.globalObjectFor(m_node->origin.semantic)->functionStructure();
3113
3114 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("NewFunction slow path"));
3115 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NewFunction continuation"));
3116
3117 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
3118
3119 LValue fastObject = allocateObject<JSFunction>(
3120 structure, m_out.intPtrZero, slowPath);
3121
3122 // We don't need memory barriers since we just fast-created the function, so it
3123 // must be young.
3124 m_out.storePtr(scope, fastObject, m_heaps.JSFunction_scope);
3125 m_out.storePtr(weakPointer(executable), fastObject, m_heaps.JSFunction_executable);
3126 m_out.storePtr(m_out.intPtrZero, fastObject, m_heaps.JSFunction_rareData);
3127
3128 ValueFromBlock fastResult = m_out.anchor(fastObject);
3129 m_out.jump(continuation);
3130
3131 m_out.appendTo(slowPath, continuation);
3132 LValue callResult = vmCall(
3133 m_out.operation(operationNewFunctionWithInvalidatedReallocationWatchpoint),
3134 m_callFrame, scope, weakPointer(executable));
3135 ValueFromBlock slowResult = m_out.anchor(callResult);
3136 m_out.jump(continuation);
3137
3138 m_out.appendTo(continuation, lastNext);
3139 setJSValue(m_out.phi(m_out.intPtr, fastResult, slowResult));
3140 }
3141
3142 void compileCreateDirectArguments()
3143 {
3144 // FIXME: A more effective way of dealing with the argument count and callee is to have
3145 // them be explicit arguments to this node.
3146 // https://bugs.webkit.org/show_bug.cgi?id=142207
3147
3148 Structure* structure =
3149 m_graph.globalObjectFor(m_node->origin.semantic)->directArgumentsStructure();
3150
3151 unsigned minCapacity = m_graph.baselineCodeBlockFor(m_node->origin.semantic)->numParameters() - 1;
3152
3153 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("CreateDirectArguments slow path"));
3154 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CreateDirectArguments continuation"));
3155
3156 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
3157
3158 ArgumentsLength length = getArgumentsLength();
3159
3160 LValue fastObject;
3161 if (length.isKnown) {
3162 fastObject = allocateObject<DirectArguments>(
3163 DirectArguments::allocationSize(std::max(length.known, minCapacity)), structure,
3164 m_out.intPtrZero, slowPath);
3165 } else {
3166 LValue size = m_out.add(
3167 m_out.shl(length.value, m_out.constInt32(3)),
3168 m_out.constInt32(DirectArguments::storageOffset()));
3169
3170 size = m_out.select(
3171 m_out.aboveOrEqual(length.value, m_out.constInt32(minCapacity)),
3172 size, m_out.constInt32(DirectArguments::allocationSize(minCapacity)));
3173
3174 fastObject = allocateVariableSizedObject<DirectArguments>(
3175 size, structure, m_out.intPtrZero, slowPath);
3176 }
3177
3178 m_out.store32(length.value, fastObject, m_heaps.DirectArguments_length);
3179 m_out.store32(m_out.constInt32(minCapacity), fastObject, m_heaps.DirectArguments_minCapacity);
3180 m_out.storePtr(m_out.intPtrZero, fastObject, m_heaps.DirectArguments_overrides);
3181
3182 ValueFromBlock fastResult = m_out.anchor(fastObject);
3183 m_out.jump(continuation);
3184
3185 m_out.appendTo(slowPath, continuation);
3186 LValue callResult = vmCall(
3187 m_out.operation(operationCreateDirectArguments), m_callFrame, weakPointer(structure),
3188 length.value, m_out.constInt32(minCapacity));
3189 ValueFromBlock slowResult = m_out.anchor(callResult);
3190 m_out.jump(continuation);
3191
3192 m_out.appendTo(continuation, lastNext);
3193 LValue result = m_out.phi(m_out.intPtr, fastResult, slowResult);
3194
3195 m_out.storePtr(getCurrentCallee(), result, m_heaps.DirectArguments_callee);
3196
3197 if (length.isKnown) {
3198 VirtualRegister start = AssemblyHelpers::argumentsStart(m_node->origin.semantic);
3199 for (unsigned i = 0; i < std::max(length.known, minCapacity); ++i) {
3200 m_out.store64(
3201 m_out.load64(addressFor(start + i)),
3202 result, m_heaps.DirectArguments_storage[i]);
3203 }
3204 } else {
3205 LValue stackBase = getArgumentsStart();
3206
3207 LBasicBlock loop = FTL_NEW_BLOCK(m_out, ("CreateDirectArguments loop body"));
3208 LBasicBlock end = FTL_NEW_BLOCK(m_out, ("CreateDirectArguments loop end"));
3209
3210 ValueFromBlock originalLength;
3211 if (minCapacity) {
3212 LValue capacity = m_out.select(
3213 m_out.aboveOrEqual(length.value, m_out.constInt32(minCapacity)),
3214 length.value,
3215 m_out.constInt32(minCapacity));
3216 originalLength = m_out.anchor(m_out.zeroExtPtr(capacity));
3217 m_out.jump(loop);
3218 } else {
3219 originalLength = m_out.anchor(m_out.zeroExtPtr(length.value));
3220 m_out.branch(m_out.isNull(originalLength.value()), unsure(end), unsure(loop));
3221 }
3222
3223 lastNext = m_out.appendTo(loop, end);
3224 LValue previousIndex = m_out.phi(m_out.intPtr, originalLength);
3225 LValue index = m_out.sub(previousIndex, m_out.intPtrOne);
3226 m_out.store64(
3227 m_out.load64(m_out.baseIndex(m_heaps.variables, stackBase, index)),
3228 m_out.baseIndex(m_heaps.DirectArguments_storage, result, index));
3229 ValueFromBlock nextIndex = m_out.anchor(index);
3230 addIncoming(previousIndex, nextIndex);
3231 m_out.branch(m_out.isNull(index), unsure(end), unsure(loop));
3232
3233 m_out.appendTo(end, lastNext);
3234 }
3235
3236 setJSValue(result);
3237 }
3238
3239 void compileCreateScopedArguments()
3240 {
3241 LValue scope = lowCell(m_node->child1());
3242
3243 LValue result = vmCall(
3244 m_out.operation(operationCreateScopedArguments), m_callFrame,
3245 weakPointer(
3246 m_graph.globalObjectFor(m_node->origin.semantic)->scopedArgumentsStructure()),
3247 getArgumentsStart(), getArgumentsLength().value, getCurrentCallee(), scope);
3248
3249 setJSValue(result);
3250 }
3251
3252 void compileCreateClonedArguments()
3253 {
3254 LValue result = vmCall(
3255 m_out.operation(operationCreateClonedArguments), m_callFrame,
3256 weakPointer(
3257 m_graph.globalObjectFor(m_node->origin.semantic)->outOfBandArgumentsStructure()),
3258 getArgumentsStart(), getArgumentsLength().value, getCurrentCallee());
3259
3260 setJSValue(result);
3261 }
3262
3263 void compileNewObject()
3264 {
3265 setJSValue(allocateObject(m_node->structure()));
3266 }
3267
3268 void compileNewArray()
3269 {
3270 // First speculate appropriately on all of the children. Do this unconditionally up here
3271 // because some of the slow paths may otherwise forget to do it. It's sort of arguable
3272 // that doing the speculations up here might be unprofitable for RA - so we can consider
3273 // sinking this to below the allocation fast path if we find that this has a lot of
3274 // register pressure.
3275 for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex)
3276 speculate(m_graph.varArgChild(m_node, operandIndex));
3277
3278 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
3279 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(
3280 m_node->indexingType());
3281
3282 DFG_ASSERT(m_graph, m_node, structure->indexingType() == m_node->indexingType());
3283
3284 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) {
3285 unsigned numElements = m_node->numChildren();
3286
3287 ArrayValues arrayValues = allocateJSArray(structure, numElements);
3288
3289 for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex) {
3290 Edge edge = m_graph.varArgChild(m_node, operandIndex);
3291
3292 switch (m_node->indexingType()) {
3293 case ALL_BLANK_INDEXING_TYPES:
3294 case ALL_UNDECIDED_INDEXING_TYPES:
3295 DFG_CRASH(m_graph, m_node, "Bad indexing type");
3296 break;
3297
3298 case ALL_DOUBLE_INDEXING_TYPES:
3299 m_out.storeDouble(
3300 lowDouble(edge),
3301 arrayValues.butterfly, m_heaps.indexedDoubleProperties[operandIndex]);
3302 break;
3303
3304 case ALL_INT32_INDEXING_TYPES:
3305 case ALL_CONTIGUOUS_INDEXING_TYPES:
3306 m_out.store64(
3307 lowJSValue(edge, ManualOperandSpeculation),
3308 arrayValues.butterfly,
3309 m_heaps.forIndexingType(m_node->indexingType())->at(operandIndex));
3310 break;
3311
3312 default:
3313 DFG_CRASH(m_graph, m_node, "Corrupt indexing type");
3314 break;
3315 }
3316 }
3317
3318 setJSValue(arrayValues.array);
3319 return;
3320 }
3321
3322 if (!m_node->numChildren()) {
3323 setJSValue(vmCall(
3324 m_out.operation(operationNewEmptyArray), m_callFrame,
3325 m_out.constIntPtr(structure)));
3326 return;
3327 }
3328
3329 size_t scratchSize = sizeof(EncodedJSValue) * m_node->numChildren();
3330 ASSERT(scratchSize);
3331 ScratchBuffer* scratchBuffer = vm().scratchBufferForSize(scratchSize);
3332 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
3333
3334 for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex) {
3335 Edge edge = m_graph.varArgChild(m_node, operandIndex);
3336 m_out.store64(
3337 lowJSValue(edge, ManualOperandSpeculation),
3338 m_out.absolute(buffer + operandIndex));
3339 }
3340
3341 m_out.storePtr(
3342 m_out.constIntPtr(scratchSize), m_out.absolute(scratchBuffer->activeLengthPtr()));
3343
3344 LValue result = vmCall(
3345 m_out.operation(operationNewArray), m_callFrame,
3346 m_out.constIntPtr(structure), m_out.constIntPtr(buffer),
3347 m_out.constIntPtr(m_node->numChildren()));
3348
3349 m_out.storePtr(m_out.intPtrZero, m_out.absolute(scratchBuffer->activeLengthPtr()));
3350
3351 setJSValue(result);
3352 }
3353
3354 void compileNewArrayBuffer()
3355 {
3356 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
3357 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(
3358 m_node->indexingType());
3359
3360 DFG_ASSERT(m_graph, m_node, structure->indexingType() == m_node->indexingType());
3361
3362 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) {
3363 unsigned numElements = m_node->numConstants();
3364
3365 ArrayValues arrayValues = allocateJSArray(structure, numElements);
3366
3367 JSValue* data = codeBlock()->constantBuffer(m_node->startConstant());
3368 for (unsigned index = 0; index < m_node->numConstants(); ++index) {
3369 int64_t value;
3370 if (hasDouble(m_node->indexingType()))
3371 value = bitwise_cast<int64_t>(data[index].asNumber());
3372 else
3373 value = JSValue::encode(data[index]);
3374
3375 m_out.store64(
3376 m_out.constInt64(value),
3377 arrayValues.butterfly,
3378 m_heaps.forIndexingType(m_node->indexingType())->at(index));
3379 }
3380
3381 setJSValue(arrayValues.array);
3382 return;
3383 }
3384
3385 setJSValue(vmCall(
3386 m_out.operation(operationNewArrayBuffer), m_callFrame,
3387 m_out.constIntPtr(structure), m_out.constIntPtr(m_node->startConstant()),
3388 m_out.constIntPtr(m_node->numConstants())));
3389 }
3390
3391 void compileNewArrayWithSize()
3392 {
3393 LValue publicLength = lowInt32(m_node->child1());
3394
3395 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
3396 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(
3397 m_node->indexingType());
3398
3399 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) {
3400 ASSERT(
3401 hasUndecided(structure->indexingType())
3402 || hasInt32(structure->indexingType())
3403 || hasDouble(structure->indexingType())
3404 || hasContiguous(structure->indexingType()));
3405
3406 LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize fast case"));
3407 LBasicBlock largeCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize large case"));
3408 LBasicBlock failCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize fail case"));
3409 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize slow case"));
3410 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize continuation"));
3411
3412 m_out.branch(
3413 m_out.aboveOrEqual(publicLength, m_out.constInt32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)),
3414 rarely(largeCase), usually(fastCase));
3415
3416 LBasicBlock lastNext = m_out.appendTo(fastCase, largeCase);
3417
3418 // We don't round up to BASE_VECTOR_LEN for new Array(blah).
3419 LValue vectorLength = publicLength;
3420
3421 LValue payloadSize =
3422 m_out.shl(m_out.zeroExt(vectorLength, m_out.intPtr), m_out.constIntPtr(3));
3423
3424 LValue butterflySize = m_out.add(
3425 payloadSize, m_out.constIntPtr(sizeof(IndexingHeader)));
3426
3427 LValue endOfStorage = allocateBasicStorageAndGetEnd(butterflySize, failCase);
3428
3429 LValue butterfly = m_out.sub(endOfStorage, payloadSize);
3430
3431 LValue object = allocateObject<JSArray>(
3432 structure, butterfly, failCase);
3433
3434 m_out.store32(publicLength, butterfly, m_heaps.Butterfly_publicLength);
3435 m_out.store32(vectorLength, butterfly, m_heaps.Butterfly_vectorLength);
3436
3437 if (hasDouble(m_node->indexingType())) {
3438 LBasicBlock initLoop = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize double init loop"));
3439 LBasicBlock initDone = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize double init done"));
3440
3441 ValueFromBlock originalIndex = m_out.anchor(vectorLength);
3442 ValueFromBlock originalPointer = m_out.anchor(butterfly);
3443 m_out.branch(
3444 m_out.notZero32(vectorLength), unsure(initLoop), unsure(initDone));
3445
3446 LBasicBlock initLastNext = m_out.appendTo(initLoop, initDone);
3447 LValue index = m_out.phi(m_out.int32, originalIndex);
3448 LValue pointer = m_out.phi(m_out.intPtr, originalPointer);
3449
3450 m_out.store64(
3451 m_out.constInt64(bitwise_cast<int64_t>(PNaN)),
3452 TypedPointer(m_heaps.indexedDoubleProperties.atAnyIndex(), pointer));
3453
3454 LValue nextIndex = m_out.sub(index, m_out.int32One);
3455 addIncoming(index, m_out.anchor(nextIndex));
3456 addIncoming(pointer, m_out.anchor(m_out.add(pointer, m_out.intPtrEight)));
3457 m_out.branch(
3458 m_out.notZero32(nextIndex), unsure(initLoop), unsure(initDone));
3459
3460 m_out.appendTo(initDone, initLastNext);
3461 }
3462
3463 ValueFromBlock fastResult = m_out.anchor(object);
3464 m_out.jump(continuation);
3465
3466 m_out.appendTo(largeCase, failCase);
3467 ValueFromBlock largeStructure = m_out.anchor(m_out.constIntPtr(
3468 globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)));
3469 m_out.jump(slowCase);
3470
3471 m_out.appendTo(failCase, slowCase);
3472 ValueFromBlock failStructure = m_out.anchor(m_out.constIntPtr(structure));
3473 m_out.jump(slowCase);
3474
3475 m_out.appendTo(slowCase, continuation);
3476 LValue structureValue = m_out.phi(
3477 m_out.intPtr, largeStructure, failStructure);
3478 ValueFromBlock slowResult = m_out.anchor(vmCall(
3479 m_out.operation(operationNewArrayWithSize),
3480 m_callFrame, structureValue, publicLength));
3481 m_out.jump(continuation);
3482
3483 m_out.appendTo(continuation, lastNext);
3484 setJSValue(m_out.phi(m_out.intPtr, fastResult, slowResult));
3485 return;
3486 }
3487
3488 LValue structureValue = m_out.select(
3489 m_out.aboveOrEqual(publicLength, m_out.constInt32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)),
3490 m_out.constIntPtr(
3491 globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)),
3492 m_out.constIntPtr(structure));
3493 setJSValue(vmCall(m_out.operation(operationNewArrayWithSize), m_callFrame, structureValue, publicLength));
3494 }
3495
3496 void compileAllocatePropertyStorage()
3497 {
3498 LValue object = lowCell(m_node->child1());
3499 setStorage(allocatePropertyStorage(object, m_node->transition()->previous));
3500 }
3501
3502 void compileReallocatePropertyStorage()
3503 {
3504 Transition* transition = m_node->transition();
3505 LValue object = lowCell(m_node->child1());
3506 LValue oldStorage = lowStorage(m_node->child2());
3507
3508 setStorage(
3509 reallocatePropertyStorage(
3510 object, oldStorage, transition->previous, transition->next));
3511 }
3512
3513 void compileToStringOrCallStringConstructor()
3514 {
3515 switch (m_node->child1().useKind()) {
3516 case StringObjectUse: {
3517 LValue cell = lowCell(m_node->child1());
3518 speculateStringObjectForCell(m_node->child1(), cell);
3519 m_interpreter.filter(m_node->child1(), SpecStringObject);
3520
3521 setJSValue(m_out.loadPtr(cell, m_heaps.JSWrapperObject_internalValue));
3522 return;
3523 }
3524
3525 case StringOrStringObjectUse: {
3526 LValue cell = lowCell(m_node->child1());
3527 LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
3528
3529 LBasicBlock notString = FTL_NEW_BLOCK(m_out, ("ToString StringOrStringObject not string case"));
3530 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToString StringOrStringObject continuation"));
3531
3532 ValueFromBlock simpleResult = m_out.anchor(cell);
3533 m_out.branch(
3534 m_out.equal(structureID, m_out.constInt32(vm().stringStructure->id())),
3535 unsure(continuation), unsure(notString));
3536
3537 LBasicBlock lastNext = m_out.appendTo(notString, continuation);
3538 speculateStringObjectForStructureID(m_node->child1(), structureID);
3539 ValueFromBlock unboxedResult = m_out.anchor(
3540 m_out.loadPtr(cell, m_heaps.JSWrapperObject_internalValue));
3541 m_out.jump(continuation);
3542
3543 m_out.appendTo(continuation, lastNext);
3544 setJSValue(m_out.phi(m_out.int64, simpleResult, unboxedResult));
3545
3546 m_interpreter.filter(m_node->child1(), SpecString | SpecStringObject);
3547 return;
3548 }
3549
3550 case CellUse:
3551 case UntypedUse: {
3552 LValue value;
3553 if (m_node->child1().useKind() == CellUse)
3554 value = lowCell(m_node->child1());
3555 else
3556 value = lowJSValue(m_node->child1());
3557
3558 LBasicBlock isCell = FTL_NEW_BLOCK(m_out, ("ToString CellUse/UntypedUse is cell"));
3559 LBasicBlock notString = FTL_NEW_BLOCK(m_out, ("ToString CellUse/UntypedUse not string"));
3560 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToString CellUse/UntypedUse continuation"));
3561
3562 LValue isCellPredicate;
3563 if (m_node->child1().useKind() == CellUse)
3564 isCellPredicate = m_out.booleanTrue;
3565 else
3566 isCellPredicate = this->isCell(value, provenType(m_node->child1()));
3567 m_out.branch(isCellPredicate, unsure(isCell), unsure(notString));
3568
3569 LBasicBlock lastNext = m_out.appendTo(isCell, notString);
3570 ValueFromBlock simpleResult = m_out.anchor(value);
3571 LValue isStringPredicate;
3572 if (m_node->child1()->prediction() & SpecString) {
3573 isStringPredicate = isString(value, provenType(m_node->child1()));
3574 } else
3575 isStringPredicate = m_out.booleanFalse;
3576 m_out.branch(isStringPredicate, unsure(continuation), unsure(notString));
3577
3578 m_out.appendTo(notString, continuation);
3579 LValue operation;
3580 if (m_node->child1().useKind() == CellUse)
3581 operation = m_out.operation(m_node->op() == ToString ? operationToStringOnCell : operationCallStringConstructorOnCell);
3582 else
3583 operation = m_out.operation(m_node->op() == ToString ? operationToString : operationCallStringConstructor);
3584 ValueFromBlock convertedResult = m_out.anchor(vmCall(operation, m_callFrame, value));
3585 m_out.jump(continuation);
3586
3587 m_out.appendTo(continuation, lastNext);
3588 setJSValue(m_out.phi(m_out.int64, simpleResult, convertedResult));
3589 return;
3590 }
3591
3592 default:
3593 DFG_CRASH(m_graph, m_node, "Bad use kind");
3594 break;
3595 }
3596 }
3597
3598 void compileToPrimitive()
3599 {
3600 LValue value = lowJSValue(m_node->child1());
3601
3602 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("ToPrimitive cell case"));
3603 LBasicBlock isObjectCase = FTL_NEW_BLOCK(m_out, ("ToPrimitive object case"));
3604 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToPrimitive continuation"));
3605
3606 Vector<ValueFromBlock, 3> results;
3607
3608 results.append(m_out.anchor(value));
3609 m_out.branch(
3610 isCell(value, provenType(m_node->child1())), unsure(isCellCase), unsure(continuation));
3611
3612 LBasicBlock lastNext = m_out.appendTo(isCellCase, isObjectCase);
3613 results.append(m_out.anchor(value));
3614 m_out.branch(
3615 isObject(value, provenType(m_node->child1())),
3616 unsure(isObjectCase), unsure(continuation));
3617
3618 m_out.appendTo(isObjectCase, continuation);
3619 results.append(m_out.anchor(vmCall(
3620 m_out.operation(operationToPrimitive), m_callFrame, value)));
3621 m_out.jump(continuation);
3622
3623 m_out.appendTo(continuation, lastNext);
3624 setJSValue(m_out.phi(m_out.int64, results));
3625 }
3626
3627 void compileMakeRope()
3628 {
3629 LValue kids[3];
3630 unsigned numKids;
3631 kids[0] = lowCell(m_node->child1());
3632 kids[1] = lowCell(m_node->child2());
3633 if (m_node->child3()) {
3634 kids[2] = lowCell(m_node->child3());
3635 numKids = 3;
3636 } else {
3637 kids[2] = 0;
3638 numKids = 2;
3639 }
3640
3641 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("MakeRope slow path"));
3642 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MakeRope continuation"));
3643
3644 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
3645
3646 MarkedAllocator& allocator =
3647 vm().heap.allocatorForObjectWithDestructor(sizeof(JSRopeString));
3648
3649 LValue result = allocateCell(
3650 m_out.constIntPtr(&allocator),
3651 vm().stringStructure.get(),
3652 slowPath);
3653
3654 m_out.storePtr(m_out.intPtrZero, result, m_heaps.JSString_value);
3655 for (unsigned i = 0; i < numKids; ++i)
3656 m_out.storePtr(kids[i], result, m_heaps.JSRopeString_fibers[i]);
3657 for (unsigned i = numKids; i < JSRopeString::s_maxInternalRopeLength; ++i)
3658 m_out.storePtr(m_out.intPtrZero, result, m_heaps.JSRopeString_fibers[i]);
3659 LValue flags = m_out.load32(kids[0], m_heaps.JSString_flags);
3660 LValue length = m_out.load32(kids[0], m_heaps.JSString_length);
3661 for (unsigned i = 1; i < numKids; ++i) {
3662 flags = m_out.bitAnd(flags, m_out.load32(kids[i], m_heaps.JSString_flags));
3663 LValue lengthAndOverflow = m_out.addWithOverflow32(
3664 length, m_out.load32(kids[i], m_heaps.JSString_length));
3665 speculate(Uncountable, noValue(), 0, m_out.extractValue(lengthAndOverflow, 1));
3666 length = m_out.extractValue(lengthAndOverflow, 0);
3667 }
3668 m_out.store32(
3669 m_out.bitAnd(m_out.constInt32(JSString::Is8Bit), flags),
3670 result, m_heaps.JSString_flags);
3671 m_out.store32(length, result, m_heaps.JSString_length);
3672
3673 ValueFromBlock fastResult = m_out.anchor(result);
3674 m_out.jump(continuation);
3675
3676 m_out.appendTo(slowPath, continuation);
3677 ValueFromBlock slowResult;
3678 switch (numKids) {
3679 case 2:
3680 slowResult = m_out.anchor(vmCall(
3681 m_out.operation(operationMakeRope2), m_callFrame, kids[0], kids[1]));
3682 break;
3683 case 3:
3684 slowResult = m_out.anchor(vmCall(
3685 m_out.operation(operationMakeRope3), m_callFrame, kids[0], kids[1], kids[2]));
3686 break;
3687 default:
3688 DFG_CRASH(m_graph, m_node, "Bad number of children");
3689 break;
3690 }
3691 m_out.jump(continuation);
3692
3693 m_out.appendTo(continuation, lastNext);
3694 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
3695 }
3696
3697 void compileStringCharAt()
3698 {
3699 LValue base = lowCell(m_node->child1());
3700 LValue index = lowInt32(m_node->child2());
3701 LValue storage = lowStorage(m_node->child3());
3702
3703 LBasicBlock fastPath = FTL_NEW_BLOCK(m_out, ("GetByVal String fast path"));
3704 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("GetByVal String slow path"));
3705 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal String continuation"));
3706
3707 m_out.branch(
3708 m_out.aboveOrEqual(
3709 index, m_out.load32NonNegative(base, m_heaps.JSString_length)),
3710 rarely(slowPath), usually(fastPath));
3711
3712 LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
3713
3714 LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value);
3715
3716 LBasicBlock is8Bit = FTL_NEW_BLOCK(m_out, ("GetByVal String 8-bit case"));
3717 LBasicBlock is16Bit = FTL_NEW_BLOCK(m_out, ("GetByVal String 16-bit case"));
3718 LBasicBlock bitsContinuation = FTL_NEW_BLOCK(m_out, ("GetByVal String bitness continuation"));
3719 LBasicBlock bigCharacter = FTL_NEW_BLOCK(m_out, ("GetByVal String big character"));
3720
3721 m_out.branch(
3722 m_out.testIsZero32(
3723 m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags),
3724 m_out.constInt32(StringImpl::flagIs8Bit())),
3725 unsure(is16Bit), unsure(is8Bit));
3726
3727 m_out.appendTo(is8Bit, is16Bit);
3728
3729 ValueFromBlock char8Bit = m_out.anchor(m_out.zeroExt(
3730 m_out.load8(m_out.baseIndex(
3731 m_heaps.characters8, storage, m_out.zeroExtPtr(index),
3732 provenValue(m_node->child2()))),
3733 m_out.int32));
3734 m_out.jump(bitsContinuation);
3735
3736 m_out.appendTo(is16Bit, bigCharacter);
3737
3738 ValueFromBlock char16Bit = m_out.anchor(m_out.zeroExt(
3739 m_out.load16(m_out.baseIndex(
3740 m_heaps.characters16, storage, m_out.zeroExtPtr(index),
3741 provenValue(m_node->child2()))),
3742 m_out.int32));
3743 m_out.branch(
3744 m_out.aboveOrEqual(char16Bit.value(), m_out.constInt32(0x100)),
3745 rarely(bigCharacter), usually(bitsContinuation));
3746
3747 m_out.appendTo(bigCharacter, bitsContinuation);
3748
3749 Vector<ValueFromBlock, 4> results;
3750 results.append(m_out.anchor(vmCall(
3751 m_out.operation(operationSingleCharacterString),
3752 m_callFrame, char16Bit.value())));
3753 m_out.jump(continuation);
3754
3755 m_out.appendTo(bitsContinuation, slowPath);
3756
3757 LValue character = m_out.phi(m_out.int32, char8Bit, char16Bit);
3758
3759 LValue smallStrings = m_out.constIntPtr(vm().smallStrings.singleCharacterStrings());
3760
3761 results.append(m_out.anchor(m_out.loadPtr(m_out.baseIndex(
3762 m_heaps.singleCharacterStrings, smallStrings, m_out.zeroExtPtr(character)))));
3763 m_out.jump(continuation);
3764
3765 m_out.appendTo(slowPath, continuation);
3766
3767 if (m_node->arrayMode().isInBounds()) {
3768 speculate(OutOfBounds, noValue(), 0, m_out.booleanTrue);
3769 results.append(m_out.anchor(m_out.intPtrZero));
3770 } else {
3771 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
3772
3773 if (globalObject->stringPrototypeChainIsSane()) {
3774 // FIXME: This could be captured using a Speculation mode that means
3775 // "out-of-bounds loads return a trivial value", something like
3776 // SaneChainOutOfBounds.
3777 // https://bugs.webkit.org/show_bug.cgi?id=144668
3778
3779 m_graph.watchpoints().addLazily(globalObject->stringPrototype()->structure()->transitionWatchpointSet());
3780 m_graph.watchpoints().addLazily(globalObject->objectPrototype()->structure()->transitionWatchpointSet());
3781
3782 LBasicBlock negativeIndex = FTL_NEW_BLOCK(m_out, ("GetByVal String negative index"));
3783
3784 results.append(m_out.anchor(m_out.constInt64(JSValue::encode(jsUndefined()))));
3785 m_out.branch(
3786 m_out.lessThan(index, m_out.int32Zero),
3787 rarely(negativeIndex), usually(continuation));
3788
3789 m_out.appendTo(negativeIndex, continuation);
3790 }
3791
3792 results.append(m_out.anchor(vmCall(
3793 m_out.operation(operationGetByValStringInt), m_callFrame, base, index)));
3794 }
3795
3796 m_out.jump(continuation);
3797
3798 m_out.appendTo(continuation, lastNext);
3799 setJSValue(m_out.phi(m_out.int64, results));
3800 }
3801
3802 void compileStringCharCodeAt()
3803 {
3804 LBasicBlock is8Bit = FTL_NEW_BLOCK(m_out, ("StringCharCodeAt 8-bit case"));
3805 LBasicBlock is16Bit = FTL_NEW_BLOCK(m_out, ("StringCharCodeAt 16-bit case"));
3806 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("StringCharCodeAt continuation"));
3807
3808 LValue base = lowCell(m_node->child1());
3809 LValue index = lowInt32(m_node->child2());
3810 LValue storage = lowStorage(m_node->child3());
3811
3812 speculate(
3813 Uncountable, noValue(), 0,
3814 m_out.aboveOrEqual(
3815 index, m_out.load32NonNegative(base, m_heaps.JSString_length)));
3816
3817 LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value);
3818
3819 m_out.branch(
3820 m_out.testIsZero32(
3821 m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags),
3822 m_out.constInt32(StringImpl::flagIs8Bit())),
3823 unsure(is16Bit), unsure(is8Bit));
3824
3825 LBasicBlock lastNext = m_out.appendTo(is8Bit, is16Bit);
3826
3827 ValueFromBlock char8Bit = m_out.anchor(m_out.zeroExt(
3828 m_out.load8(m_out.baseIndex(
3829 m_heaps.characters8, storage, m_out.zeroExtPtr(index),
3830 provenValue(m_node->child2()))),
3831 m_out.int32));
3832 m_out.jump(continuation);
3833
3834 m_out.appendTo(is16Bit, continuation);
3835
3836 ValueFromBlock char16Bit = m_out.anchor(m_out.zeroExt(
3837 m_out.load16(m_out.baseIndex(
3838 m_heaps.characters16, storage, m_out.zeroExtPtr(index),
3839 provenValue(m_node->child2()))),
3840 m_out.int32));
3841 m_out.jump(continuation);
3842
3843 m_out.appendTo(continuation, lastNext);
3844
3845 setInt32(m_out.phi(m_out.int32, char8Bit, char16Bit));
3846 }
3847
3848 void compileGetByOffset()
3849 {
3850 StorageAccessData& data = m_node->storageAccessData();
3851
3852 setJSValue(loadProperty(
3853 lowStorage(m_node->child1()), data.identifierNumber, data.offset));
3854 }
3855
3856 void compileGetGetter()
3857 {
3858 setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.GetterSetter_getter));
3859 }
3860
3861 void compileGetSetter()
3862 {
3863 setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.GetterSetter_setter));
3864 }
3865
3866 void compileMultiGetByOffset()
3867 {
3868 LValue base = lowCell(m_node->child1());
3869
3870 MultiGetByOffsetData& data = m_node->multiGetByOffsetData();
3871
3872 if (data.variants.isEmpty()) {
3873 // Protect against creating a Phi function with zero inputs. LLVM doesn't like that.
3874 terminate(BadCache);
3875 return;
3876 }
3877
3878 Vector<LBasicBlock, 2> blocks(data.variants.size());
3879 for (unsigned i = data.variants.size(); i--;)
3880 blocks[i] = FTL_NEW_BLOCK(m_out, ("MultiGetByOffset case ", i));
3881 LBasicBlock exit = FTL_NEW_BLOCK(m_out, ("MultiGetByOffset fail"));
3882 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MultiGetByOffset continuation"));
3883
3884 Vector<SwitchCase, 2> cases;
3885 StructureSet baseSet;
3886 for (unsigned i = data.variants.size(); i--;) {
3887 GetByIdVariant variant = data.variants[i];
3888 for (unsigned j = variant.structureSet().size(); j--;) {
3889 Structure* structure = variant.structureSet()[j];
3890 baseSet.add(structure);
3891 cases.append(SwitchCase(weakStructureID(structure), blocks[i], Weight(1)));
3892 }
3893 }
3894 m_out.switchInstruction(
3895 m_out.load32(base, m_heaps.JSCell_structureID), cases, exit, Weight(0));
3896
3897 LBasicBlock lastNext = m_out.m_nextBlock;
3898
3899 Vector<ValueFromBlock, 2> results;
3900 for (unsigned i = data.variants.size(); i--;) {
3901 m_out.appendTo(blocks[i], i + 1 < data.variants.size() ? blocks[i + 1] : exit);
3902
3903 GetByIdVariant variant = data.variants[i];
3904 baseSet.merge(variant.structureSet());
3905 LValue result;
3906 JSValue constantResult;
3907 if (variant.alternateBase()) {
3908 constantResult = m_graph.tryGetConstantProperty(
3909 variant.alternateBase(), variant.baseStructure(), variant.offset());
3910 }
3911 if (constantResult)
3912 result = m_out.constInt64(JSValue::encode(constantResult));
3913 else {
3914 LValue propertyBase;
3915 if (variant.alternateBase())
3916 propertyBase = weakPointer(variant.alternateBase());
3917 else
3918 propertyBase = base;
3919 if (!isInlineOffset(variant.offset()))
3920 propertyBase = m_out.loadPtr(propertyBase, m_heaps.JSObject_butterfly);
3921 result = loadProperty(propertyBase, data.identifierNumber, variant.offset());
3922 }
3923
3924 results.append(m_out.anchor(result));
3925 m_out.jump(continuation);
3926 }
3927
3928 m_out.appendTo(exit, continuation);
3929 if (!m_interpreter.forNode(m_node->child1()).m_structure.isSubsetOf(baseSet))
3930 speculate(BadCache, noValue(), nullptr, m_out.booleanTrue);
3931 m_out.unreachable();
3932
3933 m_out.appendTo(continuation, lastNext);
3934 setJSValue(m_out.phi(m_out.int64, results));
3935 }
3936
3937 void compilePutByOffset()
3938 {
3939 StorageAccessData& data = m_node->storageAccessData();
3940
3941 storeProperty(
3942 lowJSValue(m_node->child3()),
3943 lowStorage(m_node->child1()), data.identifierNumber, data.offset);
3944 }
3945
3946 void compileMultiPutByOffset()
3947 {
3948 LValue base = lowCell(m_node->child1());
3949 LValue value = lowJSValue(m_node->child2());
3950
3951 MultiPutByOffsetData& data = m_node->multiPutByOffsetData();
3952
3953 Vector<LBasicBlock, 2> blocks(data.variants.size());
3954 for (unsigned i = data.variants.size(); i--;)
3955 blocks[i] = FTL_NEW_BLOCK(m_out, ("MultiPutByOffset case ", i));
3956 LBasicBlock exit = FTL_NEW_BLOCK(m_out, ("MultiPutByOffset fail"));
3957 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MultiPutByOffset continuation"));
3958
3959 Vector<SwitchCase, 2> cases;
3960 StructureSet baseSet;
3961 for (unsigned i = data.variants.size(); i--;) {
3962 PutByIdVariant variant = data.variants[i];
3963 for (unsigned j = variant.oldStructure().size(); j--;) {
3964 Structure* structure = variant.oldStructure()[j];
3965 baseSet.add(structure);
3966 cases.append(SwitchCase(weakStructureID(structure), blocks[i], Weight(1)));
3967 }
3968 }
3969 m_out.switchInstruction(
3970 m_out.load32(base, m_heaps.JSCell_structureID), cases, exit, Weight(0));
3971
3972 LBasicBlock lastNext = m_out.m_nextBlock;
3973
3974 for (unsigned i = data.variants.size(); i--;) {
3975 m_out.appendTo(blocks[i], i + 1 < data.variants.size() ? blocks[i + 1] : exit);
3976
3977 PutByIdVariant variant = data.variants[i];
3978
3979 LValue storage;
3980 if (variant.kind() == PutByIdVariant::Replace) {
3981 if (isInlineOffset(variant.offset()))
3982 storage = base;
3983 else
3984 storage = m_out.loadPtr(base, m_heaps.JSObject_butterfly);
3985 } else {
3986 m_graph.m_plan.transitions.addLazily(
3987 codeBlock(), m_node->origin.semantic.codeOriginOwner(),
3988 variant.oldStructureForTransition(), variant.newStructure());
3989
3990 storage = storageForTransition(
3991 base, variant.offset(),
3992 variant.oldStructureForTransition(), variant.newStructure());
3993
3994 ASSERT(variant.oldStructureForTransition()->indexingType() == variant.newStructure()->indexingType());
3995 ASSERT(variant.oldStructureForTransition()->typeInfo().inlineTypeFlags() == variant.newStructure()->typeInfo().inlineTypeFlags());
3996 ASSERT(variant.oldStructureForTransition()->typeInfo().type() == variant.newStructure()->typeInfo().type());
3997 m_out.store32(
3998 weakStructureID(variant.newStructure()), base, m_heaps.JSCell_structureID);
3999 }
4000
4001 storeProperty(value, storage, data.identifierNumber, variant.offset());
4002 m_out.jump(continuation);
4003 }
4004
4005 m_out.appendTo(exit, continuation);
4006 if (!m_interpreter.forNode(m_node->child1()).m_structure.isSubsetOf(baseSet))
4007 speculate(BadCache, noValue(), nullptr, m_out.booleanTrue);
4008 m_out.unreachable();
4009
4010 m_out.appendTo(continuation, lastNext);
4011 }
4012
4013 void compileGetGlobalVar()
4014 {
4015 setJSValue(m_out.load64(m_out.absolute(m_node->variablePointer())));
4016 }
4017
4018 void compilePutGlobalVar()
4019 {
4020 m_out.store64(
4021 lowJSValue(m_node->child2()), m_out.absolute(m_node->variablePointer()));
4022 }
4023
4024 void compileNotifyWrite()
4025 {
4026 WatchpointSet* set = m_node->watchpointSet();
4027
4028 LBasicBlock isNotInvalidated = FTL_NEW_BLOCK(m_out, ("NotifyWrite not invalidated case"));
4029 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NotifyWrite continuation"));
4030
4031 LValue state = m_out.load8(m_out.absolute(set->addressOfState()));
4032 m_out.branch(
4033 m_out.equal(state, m_out.constInt8(IsInvalidated)),
4034 usually(continuation), rarely(isNotInvalidated));
4035
4036 LBasicBlock lastNext = m_out.appendTo(isNotInvalidated, continuation);
4037
4038 vmCall(m_out.operation(operationNotifyWrite), m_callFrame, m_out.constIntPtr(set));
4039 m_out.jump(continuation);
4040
4041 m_out.appendTo(continuation, lastNext);
4042 }
4043
4044 void compileGetCallee()
4045 {
4046 setJSValue(m_out.loadPtr(addressFor(JSStack::Callee)));
4047 }
4048
4049 void compileGetArgumentCount()
4050 {
4051 setInt32(m_out.load32(payloadFor(JSStack::ArgumentCount)));
4052 }
4053
4054 void compileGetScope()
4055 {
4056 setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSFunction_scope));
4057 }
4058
4059 void compileSkipScope()
4060 {
4061 setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSScope_next));
4062 }
4063
4064 void compileGetClosureVar()
4065 {
4066 setJSValue(
4067 m_out.load64(
4068 lowCell(m_node->child1()),
4069 m_heaps.JSEnvironmentRecord_variables[m_node->scopeOffset().offset()]));
4070 }
4071
4072 void compilePutClosureVar()
4073 {
4074 m_out.store64(
4075 lowJSValue(m_node->child2()),
4076 lowCell(m_node->child1()),
4077 m_heaps.JSEnvironmentRecord_variables[m_node->scopeOffset().offset()]);
4078 }
4079
4080 void compileGetFromArguments()
4081 {
4082 setJSValue(
4083 m_out.load64(
4084 lowCell(m_node->child1()),
4085 m_heaps.DirectArguments_storage[m_node->capturedArgumentsOffset().offset()]));
4086 }
4087
4088 void compilePutToArguments()
4089 {
4090 m_out.store64(
4091 lowJSValue(m_node->child2()),
4092 lowCell(m_node->child1()),
4093 m_heaps.DirectArguments_storage[m_node->capturedArgumentsOffset().offset()]);
4094 }
4095
4096 void compileCompareEq()
4097 {
4098 if (m_node->isBinaryUseKind(Int32Use)
4099 || m_node->isBinaryUseKind(Int52RepUse)
4100 || m_node->isBinaryUseKind(DoubleRepUse)
4101 || m_node->isBinaryUseKind(ObjectUse)
4102 || m_node->isBinaryUseKind(BooleanUse)
4103 || m_node->isBinaryUseKind(StringIdentUse)) {
4104 compileCompareStrictEq();
4105 return;
4106 }
4107
4108 if (m_node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse)) {
4109 compareEqObjectOrOtherToObject(m_node->child2(), m_node->child1());
4110 return;
4111 }
4112
4113 if (m_node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) {
4114 compareEqObjectOrOtherToObject(m_node->child1(), m_node->child2());
4115 return;
4116 }
4117
4118 if (m_node->isBinaryUseKind(UntypedUse)) {
4119 nonSpeculativeCompare(LLVMIntEQ, operationCompareEq);
4120 return;
4121 }
4122
4123 DFG_CRASH(m_graph, m_node, "Bad use kinds");
4124 }
4125
4126 void compileCompareEqConstant()
4127 {
4128 ASSERT(m_node->child2()->asJSValue().isNull());
4129 setBoolean(
4130 equalNullOrUndefined(
4131 m_node->child1(), AllCellsAreFalse, EqualNullOrUndefined));
4132 }
4133
4134 void compileCompareStrictEq()
4135 {
4136 if (m_node->isBinaryUseKind(Int32Use)) {
4137 setBoolean(
4138 m_out.equal(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
4139 return;
4140 }
4141
4142 if (m_node->isBinaryUseKind(Int52RepUse)) {
4143 Int52Kind kind;
4144 LValue left = lowWhicheverInt52(m_node->child1(), kind);
4145 LValue right = lowInt52(m_node->child2(), kind);
4146 setBoolean(m_out.equal(left, right));
4147 return;
4148 }
4149
4150 if (m_node->isBinaryUseKind(DoubleRepUse)) {
4151 setBoolean(
4152 m_out.doubleEqual(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
4153 return;
4154 }
4155
4156 if (m_node->isBinaryUseKind(StringIdentUse)) {
4157 setBoolean(
4158 m_out.equal(lowStringIdent(m_node->child1()), lowStringIdent(m_node->child2())));
4159 return;
4160 }
4161
4162 if (m_node->isBinaryUseKind(ObjectUse, UntypedUse)) {
4163 setBoolean(
4164 m_out.equal(
4165 lowNonNullObject(m_node->child1()),
4166 lowJSValue(m_node->child2())));
4167 return;
4168 }
4169
4170 if (m_node->isBinaryUseKind(UntypedUse, ObjectUse)) {
4171 setBoolean(
4172 m_out.equal(
4173 lowNonNullObject(m_node->child2()),
4174 lowJSValue(m_node->child1())));
4175 return;
4176 }
4177
4178 if (m_node->isBinaryUseKind(ObjectUse)) {
4179 setBoolean(
4180 m_out.equal(
4181 lowNonNullObject(m_node->child1()),
4182 lowNonNullObject(m_node->child2())));
4183 return;
4184 }
4185
4186 if (m_node->isBinaryUseKind(BooleanUse)) {
4187 setBoolean(
4188 m_out.equal(lowBoolean(m_node->child1()), lowBoolean(m_node->child2())));
4189 return;
4190 }
4191
4192 if (m_node->isBinaryUseKind(MiscUse, UntypedUse)
4193 || m_node->isBinaryUseKind(UntypedUse, MiscUse)) {
4194 speculate(m_node->child1());
4195 speculate(m_node->child2());
4196 LValue left = lowJSValue(m_node->child1(), ManualOperandSpeculation);
4197 LValue right = lowJSValue(m_node->child2(), ManualOperandSpeculation);
4198 setBoolean(m_out.equal(left, right));
4199 return;
4200 }
4201
4202 if (m_node->isBinaryUseKind(StringIdentUse, NotStringVarUse)
4203 || m_node->isBinaryUseKind(NotStringVarUse, StringIdentUse)) {
4204 Edge leftEdge = m_node->childFor(StringIdentUse);
4205 Edge rightEdge = m_node->childFor(NotStringVarUse);
4206
4207 LValue left = lowStringIdent(leftEdge);
4208 LValue rightValue = lowJSValue(rightEdge, ManualOperandSpeculation);
4209
4210 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("CompareStrictEq StringIdent to NotStringVar is cell case"));
4211 LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, ("CompareStrictEq StringIdent to NotStringVar is string case"));
4212 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CompareStrictEq StringIdent to NotStringVar continuation"));
4213
4214 ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
4215 m_out.branch(
4216 isCell(rightValue, provenType(rightEdge)),
4217 unsure(isCellCase), unsure(continuation));
4218
4219 LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
4220 ValueFromBlock notStringResult = m_out.anchor(m_out.booleanFalse);
4221 m_out.branch(
4222 isString(rightValue, provenType(rightEdge)),
4223 unsure(isStringCase), unsure(continuation));
4224
4225 m_out.appendTo(isStringCase, continuation);
4226 LValue right = m_out.loadPtr(rightValue, m_heaps.JSString_value);
4227 speculateStringIdent(rightEdge, rightValue, right);
4228 ValueFromBlock isStringResult = m_out.anchor(m_out.equal(left, right));
4229 m_out.jump(continuation);
4230
4231 m_out.appendTo(continuation, lastNext);
4232 setBoolean(m_out.phi(m_out.boolean, notCellResult, notStringResult, isStringResult));
4233 return;
4234 }
4235
4236 DFG_CRASH(m_graph, m_node, "Bad use kinds");
4237 }
4238
4239 void compileCompareStrictEqConstant()
4240 {
4241 JSValue constant = m_node->child2()->asJSValue();
4242
4243 setBoolean(
4244 m_out.equal(
4245 lowJSValue(m_node->child1()),
4246 m_out.constInt64(JSValue::encode(constant))));
4247 }
4248
4249 void compileCompareLess()
4250 {
4251 compare(LLVMIntSLT, LLVMRealOLT, operationCompareLess);
4252 }
4253
4254 void compileCompareLessEq()
4255 {
4256 compare(LLVMIntSLE, LLVMRealOLE, operationCompareLessEq);
4257 }
4258
4259 void compileCompareGreater()
4260 {
4261 compare(LLVMIntSGT, LLVMRealOGT, operationCompareGreater);
4262 }
4263
4264 void compileCompareGreaterEq()
4265 {
4266 compare(LLVMIntSGE, LLVMRealOGE, operationCompareGreaterEq);
4267 }
4268
4269 void compileLogicalNot()
4270 {
4271 setBoolean(m_out.bitNot(boolify(m_node->child1())));
4272 }
4273#if ENABLE(FTL_NATIVE_CALL_INLINING)
4274 void compileNativeCallOrConstruct()
4275 {
4276 int numPassedArgs = m_node->numChildren() - 1;
4277 int numArgs = numPassedArgs;
4278
4279 JSFunction* knownFunction = m_node->castOperand<JSFunction*>();
4280 NativeFunction function = knownFunction->nativeFunction();
4281
4282 Dl_info info;
4283 if (!dladdr((void*)function, &info))
4284 ASSERT(false); // if we couldn't find the native function this doesn't bode well.
4285
4286 LValue callee = getFunctionBySymbol(info.dli_sname);
4287
4288 bool notInlinable;
4289 if ((notInlinable = !callee))
4290 callee = m_out.operation(function);
4291
4292 m_out.storePtr(m_callFrame, m_execStorage, m_heaps.CallFrame_callerFrame);
4293 m_out.storePtr(constNull(m_out.intPtr), addressFor(m_execStorage, JSStack::CodeBlock));
4294 m_out.storePtr(weakPointer(knownFunction), addressFor(m_execStorage, JSStack::Callee));
4295
4296 m_out.store64(m_out.constInt64(numArgs), addressFor(m_execStorage, JSStack::ArgumentCount));
4297
4298 for (int i = 0; i < numPassedArgs; ++i) {
4299 m_out.storePtr(lowJSValue(m_graph.varArgChild(m_node, 1 + i)),
4300 addressFor(m_execStorage, JSStack::ThisArgument, i * sizeof(Register)));
4301 }
4302
4303 LValue calleeCallFrame = m_out.address(m_execState, m_heaps.CallFrame_callerFrame).value();
4304 m_out.storePtr(m_out.ptrToInt(calleeCallFrame, m_out.intPtr), m_out.absolute(&vm().topCallFrame));
4305
4306 LType typeCalleeArg;
4307 getParamTypes(getElementType(typeOf(callee)), &typeCalleeArg);
4308
4309 LValue argument = notInlinable
4310 ? m_out.ptrToInt(calleeCallFrame, typeCalleeArg)
4311 : m_out.bitCast(calleeCallFrame, typeCalleeArg);
4312 LValue call = vmCall(callee, argument);
4313
4314 if (verboseCompilationEnabled())
4315 dataLog("Native calling: ", info.dli_sname, "\n");
4316
4317 setJSValue(call);
4318 }
4319#endif
4320
4321 void compileCallOrConstruct()
4322 {
4323 int numPassedArgs = m_node->numChildren() - 1;
4324 int numArgs = numPassedArgs;
4325
4326 LValue jsCallee = lowJSValue(m_graph.varArgChild(m_node, 0));
4327
4328 unsigned stackmapID = m_stackmapIDs++;
4329
4330 Vector<LValue> arguments;
4331 arguments.append(m_out.constInt64(stackmapID));
4332 arguments.append(m_out.constInt32(sizeOfCall()));
4333 arguments.append(constNull(m_out.ref8));
4334 arguments.append(m_out.constInt32(1 + JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize + numArgs));
4335 arguments.append(jsCallee); // callee -> %rax
4336 arguments.append(getUndef(m_out.int64)); // code block
4337 arguments.append(jsCallee); // callee -> stack
4338 arguments.append(m_out.constInt64(numArgs)); // argument count and zeros for the tag
4339 for (int i = 0; i < numPassedArgs; ++i)
4340 arguments.append(lowJSValue(m_graph.varArgChild(m_node, 1 + i)));
4341
4342 callPreflight();
4343
4344 LValue call = m_out.call(m_out.patchpointInt64Intrinsic(), arguments);
4345 setInstructionCallingConvention(call, LLVMWebKitJSCallConv);
4346
4347 m_ftlState.jsCalls.append(JSCall(stackmapID, m_node));
4348
4349 setJSValue(call);
4350 }
4351
4352 void compileCallOrConstructVarargs()
4353 {
4354 LValue jsCallee = lowJSValue(m_node->child1());
4355 LValue thisArg = lowJSValue(m_node->child3());
4356
4357 LValue jsArguments = nullptr;
4358
4359 switch (m_node->op()) {
4360 case CallVarargs:
4361 case ConstructVarargs:
4362 jsArguments = lowJSValue(m_node->child2());
4363 break;
4364 case CallForwardVarargs:
4365 case ConstructForwardVarargs:
4366 break;
4367 default:
4368 DFG_CRASH(m_graph, m_node, "bad node type");
4369 break;
4370 }
4371
4372 unsigned stackmapID = m_stackmapIDs++;
4373
4374 Vector<LValue> arguments;
4375 arguments.append(m_out.constInt64(stackmapID));
4376 arguments.append(m_out.constInt32(sizeOfICFor(m_node)));
4377 arguments.append(constNull(m_out.ref8));
4378 arguments.append(m_out.constInt32(2 + !!jsArguments));
4379 arguments.append(jsCallee);
4380 if (jsArguments)
4381 arguments.append(jsArguments);
4382 ASSERT(thisArg);
4383 arguments.append(thisArg);
4384
4385 callPreflight();
4386
4387 LValue call = m_out.call(m_out.patchpointInt64Intrinsic(), arguments);
4388 setInstructionCallingConvention(call, LLVMCCallConv);
4389
4390 m_ftlState.jsCallVarargses.append(JSCallVarargs(stackmapID, m_node));
4391
4392 setJSValue(call);
4393 }
4394
4395 void compileLoadVarargs()
4396 {
4397 LoadVarargsData* data = m_node->loadVarargsData();
4398 LValue jsArguments = lowJSValue(m_node->child1());
4399
4400 LValue length = vmCall(
4401 m_out.operation(operationSizeOfVarargs), m_callFrame, jsArguments,
4402 m_out.constInt32(data->offset));
4403
4404 // FIXME: There is a chance that we will call an effectful length property twice. This is safe
4405 // from the standpoint of the VM's integrity, but it's subtly wrong from a spec compliance
4406 // standpoint. The best solution would be one where we can exit *into* the op_call_varargs right
4407 // past the sizing.
4408 // https://bugs.webkit.org/show_bug.cgi?id=141448
4409
4410 LValue lengthIncludingThis = m_out.add(length, m_out.int32One);
4411 speculate(
4412 VarargsOverflow, noValue(), nullptr,
4413 m_out.above(lengthIncludingThis, m_out.constInt32(data->limit)));
4414
4415 m_out.store32(lengthIncludingThis, payloadFor(data->machineCount));
4416
4417 // FIXME: This computation is rather silly. If operationLaodVarargs just took a pointer instead
4418 // of a VirtualRegister, we wouldn't have to do this.
4419 // https://bugs.webkit.org/show_bug.cgi?id=141660
4420 LValue machineStart = m_out.lShr(
4421 m_out.sub(addressFor(data->machineStart.offset()).value(), m_callFrame),
4422 m_out.constIntPtr(3));
4423
4424 vmCall(
4425 m_out.operation(operationLoadVarargs), m_callFrame,
4426 m_out.castToInt32(machineStart), jsArguments, m_out.constInt32(data->offset),
4427 length, m_out.constInt32(data->mandatoryMinimum));
4428 }
4429
4430 void compileForwardVarargs()
4431 {
4432 LoadVarargsData* data = m_node->loadVarargsData();
4433 InlineCallFrame* inlineCallFrame = m_node->child1()->origin.semantic.inlineCallFrame;
4434
4435 LValue length = getArgumentsLength(inlineCallFrame).value;
4436 LValue lengthIncludingThis = m_out.add(length, m_out.constInt32(1 - data->offset));
4437
4438 speculate(
4439 VarargsOverflow, noValue(), nullptr,
4440 m_out.above(lengthIncludingThis, m_out.constInt32(data->limit)));
4441
4442 m_out.store32(lengthIncludingThis, payloadFor(data->machineCount));
4443
4444 LValue sourceStart = getArgumentsStart(inlineCallFrame);
4445 LValue targetStart = addressFor(data->machineStart).value();
4446
4447 LBasicBlock undefinedLoop = FTL_NEW_BLOCK(m_out, ("ForwardVarargs undefined loop body"));
4448 LBasicBlock mainLoopEntry = FTL_NEW_BLOCK(m_out, ("ForwardVarargs main loop entry"));
4449 LBasicBlock mainLoop = FTL_NEW_BLOCK(m_out, ("ForwardVarargs main loop body"));
4450 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ForwardVarargs continuation"));
4451
4452 LValue lengthAsPtr = m_out.zeroExtPtr(length);
4453 ValueFromBlock loopBound = m_out.anchor(m_out.constIntPtr(data->mandatoryMinimum));
4454 m_out.branch(
4455 m_out.above(loopBound.value(), lengthAsPtr), unsure(undefinedLoop), unsure(mainLoopEntry));
4456
4457 LBasicBlock lastNext = m_out.appendTo(undefinedLoop, mainLoopEntry);
4458 LValue previousIndex = m_out.phi(m_out.intPtr, loopBound);
4459 LValue currentIndex = m_out.sub(previousIndex, m_out.intPtrOne);
4460 m_out.store64(
4461 m_out.constInt64(JSValue::encode(jsUndefined())),
4462 m_out.baseIndex(m_heaps.variables, targetStart, currentIndex));
4463 ValueFromBlock nextIndex = m_out.anchor(currentIndex);
4464 addIncoming(previousIndex, nextIndex);
4465 m_out.branch(
4466 m_out.above(currentIndex, lengthAsPtr), unsure(undefinedLoop), unsure(mainLoopEntry));
4467
4468 m_out.appendTo(mainLoopEntry, mainLoop);
4469 loopBound = m_out.anchor(lengthAsPtr);
4470 m_out.branch(m_out.notNull(loopBound.value()), unsure(mainLoop), unsure(continuation));
4471
4472 m_out.appendTo(mainLoop, continuation);
4473 previousIndex = m_out.phi(m_out.intPtr, loopBound);
4474 currentIndex = m_out.sub(previousIndex, m_out.intPtrOne);
4475 LValue value = m_out.load64(
4476 m_out.baseIndex(
4477 m_heaps.variables, sourceStart,
4478 m_out.add(currentIndex, m_out.constIntPtr(data->offset))));
4479 m_out.store64(value, m_out.baseIndex(m_heaps.variables, targetStart, currentIndex));
4480 nextIndex = m_out.anchor(currentIndex);
4481 addIncoming(previousIndex, nextIndex);
4482 m_out.branch(m_out.isNull(currentIndex), unsure(continuation), unsure(mainLoop));
4483
4484 m_out.appendTo(continuation, lastNext);
4485 }
4486
4487 void compileJump()
4488 {
4489 m_out.jump(lowBlock(m_node->targetBlock()));
4490 }
4491
4492 void compileBranch()
4493 {
4494 m_out.branch(
4495 boolify(m_node->child1()),
4496 WeightedTarget(
4497 lowBlock(m_node->branchData()->taken.block),
4498 m_node->branchData()->taken.count),
4499 WeightedTarget(
4500 lowBlock(m_node->branchData()->notTaken.block),
4501 m_node->branchData()->notTaken.count));
4502 }
4503
4504 void compileSwitch()
4505 {
4506 SwitchData* data = m_node->switchData();
4507 switch (data->kind) {
4508 case SwitchImm: {
4509 Vector<ValueFromBlock, 2> intValues;
4510 LBasicBlock switchOnInts = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm int case"));
4511
4512 LBasicBlock lastNext = m_out.appendTo(m_out.m_block, switchOnInts);
4513
4514 switch (m_node->child1().useKind()) {
4515 case Int32Use: {
4516 intValues.append(m_out.anchor(lowInt32(m_node->child1())));
4517 m_out.jump(switchOnInts);
4518 break;
4519 }
4520
4521 case UntypedUse: {
4522 LBasicBlock isInt = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm is int"));
4523 LBasicBlock isNotInt = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm is not int"));
4524 LBasicBlock isDouble = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm is double"));
4525
4526 LValue boxedValue = lowJSValue(m_node->child1());
4527 m_out.branch(isNotInt32(boxedValue), unsure(isNotInt), unsure(isInt));
4528
4529 LBasicBlock innerLastNext = m_out.appendTo(isInt, isNotInt);
4530
4531 intValues.append(m_out.anchor(unboxInt32(boxedValue)));
4532 m_out.jump(switchOnInts);
4533
4534 m_out.appendTo(isNotInt, isDouble);
4535 m_out.branch(
4536 isCellOrMisc(boxedValue, provenType(m_node->child1())),
4537 usually(lowBlock(data->fallThrough.block)), rarely(isDouble));
4538
4539 m_out.appendTo(isDouble, innerLastNext);
4540 LValue doubleValue = unboxDouble(boxedValue);
4541 LValue intInDouble = m_out.fpToInt32(doubleValue);
4542 intValues.append(m_out.anchor(intInDouble));
4543 m_out.branch(
4544 m_out.doubleEqual(m_out.intToDouble(intInDouble), doubleValue),
4545 unsure(switchOnInts), unsure(lowBlock(data->fallThrough.block)));
4546 break;
4547 }
4548
4549 default:
4550 DFG_CRASH(m_graph, m_node, "Bad use kind");
4551 break;
4552 }
4553
4554 m_out.appendTo(switchOnInts, lastNext);
4555 buildSwitch(data, m_out.int32, m_out.phi(m_out.int32, intValues));
4556 return;
4557 }
4558
4559 case SwitchChar: {
4560 LValue stringValue;
4561
4562 // FIXME: We should use something other than unsure() for the branch weight
4563 // of the fallThrough block. The main challenge is just that we have multiple
4564 // branches to fallThrough but a single count, so we would need to divvy it up
4565 // among the different lowered branches.
4566 // https://bugs.webkit.org/show_bug.cgi?id=129082
4567
4568 switch (m_node->child1().useKind()) {
4569 case StringUse: {
4570 stringValue = lowString(m_node->child1());
4571 break;
4572 }
4573
4574 case UntypedUse: {
4575 LValue unboxedValue = lowJSValue(m_node->child1());
4576
4577 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar is cell"));
4578 LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar is string"));
4579
4580 m_out.branch(
4581 isNotCell(unboxedValue, provenType(m_node->child1())),
4582 unsure(lowBlock(data->fallThrough.block)), unsure(isCellCase));
4583
4584 LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
4585 LValue cellValue = unboxedValue;
4586 m_out.branch(
4587 isNotString(cellValue, provenType(m_node->child1())),
4588 unsure(lowBlock(data->fallThrough.block)), unsure(isStringCase));
4589
4590 m_out.appendTo(isStringCase, lastNext);
4591 stringValue = cellValue;
4592 break;
4593 }
4594
4595 default:
4596 DFG_CRASH(m_graph, m_node, "Bad use kind");
4597 break;
4598 }
4599
4600 LBasicBlock lengthIs1 = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar length is 1"));
4601 LBasicBlock needResolution = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar resolution"));
4602 LBasicBlock resolved = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar resolved"));
4603 LBasicBlock is8Bit = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar 8bit"));
4604 LBasicBlock is16Bit = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar 16bit"));
4605 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar continuation"));
4606
4607 m_out.branch(
4608 m_out.notEqual(
4609 m_out.load32NonNegative(stringValue, m_heaps.JSString_length),
4610 m_out.int32One),
4611 unsure(lowBlock(data->fallThrough.block)), unsure(lengthIs1));
4612
4613 LBasicBlock lastNext = m_out.appendTo(lengthIs1, needResolution);
4614 Vector<ValueFromBlock, 2> values;
4615 LValue fastValue = m_out.loadPtr(stringValue, m_heaps.JSString_value);
4616 values.append(m_out.anchor(fastValue));
4617 m_out.branch(m_out.isNull(fastValue), rarely(needResolution), usually(resolved));
4618
4619 m_out.appendTo(needResolution, resolved);
4620 values.append(m_out.anchor(
4621 vmCall(m_out.operation(operationResolveRope), m_callFrame, stringValue)));
4622 m_out.jump(resolved);
4623
4624 m_out.appendTo(resolved, is8Bit);
4625 LValue value = m_out.phi(m_out.intPtr, values);
4626 LValue characterData = m_out.loadPtr(value, m_heaps.StringImpl_data);
4627 m_out.branch(
4628 m_out.testNonZero32(
4629 m_out.load32(value, m_heaps.StringImpl_hashAndFlags),
4630 m_out.constInt32(StringImpl::flagIs8Bit())),
4631 unsure(is8Bit), unsure(is16Bit));
4632
4633 Vector<ValueFromBlock, 2> characters;
4634 m_out.appendTo(is8Bit, is16Bit);
4635 characters.append(m_out.anchor(
4636 m_out.zeroExt(m_out.load8(characterData, m_heaps.characters8[0]), m_out.int16)));
4637 m_out.jump(continuation);
4638
4639 m_out.appendTo(is16Bit, continuation);
4640 characters.append(m_out.anchor(m_out.load16(characterData, m_heaps.characters16[0])));
4641 m_out.jump(continuation);
4642
4643 m_out.appendTo(continuation, lastNext);
4644 buildSwitch(data, m_out.int16, m_out.phi(m_out.int16, characters));
4645 return;
4646 }
4647
4648 case SwitchString: {
4649 switch (m_node->child1().useKind()) {
4650 case StringIdentUse: {
4651 LValue stringImpl = lowStringIdent(m_node->child1());
4652
4653 Vector<SwitchCase> cases;
4654 for (unsigned i = 0; i < data->cases.size(); ++i) {
4655 LValue value = m_out.constIntPtr(data->cases[i].value.stringImpl());
4656 LBasicBlock block = lowBlock(data->cases[i].target.block);
4657 Weight weight = Weight(data->cases[i].target.count);
4658 cases.append(SwitchCase(value, block, weight));
4659 }
4660
4661 m_out.switchInstruction(
4662 stringImpl, cases, lowBlock(data->fallThrough.block),
4663 Weight(data->fallThrough.count));
4664 return;
4665 }
4666
4667 case StringUse: {
4668 switchString(data, lowString(m_node->child1()));
4669 return;
4670 }
4671
4672 case UntypedUse: {
4673 LValue value = lowJSValue(m_node->child1());
4674
4675 LBasicBlock isCellBlock = FTL_NEW_BLOCK(m_out, ("Switch/SwitchString Untyped cell case"));
4676 LBasicBlock isStringBlock = FTL_NEW_BLOCK(m_out, ("Switch/SwitchString Untyped string case"));
4677
4678 m_out.branch(
4679 isCell(value, provenType(m_node->child1())),
4680 unsure(isCellBlock), unsure(lowBlock(data->fallThrough.block)));
4681
4682 LBasicBlock lastNext = m_out.appendTo(isCellBlock, isStringBlock);
4683
4684 m_out.branch(
4685 isString(value, provenType(m_node->child1())),
4686 unsure(isStringBlock), unsure(lowBlock(data->fallThrough.block)));
4687
4688 m_out.appendTo(isStringBlock, lastNext);
4689
4690 switchString(data, value);
4691 return;
4692 }
4693
4694 default:
4695 DFG_CRASH(m_graph, m_node, "Bad use kind");
4696 return;
4697 }
4698 return;
4699 }
4700
4701 case SwitchCell: {
4702 LValue cell;
4703 switch (m_node->child1().useKind()) {
4704 case CellUse: {
4705 cell = lowCell(m_node->child1());
4706 break;
4707 }
4708
4709 case UntypedUse: {
4710 LValue value = lowJSValue(m_node->child1());
4711 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("Switch/SwitchCell cell case"));
4712 m_out.branch(
4713 isCell(value, provenType(m_node->child1())),
4714 unsure(cellCase), unsure(lowBlock(data->fallThrough.block)));
4715 m_out.appendTo(cellCase);
4716 cell = value;
4717 break;
4718 }
4719
4720 default:
4721 DFG_CRASH(m_graph, m_node, "Bad use kind");
4722 return;
4723 }
4724
4725 buildSwitch(m_node->switchData(), m_out.intPtr, cell);
4726 return;
4727 } }
4728
4729 DFG_CRASH(m_graph, m_node, "Bad switch kind");
4730 }
4731
4732 void compileReturn()
4733 {
4734 m_out.ret(lowJSValue(m_node->child1()));
4735 }
4736
4737 void compileForceOSRExit()
4738 {
4739 terminate(InadequateCoverage);
4740 }
4741
4742 void compileThrow()
4743 {
4744 terminate(Uncountable);
4745 }
4746
4747 void compileInvalidationPoint()
4748 {
4749 if (verboseCompilationEnabled())
4750 dataLog(" Invalidation point with availability: ", availabilityMap(), "\n");
4751
4752 m_ftlState.jitCode->osrExit.append(OSRExit(
4753 UncountableInvalidation, InvalidValueFormat, MethodOfGettingAValueProfile(),
4754 m_codeOriginForExitTarget, m_codeOriginForExitProfile,
4755 availabilityMap().m_locals.numberOfArguments(),
4756 availabilityMap().m_locals.numberOfLocals()));
4757 m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo());
4758
4759 OSRExit& exit = m_ftlState.jitCode->osrExit.last();
4760 OSRExitCompilationInfo& info = m_ftlState.finalizer->osrExit.last();
4761
4762 ExitArgumentList arguments;
4763
4764 buildExitArguments(exit, arguments, FormattedValue(), exit.m_codeOrigin);
4765 callStackmap(exit, arguments);
4766
4767 info.m_isInvalidationPoint = true;
4768 }
4769
4770 void compileIsUndefined()
4771 {
4772 setBoolean(equalNullOrUndefined(m_node->child1(), AllCellsAreFalse, EqualUndefined));
4773 }
4774
4775 void compileIsBoolean()
4776 {
4777 setBoolean(isBoolean(lowJSValue(m_node->child1()), provenType(m_node->child1())));
4778 }
4779
4780 void compileIsNumber()
4781 {
4782 setBoolean(isNumber(lowJSValue(m_node->child1()), provenType(m_node->child1())));
4783 }
4784
4785 void compileIsString()
4786 {
4787 LValue value = lowJSValue(m_node->child1());
4788
4789 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("IsString cell case"));
4790 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("IsString continuation"));
4791
4792 ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
4793 m_out.branch(
4794 isCell(value, provenType(m_node->child1())), unsure(isCellCase), unsure(continuation));
4795
4796 LBasicBlock lastNext = m_out.appendTo(isCellCase, continuation);
4797 ValueFromBlock cellResult = m_out.anchor(isString(value, provenType(m_node->child1())));
4798 m_out.jump(continuation);
4799
4800 m_out.appendTo(continuation, lastNext);
4801 setBoolean(m_out.phi(m_out.boolean, notCellResult, cellResult));
4802 }
4803
4804 void compileIsObject()
4805 {
4806 LValue value = lowJSValue(m_node->child1());
4807
4808 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("IsObject cell case"));
4809 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("IsObject continuation"));
4810
4811 ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
4812 m_out.branch(
4813 isCell(value, provenType(m_node->child1())), unsure(isCellCase), unsure(continuation));
4814
4815 LBasicBlock lastNext = m_out.appendTo(isCellCase, continuation);
4816 ValueFromBlock cellResult = m_out.anchor(isObject(value, provenType(m_node->child1())));
4817 m_out.jump(continuation);
4818
4819 m_out.appendTo(continuation, lastNext);
4820 setBoolean(m_out.phi(m_out.boolean, notCellResult, cellResult));
4821 }
4822
4823 void compileIsObjectOrNull()
4824 {
4825 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
4826
4827 Edge child = m_node->child1();
4828 LValue value = lowJSValue(child);
4829
4830 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull cell case"));
4831 LBasicBlock notFunctionCase = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull not function case"));
4832 LBasicBlock objectCase = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull object case"));
4833 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull slow path"));
4834 LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull not cell case"));
4835 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull continuation"));
4836
4837 m_out.branch(isCell(value, provenType(child)), unsure(cellCase), unsure(notCellCase));
4838
4839 LBasicBlock lastNext = m_out.appendTo(cellCase, notFunctionCase);
4840 ValueFromBlock isFunctionResult = m_out.anchor(m_out.booleanFalse);
4841 m_out.branch(
4842 isFunction(value, provenType(child)),
4843 unsure(continuation), unsure(notFunctionCase));
4844
4845 m_out.appendTo(notFunctionCase, objectCase);
4846 ValueFromBlock notObjectResult = m_out.anchor(m_out.booleanFalse);
4847 m_out.branch(
4848 isObject(value, provenType(child)),
4849 unsure(objectCase), unsure(continuation));
4850
4851 m_out.appendTo(objectCase, slowPath);
4852 ValueFromBlock objectResult = m_out.anchor(m_out.booleanTrue);
4853 m_out.branch(
4854 isExoticForTypeof(value, provenType(child)),
4855 rarely(slowPath), usually(continuation));
4856
4857 m_out.appendTo(slowPath, notCellCase);
4858 LValue slowResultValue = vmCall(
4859 m_out.operation(operationObjectIsObject), m_callFrame, weakPointer(globalObject),
4860 value);
4861 ValueFromBlock slowResult = m_out.anchor(m_out.notNull(slowResultValue));
4862 m_out.jump(continuation);
4863
4864 m_out.appendTo(notCellCase, continuation);
4865 LValue notCellResultValue = m_out.equal(value, m_out.constInt64(JSValue::encode(jsNull())));
4866 ValueFromBlock notCellResult = m_out.anchor(notCellResultValue);
4867 m_out.jump(continuation);
4868
4869 m_out.appendTo(continuation, lastNext);
4870 LValue result = m_out.phi(
4871 m_out.boolean,
4872 isFunctionResult, notObjectResult, objectResult, slowResult, notCellResult);
4873 setBoolean(result);
4874 }
4875
4876 void compileIsFunction()
4877 {
4878 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
4879
4880 Edge child = m_node->child1();
4881 LValue value = lowJSValue(child);
4882
4883 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("IsFunction cell case"));
4884 LBasicBlock notFunctionCase = FTL_NEW_BLOCK(m_out, ("IsFunction not function case"));
4885 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("IsFunction slow path"));
4886 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("IsFunction continuation"));
4887
4888 ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
4889 m_out.branch(
4890 isCell(value, provenType(child)), unsure(cellCase), unsure(continuation));
4891
4892 LBasicBlock lastNext = m_out.appendTo(cellCase, notFunctionCase);
4893 ValueFromBlock functionResult = m_out.anchor(m_out.booleanTrue);
4894 m_out.branch(
4895 isFunction(value, provenType(child)),
4896 unsure(continuation), unsure(notFunctionCase));
4897
4898 m_out.appendTo(notFunctionCase, slowPath);
4899 ValueFromBlock objectResult = m_out.anchor(m_out.booleanFalse);
4900 m_out.branch(
4901 isExoticForTypeof(value, provenType(child)),
4902 rarely(slowPath), usually(continuation));
4903
4904 m_out.appendTo(slowPath, continuation);
4905 LValue slowResultValue = vmCall(
4906 m_out.operation(operationObjectIsFunction), m_callFrame, weakPointer(globalObject),
4907 value);
4908 ValueFromBlock slowResult = m_out.anchor(m_out.notNull(slowResultValue));
4909 m_out.jump(continuation);
4910
4911 m_out.appendTo(continuation, lastNext);
4912 LValue result = m_out.phi(
4913 m_out.boolean, notCellResult, functionResult, objectResult, slowResult);
4914 setBoolean(result);
4915 }
4916
4917 void compileTypeOf()
4918 {
4919 Edge child = m_node->child1();
4920 LValue value = lowJSValue(child);
4921
4922 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("TypeOf continuation"));
4923 LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation);
4924
4925 Vector<ValueFromBlock> results;
4926
4927 buildTypeOf(
4928 child, value,
4929 [&] (TypeofType type) {
4930 results.append(m_out.anchor(weakPointer(vm().smallStrings.typeString(type))));
4931 m_out.jump(continuation);
4932 });
4933
4934 m_out.appendTo(continuation, lastNext);
4935 setJSValue(m_out.phi(m_out.int64, results));
4936 }
4937
4938 void compileIn()
4939 {
4940 Edge base = m_node->child2();
4941 LValue cell = lowCell(base);
4942 speculateObject(base, cell);
4943 if (JSString* string = m_node->child1()->dynamicCastConstant<JSString*>()) {
4944 if (string->tryGetValueImpl() && string->tryGetValueImpl()->isAtomic()) {
4945
4946 const auto str = static_cast<const AtomicStringImpl*>(string->tryGetValueImpl());
4947 unsigned stackmapID = m_stackmapIDs++;
4948
4949 LValue call = m_out.call(
4950 m_out.patchpointInt64Intrinsic(),
4951 m_out.constInt64(stackmapID), m_out.constInt32(sizeOfIn()),
4952 constNull(m_out.ref8), m_out.constInt32(1), cell);
4953
4954 setInstructionCallingConvention(call, LLVMAnyRegCallConv);
4955
4956 m_ftlState.checkIns.append(CheckInDescriptor(stackmapID, m_node->origin.semantic, str));
4957 setJSValue(call);
4958 return;
4959 }
4960 }
4961
4962 setJSValue(vmCall(m_out.operation(operationGenericIn), m_callFrame, cell, lowJSValue(m_node->child1())));
4963 }
4964
4965 void compileCheckHasInstance()
4966 {
4967 speculate(
4968 Uncountable, noValue(), 0,
4969 m_out.testIsZero8(
4970 m_out.load8(lowCell(m_node->child1()), m_heaps.JSCell_typeInfoFlags),
4971 m_out.constInt8(ImplementsDefaultHasInstance)));
4972 }
4973
4974 void compileInstanceOf()
4975 {
4976 LValue cell;
4977
4978 if (m_node->child1().useKind() == UntypedUse)
4979 cell = lowJSValue(m_node->child1());
4980 else
4981 cell = lowCell(m_node->child1());
4982
4983 LValue prototype = lowCell(m_node->child2());
4984
4985 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("InstanceOf cell case"));
4986 LBasicBlock loop = FTL_NEW_BLOCK(m_out, ("InstanceOf loop"));
4987 LBasicBlock notYetInstance = FTL_NEW_BLOCK(m_out, ("InstanceOf not yet instance"));
4988 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("InstanceOf continuation"));
4989
4990 LValue condition;
4991 if (m_node->child1().useKind() == UntypedUse)
4992 condition = isCell(cell, provenType(m_node->child1()));
4993 else
4994 condition = m_out.booleanTrue;
4995
4996 ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
4997 m_out.branch(condition, unsure(isCellCase), unsure(continuation));
4998
4999 LBasicBlock lastNext = m_out.appendTo(isCellCase, loop);
5000
5001 speculate(BadType, noValue(), 0, isNotObject(prototype, provenType(m_node->child2())));
5002
5003 ValueFromBlock originalValue = m_out.anchor(cell);
5004 m_out.jump(loop);
5005
5006 m_out.appendTo(loop, notYetInstance);
5007 LValue value = m_out.phi(m_out.int64, originalValue);
5008 LValue structure = loadStructure(value);
5009 LValue currentPrototype = m_out.load64(structure, m_heaps.Structure_prototype);
5010 ValueFromBlock isInstanceResult = m_out.anchor(m_out.booleanTrue);
5011 m_out.branch(
5012 m_out.equal(currentPrototype, prototype),
5013 unsure(continuation), unsure(notYetInstance));
5014
5015 m_out.appendTo(notYetInstance, continuation);
5016 ValueFromBlock notInstanceResult = m_out.anchor(m_out.booleanFalse);
5017 addIncoming(value, m_out.anchor(currentPrototype));
5018 m_out.branch(isCell(currentPrototype), unsure(loop), unsure(continuation));
5019
5020 m_out.appendTo(continuation, lastNext);
5021 setBoolean(
5022 m_out.phi(m_out.boolean, notCellResult, isInstanceResult, notInstanceResult));
5023 }
5024
5025 void compileCountExecution()
5026 {
5027 TypedPointer counter = m_out.absolute(m_node->executionCounter()->address());
5028 m_out.store64(m_out.add(m_out.load64(counter), m_out.constInt64(1)), counter);
5029 }
5030
5031 void compileStoreBarrier()
5032 {
5033 emitStoreBarrier(lowCell(m_node->child1()));
5034 }
5035
5036 void compileHasIndexedProperty()
5037 {
5038 switch (m_node->arrayMode().type()) {
5039 case Array::Int32:
5040 case Array::Contiguous: {
5041 LValue base = lowCell(m_node->child1());
5042 LValue index = lowInt32(m_node->child2());
5043 LValue storage = lowStorage(m_node->child3());
5044
5045 IndexedAbstractHeap& heap = m_node->arrayMode().type() == Array::Int32 ?
5046 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties;
5047
5048 LBasicBlock checkHole = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty int/contiguous check hole"));
5049 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty int/contiguous slow case"));
5050 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty int/contiguous continuation"));
5051
5052 if (!m_node->arrayMode().isInBounds()) {
5053 m_out.branch(
5054 m_out.aboveOrEqual(
5055 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
5056 rarely(slowCase), usually(checkHole));
5057 } else
5058 m_out.jump(checkHole);
5059
5060 LBasicBlock lastNext = m_out.appendTo(checkHole, slowCase);
5061 ValueFromBlock checkHoleResult = m_out.anchor(
5062 m_out.notZero64(m_out.load64(baseIndex(heap, storage, index, m_node->child2()))));
5063 m_out.branch(checkHoleResult.value(), usually(continuation), rarely(slowCase));
5064
5065 m_out.appendTo(slowCase, continuation);
5066 ValueFromBlock slowResult = m_out.anchor(m_out.equal(
5067 m_out.constInt64(JSValue::encode(jsBoolean(true))),
5068 vmCall(m_out.operation(operationHasIndexedProperty), m_callFrame, base, index)));
5069 m_out.jump(continuation);
5070
5071 m_out.appendTo(continuation, lastNext);
5072 setBoolean(m_out.phi(m_out.boolean, checkHoleResult, slowResult));
5073 return;
5074 }
5075 case Array::Double: {
5076 LValue base = lowCell(m_node->child1());
5077 LValue index = lowInt32(m_node->child2());
5078 LValue storage = lowStorage(m_node->child3());
5079
5080 IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties;
5081
5082 LBasicBlock checkHole = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty double check hole"));
5083 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty double slow case"));
5084 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty double continuation"));
5085
5086 if (!m_node->arrayMode().isInBounds()) {
5087 m_out.branch(
5088 m_out.aboveOrEqual(
5089 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
5090 rarely(slowCase), usually(checkHole));
5091 } else
5092 m_out.jump(checkHole);
5093
5094 LBasicBlock lastNext = m_out.appendTo(checkHole, slowCase);
5095 LValue doubleValue = m_out.loadDouble(baseIndex(heap, storage, index, m_node->child2()));
5096 ValueFromBlock checkHoleResult = m_out.anchor(m_out.doubleEqual(doubleValue, doubleValue));
5097 m_out.branch(checkHoleResult.value(), usually(continuation), rarely(slowCase));
5098
5099 m_out.appendTo(slowCase, continuation);
5100 ValueFromBlock slowResult = m_out.anchor(m_out.equal(
5101 m_out.constInt64(JSValue::encode(jsBoolean(true))),
5102 vmCall(m_out.operation(operationHasIndexedProperty), m_callFrame, base, index)));
5103 m_out.jump(continuation);
5104
5105 m_out.appendTo(continuation, lastNext);
5106 setBoolean(m_out.phi(m_out.boolean, checkHoleResult, slowResult));
5107 return;
5108 }
5109
5110 default:
5111 RELEASE_ASSERT_NOT_REACHED();
5112 return;
5113 }
5114 }
5115
5116 void compileHasGenericProperty()
5117 {
5118 LValue base = lowJSValue(m_node->child1());
5119 LValue property = lowCell(m_node->child2());
5120 setJSValue(vmCall(m_out.operation(operationHasGenericProperty), m_callFrame, base, property));
5121 }
5122
5123 void compileHasStructureProperty()
5124 {
5125 LValue base = lowJSValue(m_node->child1());
5126 LValue property = lowString(m_node->child2());
5127 LValue enumerator = lowCell(m_node->child3());
5128
5129 LBasicBlock correctStructure = FTL_NEW_BLOCK(m_out, ("HasStructureProperty correct structure"));
5130 LBasicBlock wrongStructure = FTL_NEW_BLOCK(m_out, ("HasStructureProperty wrong structure"));
5131 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("HasStructureProperty continuation"));
5132
5133 m_out.branch(m_out.notEqual(
5134 m_out.load32(base, m_heaps.JSCell_structureID),
5135 m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)),
5136 rarely(wrongStructure), usually(correctStructure));
5137
5138 LBasicBlock lastNext = m_out.appendTo(correctStructure, wrongStructure);
5139 ValueFromBlock correctStructureResult = m_out.anchor(m_out.booleanTrue);
5140 m_out.jump(continuation);
5141
5142 m_out.appendTo(wrongStructure, continuation);
5143 ValueFromBlock wrongStructureResult = m_out.anchor(
5144 m_out.equal(
5145 m_out.constInt64(JSValue::encode(jsBoolean(true))),
5146 vmCall(m_out.operation(operationHasGenericProperty), m_callFrame, base, property)));
5147 m_out.jump(continuation);
5148
5149 m_out.appendTo(continuation, lastNext);
5150 setBoolean(m_out.phi(m_out.boolean, correctStructureResult, wrongStructureResult));
5151 }
5152
5153 void compileGetDirectPname()
5154 {
5155 LValue base = lowCell(m_graph.varArgChild(m_node, 0));
5156 LValue property = lowCell(m_graph.varArgChild(m_node, 1));
5157 LValue index = lowInt32(m_graph.varArgChild(m_node, 2));
5158 LValue enumerator = lowCell(m_graph.varArgChild(m_node, 3));
5159
5160 LBasicBlock checkOffset = FTL_NEW_BLOCK(m_out, ("GetDirectPname check offset"));
5161 LBasicBlock inlineLoad = FTL_NEW_BLOCK(m_out, ("GetDirectPname inline load"));
5162 LBasicBlock outOfLineLoad = FTL_NEW_BLOCK(m_out, ("GetDirectPname out-of-line load"));
5163 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetDirectPname slow case"));
5164 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetDirectPname continuation"));
5165
5166 m_out.branch(m_out.notEqual(
5167 m_out.load32(base, m_heaps.JSCell_structureID),
5168 m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)),
5169 rarely(slowCase), usually(checkOffset));
5170
5171 LBasicBlock lastNext = m_out.appendTo(checkOffset, inlineLoad);
5172 m_out.branch(m_out.aboveOrEqual(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedInlineCapacity)),
5173 unsure(outOfLineLoad), unsure(inlineLoad));
5174
5175 m_out.appendTo(inlineLoad, outOfLineLoad);
5176 ValueFromBlock inlineResult = m_out.anchor(
5177 m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(),
5178 base, m_out.zeroExt(index, m_out.int64), ScaleEight, JSObject::offsetOfInlineStorage())));
5179 m_out.jump(continuation);
5180
5181 m_out.appendTo(outOfLineLoad, slowCase);
5182 LValue storage = m_out.loadPtr(base, m_heaps.JSObject_butterfly);
5183 LValue realIndex = m_out.signExt(
5184 m_out.neg(m_out.sub(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedInlineCapacity))),
5185 m_out.int64);
5186 int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
5187 ValueFromBlock outOfLineResult = m_out.anchor(
5188 m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(), storage, realIndex, ScaleEight, offsetOfFirstProperty)));
5189 m_out.jump(continuation);
5190
5191 m_out.appendTo(slowCase, continuation);
5192 ValueFromBlock slowCaseResult = m_out.anchor(
5193 vmCall(m_out.operation(operationGetByVal), m_callFrame, base, property));
5194 m_out.jump(continuation);
5195
5196 m_out.appendTo(continuation, lastNext);
5197 setJSValue(m_out.phi(m_out.int64, inlineResult, outOfLineResult, slowCaseResult));
5198 }
5199
5200 void compileGetEnumerableLength()
5201 {
5202 LValue enumerator = lowCell(m_node->child1());
5203 setInt32(m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_indexLength));
5204 }
5205
5206 void compileGetPropertyEnumerator()
5207 {
5208 LValue base = lowCell(m_node->child1());
5209 setJSValue(vmCall(m_out.operation(operationGetPropertyEnumerator), m_callFrame, base));
5210 }
5211
5212 void compileGetEnumeratorStructurePname()
5213 {
5214 LValue enumerator = lowCell(m_node->child1());
5215 LValue index = lowInt32(m_node->child2());
5216
5217 LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorStructurePname in bounds"));
5218 LBasicBlock outOfBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorStructurePname out of bounds"));
5219 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetEnumeratorStructurePname continuation"));
5220
5221 m_out.branch(m_out.below(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_endStructurePropertyIndex)),
5222 usually(inBounds), rarely(outOfBounds));
5223
5224 LBasicBlock lastNext = m_out.appendTo(inBounds, outOfBounds);
5225 LValue storage = m_out.loadPtr(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector);
5226 ValueFromBlock inBoundsResult = m_out.anchor(
5227 m_out.loadPtr(m_out.baseIndex(m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVectorContents, storage, m_out.zeroExtPtr(index))));
5228 m_out.jump(continuation);
5229
5230 m_out.appendTo(outOfBounds, continuation);
5231 ValueFromBlock outOfBoundsResult = m_out.anchor(m_out.constInt64(ValueNull));
5232 m_out.jump(continuation);
5233
5234 m_out.appendTo(continuation, lastNext);
5235 setJSValue(m_out.phi(m_out.int64, inBoundsResult, outOfBoundsResult));
5236 }
5237
5238 void compileGetEnumeratorGenericPname()
5239 {
5240 LValue enumerator = lowCell(m_node->child1());
5241 LValue index = lowInt32(m_node->child2());
5242
5243 LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorGenericPname in bounds"));
5244 LBasicBlock outOfBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorGenericPname out of bounds"));
5245 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetEnumeratorGenericPname continuation"));
5246
5247 m_out.branch(m_out.below(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_endGenericPropertyIndex)),
5248 usually(inBounds), rarely(outOfBounds));
5249
5250 LBasicBlock lastNext = m_out.appendTo(inBounds, outOfBounds);
5251 LValue storage = m_out.loadPtr(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector);
5252 ValueFromBlock inBoundsResult = m_out.anchor(
5253 m_out.loadPtr(m_out.baseIndex(m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVectorContents, storage, m_out.zeroExtPtr(index))));
5254 m_out.jump(continuation);
5255
5256 m_out.appendTo(outOfBounds, continuation);
5257 ValueFromBlock outOfBoundsResult = m_out.anchor(m_out.constInt64(ValueNull));
5258 m_out.jump(continuation);
5259
5260 m_out.appendTo(continuation, lastNext);
5261 setJSValue(m_out.phi(m_out.int64, inBoundsResult, outOfBoundsResult));
5262 }
5263
5264 void compileToIndexString()
5265 {
5266 LValue index = lowInt32(m_node->child1());
5267 setJSValue(vmCall(m_out.operation(operationToIndexString), m_callFrame, index));
5268 }
5269
5270 void compileCheckStructureImmediate()
5271 {
5272 LValue structure = lowCell(m_node->child1());
5273 checkStructure(
5274 structure, noValue(), BadCache, m_node->structureSet(),
5275 [this] (Structure* structure) {
5276 return weakStructure(structure);
5277 });
5278 }
5279
5280 void compileMaterializeNewObject()
5281 {
5282 ObjectMaterializationData& data = m_node->objectMaterializationData();
5283
5284 // Lower the values first, to avoid creating values inside a control flow diamond.
5285
5286 Vector<LValue, 8> values;
5287 for (unsigned i = 0; i < data.m_properties.size(); ++i)
5288 values.append(lowJSValue(m_graph.varArgChild(m_node, 1 + i)));
5289
5290 StructureSet set;
5291 m_interpreter.phiChildren()->forAllTransitiveIncomingValues(
5292 m_graph.varArgChild(m_node, 0).node(),
5293 [&] (Node* incoming) {
5294 set.add(incoming->castConstant<Structure*>());
5295 });
5296
5297 Vector<LBasicBlock, 1> blocks(set.size());
5298 for (unsigned i = set.size(); i--;)
5299 blocks[i] = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject case ", i));
5300 LBasicBlock dummyDefault = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject default case"));
5301 LBasicBlock outerContinuation = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject continuation"));
5302
5303 Vector<SwitchCase, 1> cases(set.size());
5304 for (unsigned i = set.size(); i--;)
5305 cases[i] = SwitchCase(weakStructure(set[i]), blocks[i], Weight(1));
5306 m_out.switchInstruction(
5307 lowCell(m_graph.varArgChild(m_node, 0)), cases, dummyDefault, Weight(0));
5308
5309 LBasicBlock outerLastNext = m_out.m_nextBlock;
5310
5311 Vector<ValueFromBlock, 1> results;
5312
5313 for (unsigned i = set.size(); i--;) {
5314 m_out.appendTo(blocks[i], i + 1 < set.size() ? blocks[i + 1] : dummyDefault);
5315
5316 Structure* structure = set[i];
5317
5318 LValue object;
5319 LValue butterfly;
5320
5321 if (structure->outOfLineCapacity()) {
5322 size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity());
5323 MarkedAllocator* allocator = &vm().heap.allocatorForObjectWithoutDestructor(allocationSize);
5324
5325 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject complex object allocation slow path"));
5326 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject complex object allocation continuation"));
5327
5328 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
5329
5330 LValue endOfStorage = allocateBasicStorageAndGetEnd(
5331 m_out.constIntPtr(structure->outOfLineCapacity() * sizeof(JSValue)),
5332 slowPath);
5333
5334 LValue fastButterflyValue = m_out.add(
5335 m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage);
5336
5337 LValue fastObjectValue = allocateObject(
5338 m_out.constIntPtr(allocator), structure, fastButterflyValue, slowPath);
5339
5340 ValueFromBlock fastObject = m_out.anchor(fastObjectValue);
5341 ValueFromBlock fastButterfly = m_out.anchor(fastButterflyValue);
5342 m_out.jump(continuation);
5343
5344 m_out.appendTo(slowPath, continuation);
5345
5346 ValueFromBlock slowObject = m_out.anchor(vmCall(
5347 m_out.operation(operationNewObjectWithButterfly),
5348 m_callFrame, m_out.constIntPtr(structure)));
5349 ValueFromBlock slowButterfly = m_out.anchor(
5350 m_out.loadPtr(slowObject.value(), m_heaps.JSObject_butterfly));
5351
5352 m_out.jump(continuation);
5353
5354 m_out.appendTo(continuation, lastNext);
5355
5356 object = m_out.phi(m_out.intPtr, fastObject, slowObject);
5357 butterfly = m_out.phi(m_out.intPtr, fastButterfly, slowButterfly);
5358 } else {
5359 // In the easy case where we can do a one-shot allocation, we simply allocate the
5360 // object to directly have the desired structure.
5361 object = allocateObject(structure);
5362 butterfly = nullptr; // Don't have one, don't need one.
5363 }
5364
5365 for (PropertyMapEntry entry : structure->getPropertiesConcurrently()) {
5366 for (unsigned i = data.m_properties.size(); i--;) {
5367 PhantomPropertyValue value = data.m_properties[i];
5368 if (m_graph.identifiers()[value.m_identifierNumber] != entry.key)
5369 continue;
5370
5371 LValue base = isInlineOffset(entry.offset) ? object : butterfly;
5372 storeProperty(values[i], base, value.m_identifierNumber, entry.offset);
5373 break;
5374 }
5375 }
5376
5377 results.append(m_out.anchor(object));
5378 m_out.jump(outerContinuation);
5379 }
5380
5381 m_out.appendTo(dummyDefault, outerContinuation);
5382 m_out.unreachable();
5383
5384 m_out.appendTo(outerContinuation, outerLastNext);
5385 setJSValue(m_out.phi(m_out.intPtr, results));
5386 }
5387
5388 void compileMaterializeCreateActivation()
5389 {
5390 ObjectMaterializationData& data = m_node->objectMaterializationData();
5391
5392 Vector<LValue, 8> values;
5393 for (unsigned i = 0; i < data.m_properties.size(); ++i)
5394 values.append(lowJSValue(m_graph.varArgChild(m_node, 1 + i)));
5395
5396 LValue scope = lowCell(m_graph.varArgChild(m_node, 0));
5397 SymbolTable* table = m_node->castOperand<SymbolTable*>();
5398 Structure* structure = m_graph.globalObjectFor(m_node->origin.semantic)->activationStructure();
5399
5400 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("MaterializeCreateActivation slow path"));
5401 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MaterializeCreateActivation continuation"));
5402
5403 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
5404
5405 LValue fastObject = allocateObject<JSLexicalEnvironment>(
5406 JSLexicalEnvironment::allocationSize(table), structure, m_out.intPtrZero, slowPath);
5407
5408 m_out.storePtr(scope, fastObject, m_heaps.JSScope_next);
5409 m_out.storePtr(weakPointer(table), fastObject, m_heaps.JSSymbolTableObject_symbolTable);
5410
5411
5412 ValueFromBlock fastResult = m_out.anchor(fastObject);
5413 m_out.jump(continuation);
5414
5415 m_out.appendTo(slowPath, continuation);
5416 LValue callResult = vmCall(
5417 m_out.operation(operationCreateActivationDirect), m_callFrame, weakPointer(structure),
5418 scope, weakPointer(table));
5419 ValueFromBlock slowResult = m_out.anchor(callResult);
5420 m_out.jump(continuation);
5421
5422 m_out.appendTo(continuation, lastNext);
5423 LValue activation = m_out.phi(m_out.intPtr, fastResult, slowResult);
5424 RELEASE_ASSERT(data.m_properties.size() == table->scopeSize());
5425 for (unsigned i = 0; i < data.m_properties.size(); ++i) {
5426 m_out.store64(values[i],
5427 activation,
5428 m_heaps.JSEnvironmentRecord_variables[data.m_properties[i].m_identifierNumber]);
5429 }
5430
5431 if (validationEnabled()) {
5432 // Validate to make sure every slot in the scope has one value.
5433 ConcurrentJITLocker locker(table->m_lock);
5434 for (auto iter = table->begin(locker), end = table->end(locker); iter != end; ++iter) {
5435 bool found = false;
5436 for (unsigned i = 0; i < data.m_properties.size(); ++i) {
5437 if (iter->value.scopeOffset().offset() == data.m_properties[i].m_identifierNumber) {
5438 found = true;
5439 break;
5440 }
5441 }
5442 ASSERT_UNUSED(found, found);
5443 }
5444 }
5445
5446 setJSValue(activation);
5447 }
5448
5449#if ENABLE(FTL_NATIVE_CALL_INLINING)
5450 LValue getFunctionBySymbol(const CString symbol)
5451 {
5452 if (!m_ftlState.symbolTable.contains(symbol))
5453 return nullptr;
5454 if (!getModuleByPathForSymbol(m_ftlState.symbolTable.get(symbol), symbol))
5455 return nullptr;
5456 return getNamedFunction(m_ftlState.module, symbol.data());
5457 }
5458
5459 bool getModuleByPathForSymbol(const CString path, const CString symbol)
5460 {
5461 if (m_ftlState.nativeLoadedLibraries.contains(path)) {
5462 LValue function = getNamedFunction(m_ftlState.module, symbol.data());
5463 if (!isInlinableSize(function)) {
5464 // We had no choice but to compile this function, but don't try to inline it ever again.
5465 m_ftlState.symbolTable.remove(symbol);
5466 return false;
5467 }
5468 return true;
5469 }
5470
5471 LMemoryBuffer memBuf;
5472
5473 ASSERT(isX86() || isARM64());
5474
5475#if PLATFORM(EFL)
5476 const CString actualPath = toCString(bundlePath().data(), "/runtime/", path.data());
5477#else
5478 const CString actualPath = toCString(bundlePath().data(),
5479 isX86() ? "/Resources/Runtime/x86_64/" : "/Resources/Runtime/arm64/",
5480 path.data());
5481#endif
5482
5483 char* outMsg;
5484
5485 if (createMemoryBufferWithContentsOfFile(actualPath.data(), &memBuf, &outMsg)) {
5486 if (Options::verboseFTLFailure())
5487 dataLog("Failed to load module at ", actualPath, "\n for symbol ", symbol, "\nERROR: ", outMsg, "\n");
5488 disposeMessage(outMsg);
5489 return false;
5490 }
5491
5492 LModule module;
5493
5494 if (parseBitcodeInContext(m_ftlState.context, memBuf, &module, &outMsg)) {
5495 if (Options::verboseFTLFailure())
5496 dataLog("Failed to parse module at ", actualPath, "\n for symbol ", symbol, "\nERROR: ", outMsg, "\n");
5497 disposeMemoryBuffer(memBuf);
5498 disposeMessage(outMsg);
5499 return false;
5500 }
5501
5502 disposeMemoryBuffer(memBuf);
5503
5504 if (LValue function = getNamedFunction(m_ftlState.module, symbol.data())) {
5505 if (!isInlinableSize(function)) {
5506 m_ftlState.symbolTable.remove(symbol);
5507 disposeModule(module);
5508 return false;
5509 }
5510 }
5511
5512 Vector<CString> namedFunctions;
5513 for (LValue function = getFirstFunction(module); function; function = getNextFunction(function)) {
5514 CString functionName(getValueName(function));
5515 namedFunctions.append(functionName);
5516
5517 for (LBasicBlock basicBlock = getFirstBasicBlock(function); basicBlock; basicBlock = getNextBasicBlock(basicBlock)) {
5518 for (LValue instruction = getFirstInstruction(basicBlock); instruction; instruction = getNextInstruction(instruction)) {
5519 setMetadata(instruction, m_tbaaKind, nullptr);
5520 setMetadata(instruction, m_tbaaStructKind, nullptr);
5521 }
5522 }
5523 }
5524
5525 Vector<CString> namedGlobals;
5526 for (LValue global = getFirstGlobal(module); global; global = getNextGlobal(global)) {
5527 CString globalName(getValueName(global));
5528 namedGlobals.append(globalName);
5529 }
5530
5531 if (linkModules(m_ftlState.module, module, LLVMLinkerDestroySource, &outMsg)) {
5532 if (Options::verboseFTLFailure())
5533 dataLog("Failed to link module at ", actualPath, "\n for symbol ", symbol, "\nERROR: ", outMsg, "\n");
5534 disposeMessage(outMsg);
5535 return false;
5536 }
5537
5538 for (CString* symbol = namedFunctions.begin(); symbol != namedFunctions.end(); ++symbol) {
5539 LValue function = getNamedFunction(m_ftlState.module, symbol->data());
5540 LLVMLinkage linkage = getLinkage(function);
5541 if (linkage != LLVMInternalLinkage && linkage != LLVMPrivateLinkage)
5542 setVisibility(function, LLVMHiddenVisibility);
5543 if (!isDeclaration(function)) {
5544 setLinkage(function, LLVMPrivateLinkage);
5545 setLinkage(function, LLVMAvailableExternallyLinkage);
5546
5547 if (ASSERT_DISABLED)
5548 removeFunctionAttr(function, LLVMStackProtectAttribute);
5549 }
5550 }
5551
5552 for (CString* symbol = namedGlobals.begin(); symbol != namedGlobals.end(); ++symbol) {
5553 LValue global = getNamedGlobal(m_ftlState.module, symbol->data());
5554 LLVMLinkage linkage = getLinkage(global);
5555 if (linkage != LLVMInternalLinkage && linkage != LLVMPrivateLinkage)
5556 setVisibility(global, LLVMHiddenVisibility);
5557 if (!isDeclaration(global))
5558 setLinkage(global, LLVMPrivateLinkage);
5559 }
5560
5561 m_ftlState.nativeLoadedLibraries.add(path);
5562 return true;
5563 }
5564#endif
5565
5566 bool isInlinableSize(LValue function)
5567 {
5568 size_t instructionCount = 0;
5569 size_t maxSize = Options::maximumLLVMInstructionCountForNativeInlining();
5570 for (LBasicBlock basicBlock = getFirstBasicBlock(function); basicBlock; basicBlock = getNextBasicBlock(basicBlock)) {
5571 for (LValue instruction = getFirstInstruction(basicBlock); instruction; instruction = getNextInstruction(instruction)) {
5572 if (++instructionCount >= maxSize)
5573 return false;
5574 }
5575 }
5576 return true;
5577 }
5578
5579 LValue didOverflowStack()
5580 {
5581 // This does a very simple leaf function analysis. The invariant of FTL call
5582 // frames is that the caller had already done enough of a stack check to
5583 // prove that this call frame has enough stack to run, and also enough stack
5584 // to make runtime calls. So, we only need to stack check when making calls
5585 // to other JS functions. If we don't find such calls then we don't need to
5586 // do any stack checks.
5587
5588 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
5589 BasicBlock* block = m_graph.block(blockIndex);
5590 if (!block)
5591 continue;
5592
5593 for (unsigned nodeIndex = block->size(); nodeIndex--;) {
5594 Node* node = block->at(nodeIndex);
5595
5596 switch (node->op()) {
5597 case GetById:
5598 case PutById:
5599 case Call:
5600 case Construct:
5601 case NativeCall:
5602 case NativeConstruct:
5603 return m_out.below(
5604 m_callFrame,
5605 m_out.loadPtr(
5606 m_out.absolute(vm().addressOfFTLStackLimit())));
5607
5608 default:
5609 break;
5610 }
5611 }
5612 }
5613
5614 return m_out.booleanFalse;
5615 }
5616
5617 struct ArgumentsLength {
5618 ArgumentsLength()
5619 : isKnown(false)
5620 , known(UINT_MAX)
5621 , value(nullptr)
5622 {
5623 }
5624
5625 bool isKnown;
5626 unsigned known;
5627 LValue value;
5628 };
5629 ArgumentsLength getArgumentsLength(InlineCallFrame* inlineCallFrame)
5630 {
5631 ArgumentsLength length;
5632
5633 if (inlineCallFrame && !inlineCallFrame->isVarargs()) {
5634 length.known = inlineCallFrame->arguments.size() - 1;
5635 length.isKnown = true;
5636 length.value = m_out.constInt32(length.known);
5637 } else {
5638 length.known = UINT_MAX;
5639 length.isKnown = false;
5640
5641 VirtualRegister argumentCountRegister;
5642 if (!inlineCallFrame)
5643 argumentCountRegister = VirtualRegister(JSStack::ArgumentCount);
5644 else
5645 argumentCountRegister = inlineCallFrame->argumentCountRegister;
5646 length.value = m_out.sub(m_out.load32(payloadFor(argumentCountRegister)), m_out.int32One);
5647 }
5648
5649 return length;
5650 }
5651
5652 ArgumentsLength getArgumentsLength()
5653 {
5654 return getArgumentsLength(m_node->origin.semantic.inlineCallFrame);
5655 }
5656
5657 LValue getCurrentCallee()
5658 {
5659 if (InlineCallFrame* frame = m_node->origin.semantic.inlineCallFrame) {
5660 if (frame->isClosureCall)
5661 return m_out.loadPtr(addressFor(frame->calleeRecovery.virtualRegister()));
5662 return weakPointer(frame->calleeRecovery.constant().asCell());
5663 }
5664 return m_out.loadPtr(addressFor(JSStack::Callee));
5665 }
5666
5667 LValue getArgumentsStart(InlineCallFrame* inlineCallFrame)
5668 {
5669 VirtualRegister start = AssemblyHelpers::argumentsStart(inlineCallFrame);
5670 return addressFor(start).value();
5671 }
5672
5673 LValue getArgumentsStart()
5674 {
5675 return getArgumentsStart(m_node->origin.semantic.inlineCallFrame);
5676 }
5677
5678 template<typename Functor>
5679 void checkStructure(
5680 LValue structureDiscriminant, const FormattedValue& formattedValue, ExitKind exitKind,
5681 const StructureSet& set, const Functor& weakStructureDiscriminant)
5682 {
5683 if (set.size() == 1) {
5684 speculate(
5685 exitKind, formattedValue, 0,
5686 m_out.notEqual(structureDiscriminant, weakStructureDiscriminant(set[0])));
5687 return;
5688 }
5689
5690 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("checkStructure continuation"));
5691
5692 LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation);
5693 for (unsigned i = 0; i < set.size() - 1; ++i) {
5694 LBasicBlock nextStructure = FTL_NEW_BLOCK(m_out, ("checkStructure nextStructure"));
5695 m_out.branch(
5696 m_out.equal(structureDiscriminant, weakStructureDiscriminant(set[i])),
5697 unsure(continuation), unsure(nextStructure));
5698 m_out.appendTo(nextStructure);
5699 }
5700
5701 speculate(
5702 exitKind, formattedValue, 0,
5703 m_out.notEqual(structureDiscriminant, weakStructureDiscriminant(set.last())));
5704
5705 m_out.jump(continuation);
5706 m_out.appendTo(continuation, lastNext);
5707 }
5708
5709 LValue numberOrNotCellToInt32(Edge edge, LValue value)
5710 {
5711 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 int case"));
5712 LBasicBlock notIntCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 not int case"));
5713 LBasicBlock doubleCase = 0;
5714 LBasicBlock notNumberCase = 0;
5715 if (edge.useKind() == NotCellUse) {
5716 doubleCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 double case"));
5717 notNumberCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 not number case"));
5718 }
5719 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ValueToInt32 continuation"));
5720
5721 Vector<ValueFromBlock> results;
5722
5723 m_out.branch(isNotInt32(value), unsure(notIntCase), unsure(intCase));
5724
5725 LBasicBlock lastNext = m_out.appendTo(intCase, notIntCase);
5726 results.append(m_out.anchor(unboxInt32(value)));
5727 m_out.jump(continuation);
5728
5729 if (edge.useKind() == NumberUse) {
5730 m_out.appendTo(notIntCase, continuation);
5731 FTL_TYPE_CHECK(jsValueValue(value), edge, SpecBytecodeNumber, isCellOrMisc(value));
5732 results.append(m_out.anchor(doubleToInt32(unboxDouble(value))));
5733 m_out.jump(continuation);
5734 } else {
5735 m_out.appendTo(notIntCase, doubleCase);
5736 m_out.branch(
5737 isCellOrMisc(value, provenType(edge)), unsure(notNumberCase), unsure(doubleCase));
5738
5739 m_out.appendTo(doubleCase, notNumberCase);
5740 results.append(m_out.anchor(doubleToInt32(unboxDouble(value))));
5741 m_out.jump(continuation);
5742
5743 m_out.appendTo(notNumberCase, continuation);
5744
5745 FTL_TYPE_CHECK(jsValueValue(value), edge, ~SpecCell, isCell(value));
5746
5747 LValue specialResult = m_out.select(
5748 m_out.equal(value, m_out.constInt64(JSValue::encode(jsBoolean(true)))),
5749 m_out.int32One, m_out.int32Zero);
5750 results.append(m_out.anchor(specialResult));
5751 m_out.jump(continuation);
5752 }
5753
5754 m_out.appendTo(continuation, lastNext);
5755 return m_out.phi(m_out.int32, results);
5756 }
5757
5758 LValue loadProperty(LValue storage, unsigned identifierNumber, PropertyOffset offset)
5759 {
5760 return m_out.load64(addressOfProperty(storage, identifierNumber, offset));
5761 }
5762
5763 void storeProperty(
5764 LValue value, LValue storage, unsigned identifierNumber, PropertyOffset offset)
5765 {
5766 m_out.store64(value, addressOfProperty(storage, identifierNumber, offset));
5767 }
5768
5769 TypedPointer addressOfProperty(
5770 LValue storage, unsigned identifierNumber, PropertyOffset offset)
5771 {
5772 return m_out.address(
5773 m_heaps.properties[identifierNumber], storage, offsetRelativeToBase(offset));
5774 }
5775
5776 LValue storageForTransition(
5777 LValue object, PropertyOffset offset,
5778 Structure* previousStructure, Structure* nextStructure)
5779 {
5780 if (isInlineOffset(offset))
5781 return object;
5782
5783 if (previousStructure->outOfLineCapacity() == nextStructure->outOfLineCapacity())
5784 return m_out.loadPtr(object, m_heaps.JSObject_butterfly);
5785
5786 LValue result;
5787 if (!previousStructure->outOfLineCapacity())
5788 result = allocatePropertyStorage(object, previousStructure);
5789 else {
5790 result = reallocatePropertyStorage(
5791 object, m_out.loadPtr(object, m_heaps.JSObject_butterfly),
5792 previousStructure, nextStructure);
5793 }
5794
5795 emitStoreBarrier(object);
5796
5797 return result;
5798 }
5799
5800 LValue allocatePropertyStorage(LValue object, Structure* previousStructure)
5801 {
5802 if (previousStructure->couldHaveIndexingHeader()) {
5803 return vmCall(
5804 m_out.operation(
5805 operationReallocateButterflyToHavePropertyStorageWithInitialCapacity),
5806 m_callFrame, object);
5807 }
5808
5809 LValue result = allocatePropertyStorageWithSizeImpl(initialOutOfLineCapacity);
5810 m_out.storePtr(result, object, m_heaps.JSObject_butterfly);
5811 return result;
5812 }
5813
5814 LValue reallocatePropertyStorage(
5815 LValue object, LValue oldStorage, Structure* previous, Structure* next)
5816 {
5817 size_t oldSize = previous->outOfLineCapacity();
5818 size_t newSize = oldSize * outOfLineGrowthFactor;
5819
5820 ASSERT_UNUSED(next, newSize == next->outOfLineCapacity());
5821
5822 if (previous->couldHaveIndexingHeader()) {
5823 LValue newAllocSize = m_out.constIntPtr(newSize);
5824 return vmCall(m_out.operation(operationReallocateButterflyToGrowPropertyStorage), m_callFrame, object, newAllocSize);
5825 }
5826
5827 LValue result = allocatePropertyStorageWithSizeImpl(newSize);
5828
5829 ptrdiff_t headerSize = -sizeof(IndexingHeader) - sizeof(void*);
5830 ptrdiff_t endStorage = headerSize - static_cast<ptrdiff_t>(oldSize * sizeof(JSValue));
5831
5832 for (ptrdiff_t offset = headerSize; offset > endStorage; offset -= sizeof(void*)) {
5833 LValue loaded =
5834 m_out.loadPtr(m_out.address(m_heaps.properties.atAnyNumber(), oldStorage, offset));
5835 m_out.storePtr(loaded, m_out.address(m_heaps.properties.atAnyNumber(), result, offset));
5836 }
5837
5838 m_out.storePtr(result, m_out.address(object, m_heaps.JSObject_butterfly));
5839
5840 return result;
5841 }
5842
5843 LValue allocatePropertyStorageWithSizeImpl(size_t sizeInValues)
5844 {
5845 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorageWithSizeImpl slow path"));
5846 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorageWithSizeImpl continuation"));
5847
5848 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
5849
5850 LValue endOfStorage = allocateBasicStorageAndGetEnd(
5851 m_out.constIntPtr(sizeInValues * sizeof(JSValue)), slowPath);
5852
5853 ValueFromBlock fastButterfly = m_out.anchor(
5854 m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage));
5855
5856 m_out.jump(continuation);
5857
5858 m_out.appendTo(slowPath, continuation);
5859
5860 LValue slowButterflyValue;
5861 if (sizeInValues == initialOutOfLineCapacity) {
5862 slowButterflyValue = vmCall(
5863 m_out.operation(operationAllocatePropertyStorageWithInitialCapacity),
5864 m_callFrame);
5865 } else {
5866 slowButterflyValue = vmCall(
5867 m_out.operation(operationAllocatePropertyStorage),
5868 m_callFrame, m_out.constIntPtr(sizeInValues));
5869 }
5870 ValueFromBlock slowButterfly = m_out.anchor(slowButterflyValue);
5871
5872 m_out.jump(continuation);
5873
5874 m_out.appendTo(continuation, lastNext);
5875
5876 return m_out.phi(m_out.intPtr, fastButterfly, slowButterfly);
5877 }
5878
5879 LValue getById(LValue base)
5880 {
5881 auto uid = m_graph.identifiers()[m_node->identifierNumber()];
5882
5883 // Arguments: id, bytes, target, numArgs, args...
5884 unsigned stackmapID = m_stackmapIDs++;
5885
5886 if (Options::verboseCompilation())
5887 dataLog(" Emitting GetById patchpoint with stackmap #", stackmapID, "\n");
5888
5889 LValue call = m_out.call(
5890 m_out.patchpointInt64Intrinsic(),
5891 m_out.constInt64(stackmapID), m_out.constInt32(sizeOfGetById()),
5892 constNull(m_out.ref8), m_out.constInt32(1), base);
5893 setInstructionCallingConvention(call, LLVMAnyRegCallConv);
5894
5895 m_ftlState.getByIds.append(GetByIdDescriptor(stackmapID, m_node->origin.semantic, uid));
5896
5897 return call;
5898 }
5899
5900 TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue storage, LValue index, Edge edge, ptrdiff_t offset = 0)
5901 {
5902 return m_out.baseIndex(
5903 heap, storage, m_out.zeroExtPtr(index), provenValue(edge), offset);
5904 }
5905
5906 void compare(
5907 LIntPredicate intCondition, LRealPredicate realCondition,
5908 S_JITOperation_EJJ helperFunction)
5909 {
5910 if (m_node->isBinaryUseKind(Int32Use)) {
5911 LValue left = lowInt32(m_node->child1());
5912 LValue right = lowInt32(m_node->child2());
5913 setBoolean(m_out.icmp(intCondition, left, right));
5914 return;
5915 }
5916
5917 if (m_node->isBinaryUseKind(Int52RepUse)) {
5918 Int52Kind kind;
5919 LValue left = lowWhicheverInt52(m_node->child1(), kind);
5920 LValue right = lowInt52(m_node->child2(), kind);
5921 setBoolean(m_out.icmp(intCondition, left, right));
5922 return;
5923 }
5924
5925 if (m_node->isBinaryUseKind(DoubleRepUse)) {
5926 LValue left = lowDouble(m_node->child1());
5927 LValue right = lowDouble(m_node->child2());
5928 setBoolean(m_out.fcmp(realCondition, left, right));
5929 return;
5930 }
5931
5932 if (m_node->isBinaryUseKind(UntypedUse)) {
5933 nonSpeculativeCompare(intCondition, helperFunction);
5934 return;
5935 }
5936
5937 DFG_CRASH(m_graph, m_node, "Bad use kinds");
5938 }
5939
5940 void compareEqObjectOrOtherToObject(Edge leftChild, Edge rightChild)
5941 {
5942 LValue rightCell = lowCell(rightChild);
5943 LValue leftValue = lowJSValue(leftChild, ManualOperandSpeculation);
5944
5945 speculateTruthyObject(rightChild, rightCell, SpecObject);
5946
5947 LBasicBlock leftCellCase = FTL_NEW_BLOCK(m_out, ("CompareEqObjectOrOtherToObject left cell case"));
5948 LBasicBlock leftNotCellCase = FTL_NEW_BLOCK(m_out, ("CompareEqObjectOrOtherToObject left not cell case"));
5949 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CompareEqObjectOrOtherToObject continuation"));
5950
5951 m_out.branch(
5952 isCell(leftValue, provenType(leftChild)),
5953 unsure(leftCellCase), unsure(leftNotCellCase));
5954
5955 LBasicBlock lastNext = m_out.appendTo(leftCellCase, leftNotCellCase);
5956 speculateTruthyObject(leftChild, leftValue, SpecObject | (~SpecCell));
5957 ValueFromBlock cellResult = m_out.anchor(m_out.equal(rightCell, leftValue));
5958 m_out.jump(continuation);
5959
5960 m_out.appendTo(leftNotCellCase, continuation);
5961 FTL_TYPE_CHECK(
5962 jsValueValue(leftValue), leftChild, SpecOther | SpecCell, isNotOther(leftValue));
5963 ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
5964 m_out.jump(continuation);
5965
5966 m_out.appendTo(continuation, lastNext);
5967 setBoolean(m_out.phi(m_out.boolean, cellResult, notCellResult));
5968 }
5969
5970 void speculateTruthyObject(Edge edge, LValue cell, SpeculatedType filter)
5971 {
5972 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
5973 FTL_TYPE_CHECK(jsValueValue(cell), edge, filter, isNotObject(cell));
5974 return;
5975 }
5976
5977 FTL_TYPE_CHECK(jsValueValue(cell), edge, filter, isNotObject(cell));
5978 speculate(
5979 BadType, jsValueValue(cell), edge.node(),
5980 m_out.testNonZero8(
5981 m_out.load8(cell, m_heaps.JSCell_typeInfoFlags),
5982 m_out.constInt8(MasqueradesAsUndefined)));
5983 }
5984
5985 void nonSpeculativeCompare(LIntPredicate intCondition, S_JITOperation_EJJ helperFunction)
5986 {
5987 LValue left = lowJSValue(m_node->child1());
5988 LValue right = lowJSValue(m_node->child2());
5989
5990 LBasicBlock leftIsInt = FTL_NEW_BLOCK(m_out, ("CompareEq untyped left is int"));
5991 LBasicBlock fastPath = FTL_NEW_BLOCK(m_out, ("CompareEq untyped fast path"));
5992 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("CompareEq untyped slow path"));
5993 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CompareEq untyped continuation"));
5994
5995 m_out.branch(isNotInt32(left), rarely(slowPath), usually(leftIsInt));
5996
5997 LBasicBlock lastNext = m_out.appendTo(leftIsInt, fastPath);
5998 m_out.branch(isNotInt32(right), rarely(slowPath), usually(fastPath));
5999
6000 m_out.appendTo(fastPath, slowPath);
6001 ValueFromBlock fastResult = m_out.anchor(
6002 m_out.icmp(intCondition, unboxInt32(left), unboxInt32(right)));
6003 m_out.jump(continuation);
6004
6005 m_out.appendTo(slowPath, continuation);
6006 ValueFromBlock slowResult = m_out.anchor(m_out.notNull(vmCall(
6007 m_out.operation(helperFunction), m_callFrame, left, right)));
6008 m_out.jump(continuation);
6009
6010 m_out.appendTo(continuation, lastNext);
6011 setBoolean(m_out.phi(m_out.boolean, fastResult, slowResult));
6012 }
6013
6014 LValue allocateCell(LValue allocator, LBasicBlock slowPath)
6015 {
6016 LBasicBlock success = FTL_NEW_BLOCK(m_out, ("object allocation success"));
6017
6018 LValue result = m_out.loadPtr(
6019 allocator, m_heaps.MarkedAllocator_freeListHead);
6020
6021 m_out.branch(m_out.notNull(result), usually(success), rarely(slowPath));
6022
6023 m_out.appendTo(success);
6024
6025 m_out.storePtr(
6026 m_out.loadPtr(result, m_heaps.JSCell_freeListNext),
6027 allocator, m_heaps.MarkedAllocator_freeListHead);
6028
6029 return result;
6030 }
6031
6032 void storeStructure(LValue object, Structure* structure)
6033 {
6034 m_out.store32(m_out.constInt32(structure->id()), object, m_heaps.JSCell_structureID);
6035 m_out.store32(
6036 m_out.constInt32(structure->objectInitializationBlob()),
6037 object, m_heaps.JSCell_usefulBytes);
6038 }
6039
6040 LValue allocateCell(LValue allocator, Structure* structure, LBasicBlock slowPath)
6041 {
6042 LValue result = allocateCell(allocator, slowPath);
6043 storeStructure(result, structure);
6044 return result;
6045 }
6046
6047 LValue allocateObject(
6048 LValue allocator, Structure* structure, LValue butterfly, LBasicBlock slowPath)
6049 {
6050 LValue result = allocateCell(allocator, structure, slowPath);
6051 m_out.storePtr(butterfly, result, m_heaps.JSObject_butterfly);
6052 return result;
6053 }
6054
6055 template<typename ClassType>
6056 LValue allocateObject(
6057 size_t size, Structure* structure, LValue butterfly, LBasicBlock slowPath)
6058 {
6059 MarkedAllocator* allocator = &vm().heap.allocatorForObjectOfType<ClassType>(size);
6060 return allocateObject(m_out.constIntPtr(allocator), structure, butterfly, slowPath);
6061 }
6062
6063 template<typename ClassType>
6064 LValue allocateObject(Structure* structure, LValue butterfly, LBasicBlock slowPath)
6065 {
6066 return allocateObject<ClassType>(
6067 ClassType::allocationSize(0), structure, butterfly, slowPath);
6068 }
6069
6070 template<typename ClassType>
6071 LValue allocateVariableSizedObject(
6072 LValue size, Structure* structure, LValue butterfly, LBasicBlock slowPath)
6073 {
6074 static_assert(!(MarkedSpace::preciseStep & (MarkedSpace::preciseStep - 1)), "MarkedSpace::preciseStep must be a power of two.");
6075 static_assert(!(MarkedSpace::impreciseStep & (MarkedSpace::impreciseStep - 1)), "MarkedSpace::impreciseStep must be a power of two.");
6076
6077 LValue subspace = m_out.constIntPtr(&vm().heap.subspaceForObjectOfType<ClassType>());
6078
6079 LBasicBlock smallCaseBlock = FTL_NEW_BLOCK(m_out, ("allocateVariableSizedObject small case"));
6080 LBasicBlock largeOrOversizeCaseBlock = FTL_NEW_BLOCK(m_out, ("allocateVariableSizedObject large or oversize case"));
6081 LBasicBlock largeCaseBlock = FTL_NEW_BLOCK(m_out, ("allocateVariableSizedObject large case"));
6082 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("allocateVariableSizedObject continuation"));
6083
6084 LValue uproundedSize = m_out.add(size, m_out.constInt32(MarkedSpace::preciseStep - 1));
6085 LValue isSmall = m_out.below(uproundedSize, m_out.constInt32(MarkedSpace::preciseCutoff));
6086 m_out.branch(isSmall, unsure(smallCaseBlock), unsure(largeOrOversizeCaseBlock));
6087
6088 LBasicBlock lastNext = m_out.appendTo(smallCaseBlock, largeOrOversizeCaseBlock);
6089 TypedPointer address = m_out.baseIndex(
6090 m_heaps.MarkedSpace_Subspace_preciseAllocators, subspace,
6091 m_out.zeroExtPtr(m_out.lShr(uproundedSize, m_out.constInt32(getLSBSet(MarkedSpace::preciseStep)))));
6092 ValueFromBlock smallAllocator = m_out.anchor(address.value());
6093 m_out.jump(continuation);
6094
6095 m_out.appendTo(largeOrOversizeCaseBlock, largeCaseBlock);
6096 m_out.branch(
6097 m_out.below(uproundedSize, m_out.constInt32(MarkedSpace::impreciseCutoff)),
6098 usually(largeCaseBlock), rarely(slowPath));
6099
6100 m_out.appendTo(largeCaseBlock, continuation);
6101 address = m_out.baseIndex(
6102 m_heaps.MarkedSpace_Subspace_impreciseAllocators, subspace,
6103 m_out.zeroExtPtr(m_out.lShr(uproundedSize, m_out.constInt32(getLSBSet(MarkedSpace::impreciseStep)))));
6104 ValueFromBlock largeAllocator = m_out.anchor(address.value());
6105 m_out.jump(continuation);
6106
6107 m_out.appendTo(continuation, lastNext);
6108 LValue allocator = m_out.phi(m_out.intPtr, smallAllocator, largeAllocator);
6109
6110 return allocateObject(allocator, structure, butterfly, slowPath);
6111 }
6112
6113 // Returns a pointer to the end of the allocation.
6114 LValue allocateBasicStorageAndGetEnd(LValue size, LBasicBlock slowPath)
6115 {
6116 CopiedAllocator& allocator = vm().heap.storageAllocator();
6117
6118 LBasicBlock success = FTL_NEW_BLOCK(m_out, ("storage allocation success"));
6119
6120 LValue remaining = m_out.loadPtr(m_out.absolute(&allocator.m_currentRemaining));
6121 LValue newRemaining = m_out.sub(remaining, size);
6122
6123 m_out.branch(
6124 m_out.lessThan(newRemaining, m_out.intPtrZero),
6125 rarely(slowPath), usually(success));
6126
6127 m_out.appendTo(success);
6128
6129 m_out.storePtr(newRemaining, m_out.absolute(&allocator.m_currentRemaining));
6130 return m_out.sub(
6131 m_out.loadPtr(m_out.absolute(&allocator.m_currentPayloadEnd)), newRemaining);
6132 }
6133
6134 LValue allocateObject(Structure* structure)
6135 {
6136 size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity());
6137 MarkedAllocator* allocator = &vm().heap.allocatorForObjectWithoutDestructor(allocationSize);
6138
6139 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("allocateObject slow path"));
6140 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("allocateObject continuation"));
6141
6142 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
6143
6144 ValueFromBlock fastResult = m_out.anchor(allocateObject(
6145 m_out.constIntPtr(allocator), structure, m_out.intPtrZero, slowPath));
6146
6147 m_out.jump(continuation);
6148
6149 m_out.appendTo(slowPath, continuation);
6150
6151 ValueFromBlock slowResult = m_out.anchor(vmCall(
6152 m_out.operation(operationNewObject), m_callFrame, m_out.constIntPtr(structure)));
6153 m_out.jump(continuation);
6154
6155 m_out.appendTo(continuation, lastNext);
6156 return m_out.phi(m_out.intPtr, fastResult, slowResult);
6157 }
6158
6159 struct ArrayValues {
6160 ArrayValues()
6161 : array(0)
6162 , butterfly(0)
6163 {
6164 }
6165
6166 ArrayValues(LValue array, LValue butterfly)
6167 : array(array)
6168 , butterfly(butterfly)
6169 {
6170 }
6171
6172 LValue array;
6173 LValue butterfly;
6174 };
6175 ArrayValues allocateJSArray(
6176 Structure* structure, unsigned numElements, LBasicBlock slowPath)
6177 {
6178 ASSERT(
6179 hasUndecided(structure->indexingType())
6180 || hasInt32(structure->indexingType())
6181 || hasDouble(structure->indexingType())
6182 || hasContiguous(structure->indexingType()));
6183
6184 unsigned vectorLength = std::max(BASE_VECTOR_LEN, numElements);
6185
6186 LValue endOfStorage = allocateBasicStorageAndGetEnd(
6187 m_out.constIntPtr(sizeof(JSValue) * vectorLength + sizeof(IndexingHeader)),
6188 slowPath);
6189
6190 LValue butterfly = m_out.sub(
6191 endOfStorage, m_out.constIntPtr(sizeof(JSValue) * vectorLength));
6192
6193 LValue object = allocateObject<JSArray>(
6194 structure, butterfly, slowPath);
6195
6196 m_out.store32(m_out.constInt32(numElements), butterfly, m_heaps.Butterfly_publicLength);
6197 m_out.store32(m_out.constInt32(vectorLength), butterfly, m_heaps.Butterfly_vectorLength);
6198
6199 if (hasDouble(structure->indexingType())) {
6200 for (unsigned i = numElements; i < vectorLength; ++i) {
6201 m_out.store64(
6202 m_out.constInt64(bitwise_cast<int64_t>(PNaN)),
6203 butterfly, m_heaps.indexedDoubleProperties[i]);
6204 }
6205 }
6206
6207 return ArrayValues(object, butterfly);
6208 }
6209
6210 ArrayValues allocateJSArray(Structure* structure, unsigned numElements)
6211 {
6212 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("JSArray allocation slow path"));
6213 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("JSArray allocation continuation"));
6214
6215 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
6216
6217 ArrayValues fastValues = allocateJSArray(structure, numElements, slowPath);
6218 ValueFromBlock fastArray = m_out.anchor(fastValues.array);
6219 ValueFromBlock fastButterfly = m_out.anchor(fastValues.butterfly);
6220
6221 m_out.jump(continuation);
6222
6223 m_out.appendTo(slowPath, continuation);
6224
6225 ValueFromBlock slowArray = m_out.anchor(vmCall(
6226 m_out.operation(operationNewArrayWithSize), m_callFrame,
6227 m_out.constIntPtr(structure), m_out.constInt32(numElements)));
6228 ValueFromBlock slowButterfly = m_out.anchor(
6229 m_out.loadPtr(slowArray.value(), m_heaps.JSObject_butterfly));
6230
6231 m_out.jump(continuation);
6232
6233 m_out.appendTo(continuation, lastNext);
6234
6235 return ArrayValues(
6236 m_out.phi(m_out.intPtr, fastArray, slowArray),
6237 m_out.phi(m_out.intPtr, fastButterfly, slowButterfly));
6238 }
6239
6240 LValue typedArrayLength(Edge baseEdge, ArrayMode arrayMode, LValue base)
6241 {
6242 JSArrayBufferView* view = m_graph.tryGetFoldableView(provenValue(baseEdge), arrayMode);
6243 if (view)
6244 return m_out.constInt32(view->length());
6245 return m_out.load32NonNegative(base, m_heaps.JSArrayBufferView_length);
6246 }
6247
6248 LValue typedArrayLength(Edge baseEdge, ArrayMode arrayMode)
6249 {
6250 return typedArrayLength(baseEdge, arrayMode, lowCell(baseEdge));
6251 }
6252
6253 LValue boolify(Edge edge)
6254 {
6255 switch (edge.useKind()) {
6256 case BooleanUse:
6257 return lowBoolean(edge);
6258 case Int32Use:
6259 return m_out.notZero32(lowInt32(edge));
6260 case DoubleRepUse:
6261 return m_out.doubleNotEqual(lowDouble(edge), m_out.doubleZero);
6262 case ObjectOrOtherUse:
6263 return m_out.bitNot(
6264 equalNullOrUndefined(
6265 edge, CellCaseSpeculatesObject, SpeculateNullOrUndefined,
6266 ManualOperandSpeculation));
6267 case StringUse: {
6268 LValue stringValue = lowString(edge);
6269 LValue length = m_out.load32NonNegative(stringValue, m_heaps.JSString_length);
6270 return m_out.notEqual(length, m_out.int32Zero);
6271 }
6272 case UntypedUse: {
6273 LValue value = lowJSValue(edge);
6274
6275 // Implements the following control flow structure:
6276 // if (value is cell) {
6277 // if (value is string)
6278 // result = !!value->length
6279 // else {
6280 // do evil things for masquerades-as-undefined
6281 // result = true
6282 // }
6283 // } else if (value is int32) {
6284 // result = !!unboxInt32(value)
6285 // } else if (value is number) {
6286 // result = !!unboxDouble(value)
6287 // } else {
6288 // result = value == jsTrue
6289 // }
6290
6291 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped cell case"));
6292 LBasicBlock stringCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped string case"));
6293 LBasicBlock notStringCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped not string case"));
6294 LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped not cell case"));
6295 LBasicBlock int32Case = FTL_NEW_BLOCK(m_out, ("Boolify untyped int32 case"));
6296 LBasicBlock notInt32Case = FTL_NEW_BLOCK(m_out, ("Boolify untyped not int32 case"));
6297 LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped double case"));
6298 LBasicBlock notDoubleCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped not double case"));
6299 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Boolify untyped continuation"));
6300
6301 Vector<ValueFromBlock> results;
6302
6303 m_out.branch(isCell(value, provenType(edge)), unsure(cellCase), unsure(notCellCase));
6304
6305 LBasicBlock lastNext = m_out.appendTo(cellCase, stringCase);
6306 m_out.branch(
6307 isString(value, provenType(edge) & SpecCell),
6308 unsure(stringCase), unsure(notStringCase));
6309
6310 m_out.appendTo(stringCase, notStringCase);
6311 LValue nonEmptyString = m_out.notZero32(
6312 m_out.load32NonNegative(value, m_heaps.JSString_length));
6313 results.append(m_out.anchor(nonEmptyString));
6314 m_out.jump(continuation);
6315
6316 m_out.appendTo(notStringCase, notCellCase);
6317 LValue isTruthyObject;
6318 if (masqueradesAsUndefinedWatchpointIsStillValid())
6319 isTruthyObject = m_out.booleanTrue;
6320 else {
6321 LBasicBlock masqueradesCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped masquerades case"));
6322
6323 results.append(m_out.anchor(m_out.booleanTrue));
6324
6325 m_out.branch(
6326 m_out.testIsZero8(
6327 m_out.load8(value, m_heaps.JSCell_typeInfoFlags),
6328 m_out.constInt8(MasqueradesAsUndefined)),
6329 usually(continuation), rarely(masqueradesCase));
6330
6331 m_out.appendTo(masqueradesCase);
6332
6333 isTruthyObject = m_out.notEqual(
6334 m_out.constIntPtr(m_graph.globalObjectFor(m_node->origin.semantic)),
6335 m_out.loadPtr(loadStructure(value), m_heaps.Structure_globalObject));
6336 }
6337 results.append(m_out.anchor(isTruthyObject));
6338 m_out.jump(continuation);
6339
6340 m_out.appendTo(notCellCase, int32Case);
6341 m_out.branch(
6342 isInt32(value, provenType(edge) & ~SpecCell),
6343 unsure(int32Case), unsure(notInt32Case));
6344
6345 m_out.appendTo(int32Case, notInt32Case);
6346 results.append(m_out.anchor(m_out.notZero32(unboxInt32(value))));
6347 m_out.jump(continuation);
6348
6349 m_out.appendTo(notInt32Case, doubleCase);
6350 m_out.branch(
6351 isNumber(value, provenType(edge) & ~SpecCell),
6352 unsure(doubleCase), unsure(notDoubleCase));
6353
6354 m_out.appendTo(doubleCase, notDoubleCase);
6355 // Note that doubleNotEqual() really means not-equal-and-ordered. It will return false
6356 // if value is NaN.
6357 LValue doubleIsTruthy = m_out.doubleNotEqual(
6358 unboxDouble(value), m_out.constDouble(0));
6359 results.append(m_out.anchor(doubleIsTruthy));
6360 m_out.jump(continuation);
6361
6362 m_out.appendTo(notDoubleCase, continuation);
6363 LValue miscIsTruthy = m_out.equal(
6364 value, m_out.constInt64(JSValue::encode(jsBoolean(true))));
6365 results.append(m_out.anchor(miscIsTruthy));
6366 m_out.jump(continuation);
6367
6368 m_out.appendTo(continuation, lastNext);
6369 return m_out.phi(m_out.boolean, results);
6370 }
6371 default:
6372 DFG_CRASH(m_graph, m_node, "Bad use kind");
6373 return 0;
6374 }
6375 }
6376
6377 enum StringOrObjectMode {
6378 AllCellsAreFalse,
6379 CellCaseSpeculatesObject
6380 };
6381 enum EqualNullOrUndefinedMode {
6382 EqualNull,
6383 EqualUndefined,
6384 EqualNullOrUndefined,
6385 SpeculateNullOrUndefined
6386 };
6387 LValue equalNullOrUndefined(
6388 Edge edge, StringOrObjectMode cellMode, EqualNullOrUndefinedMode primitiveMode,
6389 OperandSpeculationMode operandMode = AutomaticOperandSpeculation)
6390 {
6391 bool validWatchpoint = masqueradesAsUndefinedWatchpointIsStillValid();
6392
6393 LValue value = lowJSValue(edge, operandMode);
6394
6395 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined cell case"));
6396 LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined primitive case"));
6397 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined continuation"));
6398
6399 m_out.branch(isNotCell(value, provenType(edge)), unsure(primitiveCase), unsure(cellCase));
6400
6401 LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase);
6402
6403 Vector<ValueFromBlock, 3> results;
6404
6405 switch (cellMode) {
6406 case AllCellsAreFalse:
6407 break;
6408 case CellCaseSpeculatesObject:
6409 FTL_TYPE_CHECK(
6410 jsValueValue(value), edge, (~SpecCell) | SpecObject, isNotObject(value));
6411 break;
6412 }
6413
6414 if (validWatchpoint) {
6415 results.append(m_out.anchor(m_out.booleanFalse));
6416 m_out.jump(continuation);
6417 } else {
6418 LBasicBlock masqueradesCase =
6419 FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined masquerades case"));
6420
6421 results.append(m_out.anchor(m_out.booleanFalse));
6422
6423 m_out.branch(
6424 m_out.testNonZero8(
6425 m_out.load8(value, m_heaps.JSCell_typeInfoFlags),
6426 m_out.constInt8(MasqueradesAsUndefined)),
6427 rarely(masqueradesCase), usually(continuation));
6428
6429 m_out.appendTo(masqueradesCase, primitiveCase);
6430
6431 LValue structure = loadStructure(value);
6432
6433 results.append(m_out.anchor(
6434 m_out.equal(
6435 m_out.constIntPtr(m_graph.globalObjectFor(m_node->origin.semantic)),
6436 m_out.loadPtr(structure, m_heaps.Structure_globalObject))));
6437 m_out.jump(continuation);
6438 }
6439
6440 m_out.appendTo(primitiveCase, continuation);
6441
6442 LValue primitiveResult;
6443 switch (primitiveMode) {
6444 case EqualNull:
6445 primitiveResult = m_out.equal(value, m_out.constInt64(ValueNull));
6446 break;
6447 case EqualUndefined:
6448 primitiveResult = m_out.equal(value, m_out.constInt64(ValueUndefined));
6449 break;
6450 case EqualNullOrUndefined:
6451 primitiveResult = isOther(value, provenType(edge));
6452 break;
6453 case SpeculateNullOrUndefined:
6454 FTL_TYPE_CHECK(
6455 jsValueValue(value), edge, SpecCell | SpecOther, isNotOther(value));
6456 primitiveResult = m_out.booleanTrue;
6457 break;
6458 }
6459 results.append(m_out.anchor(primitiveResult));
6460 m_out.jump(continuation);
6461
6462 m_out.appendTo(continuation, lastNext);
6463
6464 return m_out.phi(m_out.boolean, results);
6465 }
6466
6467 template<typename FunctionType>
6468 void contiguousPutByValOutOfBounds(
6469 FunctionType slowPathFunction, LValue base, LValue storage, LValue index, LValue value,
6470 LBasicBlock continuation)
6471 {
6472 LValue isNotInBounds = m_out.aboveOrEqual(
6473 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength));
6474 if (!m_node->arrayMode().isInBounds()) {
6475 LBasicBlock notInBoundsCase =
6476 FTL_NEW_BLOCK(m_out, ("PutByVal not in bounds"));
6477 LBasicBlock performStore =
6478 FTL_NEW_BLOCK(m_out, ("PutByVal perform store"));
6479
6480 m_out.branch(isNotInBounds, unsure(notInBoundsCase), unsure(performStore));
6481
6482 LBasicBlock lastNext = m_out.appendTo(notInBoundsCase, performStore);
6483
6484 LValue isOutOfBounds = m_out.aboveOrEqual(
6485 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_vectorLength));
6486
6487 if (!m_node->arrayMode().isOutOfBounds())
6488 speculate(OutOfBounds, noValue(), 0, isOutOfBounds);
6489 else {
6490 LBasicBlock outOfBoundsCase =
6491 FTL_NEW_BLOCK(m_out, ("PutByVal out of bounds"));
6492 LBasicBlock holeCase =
6493 FTL_NEW_BLOCK(m_out, ("PutByVal hole case"));
6494
6495 m_out.branch(isOutOfBounds, unsure(outOfBoundsCase), unsure(holeCase));
6496
6497 LBasicBlock innerLastNext = m_out.appendTo(outOfBoundsCase, holeCase);
6498
6499 vmCall(
6500 m_out.operation(slowPathFunction),
6501 m_callFrame, base, index, value);
6502
6503 m_out.jump(continuation);
6504
6505 m_out.appendTo(holeCase, innerLastNext);
6506 }
6507
6508 m_out.store32(
6509 m_out.add(index, m_out.int32One),
6510 storage, m_heaps.Butterfly_publicLength);
6511
6512 m_out.jump(performStore);
6513 m_out.appendTo(performStore, lastNext);
6514 }
6515 }
6516
6517 void buildSwitch(SwitchData* data, LType type, LValue switchValue)
6518 {
6519 Vector<SwitchCase> cases;
6520 for (unsigned i = 0; i < data->cases.size(); ++i) {
6521 cases.append(SwitchCase(
6522 constInt(type, data->cases[i].value.switchLookupValue(data->kind)),
6523 lowBlock(data->cases[i].target.block), Weight(data->cases[i].target.count)));
6524 }
6525
6526 m_out.switchInstruction(
6527 switchValue, cases,
6528 lowBlock(data->fallThrough.block), Weight(data->fallThrough.count));
6529 }
6530
6531 void switchString(SwitchData* data, LValue string)
6532 {
6533 bool canDoBinarySwitch = true;
6534 unsigned totalLength = 0;
6535
6536 for (DFG::SwitchCase myCase : data->cases) {
6537 StringImpl* string = myCase.value.stringImpl();
6538 if (!string->is8Bit()) {
6539 canDoBinarySwitch = false;
6540 break;
6541 }
6542 if (string->length() > Options::maximumBinaryStringSwitchCaseLength()) {
6543 canDoBinarySwitch = false;
6544 break;
6545 }
6546 totalLength += string->length();
6547 }
6548
6549 if (!canDoBinarySwitch || totalLength > Options::maximumBinaryStringSwitchTotalLength()) {
6550 switchStringSlow(data, string);
6551 return;
6552 }
6553
6554 LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
6555 LValue length = m_out.load32(string, m_heaps.JSString_length);
6556
6557 LBasicBlock hasImplBlock = FTL_NEW_BLOCK(m_out, ("Switch/SwitchString has impl case"));
6558 LBasicBlock is8BitBlock = FTL_NEW_BLOCK(m_out, ("Switch/SwitchString is 8 bit case"));
6559 LBasicBlock slowBlock = FTL_NEW_BLOCK(m_out, ("Switch/SwitchString slow case"));
6560
6561 m_out.branch(m_out.isNull(stringImpl), unsure(slowBlock), unsure(hasImplBlock));
6562
6563 LBasicBlock lastNext = m_out.appendTo(hasImplBlock, is8BitBlock);
6564
6565 m_out.branch(
6566 m_out.testIsZero32(
6567 m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags),
6568 m_out.constInt32(StringImpl::flagIs8Bit())),
6569 unsure(slowBlock), unsure(is8BitBlock));
6570
6571 m_out.appendTo(is8BitBlock, slowBlock);
6572
6573 LValue buffer = m_out.loadPtr(stringImpl, m_heaps.StringImpl_data);
6574
6575 // FIXME: We should propagate branch weight data to the cases of this switch.
6576 // https://bugs.webkit.org/show_bug.cgi?id=144368
6577
6578 Vector<StringSwitchCase> cases;
6579 for (DFG::SwitchCase myCase : data->cases)
6580 cases.append(StringSwitchCase(myCase.value.stringImpl(), lowBlock(myCase.target.block)));
6581 std::sort(cases.begin(), cases.end());
6582 switchStringRecurse(data, buffer, length, cases, 0, 0, cases.size(), 0, false);
6583
6584 m_out.appendTo(slowBlock, lastNext);
6585 switchStringSlow(data, string);
6586 }
6587
6588 // The code for string switching is based closely on the same code in the DFG backend. While it
6589 // would be nice to reduce the amount of similar-looking code, it seems like this is one of
6590 // those algorithms where factoring out the common bits would result in more code than just
6591 // duplicating.
6592
6593 struct StringSwitchCase {
6594 StringSwitchCase() { }
6595
6596 StringSwitchCase(StringImpl* string, LBasicBlock target)
6597 : string(string)
6598 , target(target)
6599 {
6600 }
6601
6602 bool operator<(const StringSwitchCase& other) const
6603 {
6604 return stringLessThan(*string, *other.string);
6605 }
6606
6607 StringImpl* string;
6608 LBasicBlock target;
6609 };
6610
6611 struct CharacterCase {
6612 CharacterCase()
6613 : character(0)
6614 , begin(0)
6615 , end(0)
6616 {
6617 }
6618
6619 CharacterCase(LChar character, unsigned begin, unsigned end)
6620 : character(character)
6621 , begin(begin)
6622 , end(end)
6623 {
6624 }
6625
6626 bool operator<(const CharacterCase& other) const
6627 {
6628 return character < other.character;
6629 }
6630
6631 LChar character;
6632 unsigned begin;
6633 unsigned end;
6634 };
6635
6636 void switchStringRecurse(
6637 SwitchData* data, LValue buffer, LValue length, const Vector<StringSwitchCase>& cases,
6638 unsigned numChecked, unsigned begin, unsigned end, unsigned alreadyCheckedLength,
6639 unsigned checkedExactLength)
6640 {
6641 LBasicBlock fallThrough = lowBlock(data->fallThrough.block);
6642
6643 if (begin == end) {
6644 m_out.jump(fallThrough);
6645 return;
6646 }
6647
6648 unsigned minLength = cases[begin].string->length();
6649 unsigned commonChars = minLength;
6650 bool allLengthsEqual = true;
6651 for (unsigned i = begin + 1; i < end; ++i) {
6652 unsigned myCommonChars = numChecked;
6653 unsigned limit = std::min(cases[begin].string->length(), cases[i].string->length());
6654 for (unsigned j = numChecked; j < limit; ++j) {
6655 if (cases[begin].string->at(j) != cases[i].string->at(j))
6656 break;
6657 myCommonChars++;
6658 }
6659 commonChars = std::min(commonChars, myCommonChars);
6660 if (minLength != cases[i].string->length())
6661 allLengthsEqual = false;
6662 minLength = std::min(minLength, cases[i].string->length());
6663 }
6664
6665 if (checkedExactLength) {
6666 DFG_ASSERT(m_graph, m_node, alreadyCheckedLength == minLength);
6667 DFG_ASSERT(m_graph, m_node, allLengthsEqual);
6668 }
6669
6670 DFG_ASSERT(m_graph, m_node, minLength >= commonChars);
6671
6672 if (!allLengthsEqual && alreadyCheckedLength < minLength)
6673 m_out.check(m_out.below(length, m_out.constInt32(minLength)), unsure(fallThrough));
6674 if (allLengthsEqual && (alreadyCheckedLength < minLength || !checkedExactLength))
6675 m_out.check(m_out.notEqual(length, m_out.constInt32(minLength)), unsure(fallThrough));
6676
6677 for (unsigned i = numChecked; i < commonChars; ++i) {
6678 m_out.check(
6679 m_out.notEqual(
6680 m_out.load8(buffer, m_heaps.characters8[i]),
6681 m_out.constInt8(cases[begin].string->at(i))),
6682 unsure(fallThrough));
6683 }
6684
6685 if (minLength == commonChars) {
6686 // This is the case where one of the cases is a prefix of all of the other cases.
6687 // We've already checked that the input string is a prefix of all of the cases,
6688 // so we just check length to jump to that case.
6689
6690 DFG_ASSERT(m_graph, m_node, cases[begin].string->length() == commonChars);
6691 for (unsigned i = begin + 1; i < end; ++i)
6692 DFG_ASSERT(m_graph, m_node, cases[i].string->length() > commonChars);
6693
6694 if (allLengthsEqual) {
6695 DFG_ASSERT(m_graph, m_node, end == begin + 1);
6696 m_out.jump(cases[begin].target);
6697 return;
6698 }
6699
6700 m_out.check(
6701 m_out.equal(length, m_out.constInt32(commonChars)),
6702 unsure(cases[begin].target));
6703
6704 // We've checked if the length is >= minLength, and then we checked if the length is
6705 // == commonChars. We get to this point if it is >= minLength but not == commonChars.
6706 // Hence we know that it now must be > minLength, i.e. that it's >= minLength + 1.
6707 switchStringRecurse(
6708 data, buffer, length, cases, commonChars, begin + 1, end, minLength + 1, false);
6709 return;
6710 }
6711
6712 // At this point we know that the string is longer than commonChars, and we've only verified
6713 // commonChars. Use a binary switch on the next unchecked character, i.e.
6714 // string[commonChars].
6715
6716 DFG_ASSERT(m_graph, m_node, end >= begin + 2);
6717
6718 LValue uncheckedChar = m_out.load8(buffer, m_heaps.characters8[commonChars]);
6719
6720 Vector<CharacterCase> characterCases;
6721 CharacterCase currentCase(cases[begin].string->at(commonChars), begin, begin + 1);
6722 for (unsigned i = begin + 1; i < end; ++i) {
6723 LChar currentChar = cases[i].string->at(commonChars);
6724 if (currentChar != currentCase.character) {
6725 currentCase.end = i;
6726 characterCases.append(currentCase);
6727 currentCase = CharacterCase(currentChar, i, i + 1);
6728 } else
6729 currentCase.end = i + 1;
6730 }
6731 characterCases.append(currentCase);
6732
6733 Vector<LBasicBlock> characterBlocks;
6734 for (CharacterCase& myCase : characterCases)
6735 characterBlocks.append(FTL_NEW_BLOCK(m_out, ("Switch/SwitchString case for ", myCase.character, " at index ", commonChars)));
6736
6737 Vector<SwitchCase> switchCases;
6738 for (unsigned i = 0; i < characterCases.size(); ++i) {
6739 if (i)
6740 DFG_ASSERT(m_graph, m_node, characterCases[i - 1].character < characterCases[i].character);
6741 switchCases.append(SwitchCase(
6742 m_out.constInt8(characterCases[i].character), characterBlocks[i], Weight()));
6743 }
6744 m_out.switchInstruction(uncheckedChar, switchCases, fallThrough, Weight());
6745
6746 LBasicBlock lastNext = m_out.m_nextBlock;
6747 characterBlocks.append(lastNext); // Makes it convenient to set nextBlock.
6748 for (unsigned i = 0; i < characterCases.size(); ++i) {
6749 m_out.appendTo(characterBlocks[i], characterBlocks[i + 1]);
6750 switchStringRecurse(
6751 data, buffer, length, cases, commonChars + 1,
6752 characterCases[i].begin, characterCases[i].end, minLength, allLengthsEqual);
6753 }
6754
6755 DFG_ASSERT(m_graph, m_node, m_out.m_nextBlock == lastNext);
6756 }
6757
6758 void switchStringSlow(SwitchData* data, LValue string)
6759 {
6760 // FIXME: We ought to be able to use computed gotos here. We would save the labels of the
6761 // blocks we want to jump to, and then request their addresses after compilation completes.
6762 // https://bugs.webkit.org/show_bug.cgi?id=144369
6763
6764 LValue branchOffset = vmCall(
6765 m_out.operation(operationSwitchStringAndGetBranchOffset),
6766 m_callFrame, m_out.constIntPtr(data->switchTableIndex), string);
6767
6768 StringJumpTable& table = codeBlock()->stringSwitchJumpTable(data->switchTableIndex);
6769
6770 Vector<SwitchCase> cases;
6771 std::unordered_set<int32_t> alreadyHandled; // These may be negative, or zero, or probably other stuff, too. We don't want to mess with HashSet's corner cases and we don't really care about throughput here.
6772 for (unsigned i = 0; i < data->cases.size(); ++i) {
6773 // FIXME: The fact that we're using the bytecode's switch table means that the
6774 // following DFG IR transformation would be invalid.
6775 //
6776 // Original code:
6777 // switch (v) {
6778 // case "foo":
6779 // case "bar":
6780 // things();
6781 // break;
6782 // default:
6783 // break;
6784 // }
6785 //
6786 // New code:
6787 // switch (v) {
6788 // case "foo":
6789 // instrumentFoo();
6790 // goto _things;
6791 // case "bar":
6792 // instrumentBar();
6793 // _things:
6794 // things();
6795 // break;
6796 // default:
6797 // break;
6798 // }
6799 //
6800 // Luckily, we don't currently do any such transformation. But it's kind of silly that
6801 // this is an issue.
6802 // https://bugs.webkit.org/show_bug.cgi?id=144635
6803
6804 DFG::SwitchCase myCase = data->cases[i];
6805 StringJumpTable::StringOffsetTable::iterator iter =
6806 table.offsetTable.find(myCase.value.stringImpl());
6807 DFG_ASSERT(m_graph, m_node, iter != table.offsetTable.end());
6808
6809 if (!alreadyHandled.insert(iter->value.branchOffset).second)
6810 continue;
6811
6812 cases.append(SwitchCase(
6813 m_out.constInt32(iter->value.branchOffset),
6814 lowBlock(myCase.target.block), Weight(myCase.target.count)));
6815 }
6816
6817 m_out.switchInstruction(
6818 branchOffset, cases, lowBlock(data->fallThrough.block),
6819 Weight(data->fallThrough.count));
6820 }
6821
6822 // Calls the functor at the point of code generation where we know what the result type is.
6823 // You can emit whatever code you like at that point. Expects you to terminate the basic block.
6824 // When buildTypeOf() returns, it will have terminated all basic blocks that it created. So, if
6825 // you aren't using this as the terminator of a high-level block, you should create your own
6826 // contination and set it as the nextBlock (m_out.insertNewBlocksBefore(continuation)) before
6827 // calling this. For example:
6828 //
6829 // LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("My continuation"));
6830 // LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation);
6831 // buildTypeOf(
6832 // child, value,
6833 // [&] (TypeofType type) {
6834 // do things;
6835 // m_out.jump(continuation);
6836 // });
6837 // m_out.appendTo(continuation, lastNext);
6838 template<typename Functor>
6839 void buildTypeOf(Edge child, LValue value, const Functor& functor)
6840 {
6841 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
6842
6843 // Implements the following branching structure:
6844 //
6845 // if (is cell) {
6846 // if (is object) {
6847 // if (is function) {
6848 // return function;
6849 // } else if (doesn't have call trap and doesn't masquerade as undefined) {
6850 // return object
6851 // } else {
6852 // return slowPath();
6853 // }
6854 // } else if (is string) {
6855 // return string
6856 // } else {
6857 // return symbol
6858 // }
6859 // } else if (is number) {
6860 // return number
6861 // } else if (is null) {
6862 // return object
6863 // } else if (is boolean) {
6864 // return boolean
6865 // } else {
6866 // return undefined
6867 // }
6868
6869 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf cell case"));
6870 LBasicBlock objectCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf object case"));
6871 LBasicBlock functionCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf function case"));
6872 LBasicBlock notFunctionCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not function case"));
6873 LBasicBlock reallyObjectCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf really object case"));
6874 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("buildTypeOf slow path"));
6875 LBasicBlock unreachable = FTL_NEW_BLOCK(m_out, ("buildTypeOf unreachable"));
6876 LBasicBlock notObjectCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not object case"));
6877 LBasicBlock stringCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf string case"));
6878 LBasicBlock symbolCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf symbol case"));
6879 LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not cell case"));
6880 LBasicBlock numberCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf number case"));
6881 LBasicBlock notNumberCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not number case"));
6882 LBasicBlock notNullCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not null case"));
6883 LBasicBlock booleanCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf boolean case"));
6884 LBasicBlock undefinedCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf undefined case"));
6885
6886 m_out.branch(isCell(value, provenType(child)), unsure(cellCase), unsure(notCellCase));
6887
6888 LBasicBlock lastNext = m_out.appendTo(cellCase, objectCase);
6889 m_out.branch(isObject(value, provenType(child)), unsure(objectCase), unsure(notObjectCase));
6890
6891 m_out.appendTo(objectCase, functionCase);
6892 m_out.branch(
6893 isFunction(value, provenType(child) & SpecObject),
6894 unsure(functionCase), unsure(notFunctionCase));
6895
6896 m_out.appendTo(functionCase, notFunctionCase);
6897 functor(TypeofType::Function);
6898
6899 m_out.appendTo(notFunctionCase, reallyObjectCase);
6900 m_out.branch(
6901 isExoticForTypeof(value, provenType(child) & (SpecObject - SpecFunction)),
6902 rarely(slowPath), usually(reallyObjectCase));
6903
6904 m_out.appendTo(reallyObjectCase, slowPath);
6905 functor(TypeofType::Object);
6906
6907 m_out.appendTo(slowPath, unreachable);
6908 LValue result = vmCall(
6909 m_out.operation(operationTypeOfObjectAsTypeofType), m_callFrame,
6910 weakPointer(globalObject), value);
6911 Vector<SwitchCase, 3> cases;
6912 cases.append(SwitchCase(m_out.constInt32(static_cast<int32_t>(TypeofType::Undefined)), undefinedCase));
6913 cases.append(SwitchCase(m_out.constInt32(static_cast<int32_t>(TypeofType::Object)), reallyObjectCase));
6914 cases.append(SwitchCase(m_out.constInt32(static_cast<int32_t>(TypeofType::Function)), functionCase));
6915 m_out.switchInstruction(result, cases, unreachable, Weight());
6916
6917 m_out.appendTo(unreachable, notObjectCase);
6918 m_out.unreachable();
6919
6920 m_out.appendTo(notObjectCase, stringCase);
6921 m_out.branch(
6922 isString(value, provenType(child) & (SpecCell - SpecObject)),
6923 unsure(stringCase), unsure(symbolCase));
6924
6925 m_out.appendTo(stringCase, symbolCase);
6926 functor(TypeofType::String);
6927
6928 m_out.appendTo(symbolCase, notCellCase);
6929 functor(TypeofType::Symbol);
6930
6931 m_out.appendTo(notCellCase, numberCase);
6932 m_out.branch(
6933 isNumber(value, provenType(child) & ~SpecCell),
6934 unsure(numberCase), unsure(notNumberCase));
6935
6936 m_out.appendTo(numberCase, notNumberCase);
6937 functor(TypeofType::Number);
6938
6939 m_out.appendTo(notNumberCase, notNullCase);
6940 LValue isNull;
6941 if (provenType(child) & SpecOther)
6942 isNull = m_out.equal(value, m_out.constInt64(ValueNull));
6943 else
6944 isNull = m_out.booleanFalse;
6945 m_out.branch(isNull, unsure(reallyObjectCase), unsure(notNullCase));
6946
6947 m_out.appendTo(notNullCase, booleanCase);
6948 m_out.branch(
6949 isBoolean(value, provenType(child) & ~(SpecCell | SpecFullNumber)),
6950 unsure(booleanCase), unsure(undefinedCase));
6951
6952 m_out.appendTo(booleanCase, undefinedCase);
6953 functor(TypeofType::Boolean);
6954
6955 m_out.appendTo(undefinedCase, lastNext);
6956 functor(TypeofType::Undefined);
6957 }
6958
6959 LValue doubleToInt32(LValue doubleValue, double low, double high, bool isSigned = true)
6960 {
6961 LBasicBlock greatEnough = FTL_NEW_BLOCK(m_out, ("doubleToInt32 greatEnough"));
6962 LBasicBlock withinRange = FTL_NEW_BLOCK(m_out, ("doubleToInt32 withinRange"));
6963 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("doubleToInt32 slowPath"));
6964 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("doubleToInt32 continuation"));
6965
6966 Vector<ValueFromBlock, 2> results;
6967
6968 m_out.branch(
6969 m_out.doubleGreaterThanOrEqual(doubleValue, m_out.constDouble(low)),
6970 unsure(greatEnough), unsure(slowPath));
6971
6972 LBasicBlock lastNext = m_out.appendTo(greatEnough, withinRange);
6973 m_out.branch(
6974 m_out.doubleLessThanOrEqual(doubleValue, m_out.constDouble(high)),
6975 unsure(withinRange), unsure(slowPath));
6976
6977 m_out.appendTo(withinRange, slowPath);
6978 LValue fastResult;
6979 if (isSigned)
6980 fastResult = m_out.fpToInt32(doubleValue);
6981 else
6982 fastResult = m_out.fpToUInt32(doubleValue);
6983 results.append(m_out.anchor(fastResult));
6984 m_out.jump(continuation);
6985
6986 m_out.appendTo(slowPath, continuation);
6987 results.append(m_out.anchor(m_out.call(m_out.operation(toInt32), doubleValue)));
6988 m_out.jump(continuation);
6989
6990 m_out.appendTo(continuation, lastNext);
6991 return m_out.phi(m_out.int32, results);
6992 }
6993
6994 LValue doubleToInt32(LValue doubleValue)
6995 {
6996 if (Output::hasSensibleDoubleToInt())
6997 return sensibleDoubleToInt32(doubleValue);
6998
6999 double limit = pow(2, 31) - 1;
7000 return doubleToInt32(doubleValue, -limit, limit);
7001 }
7002
7003 LValue sensibleDoubleToInt32(LValue doubleValue)
7004 {
7005 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("sensible doubleToInt32 slow path"));
7006 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("sensible doubleToInt32 continuation"));
7007
7008 ValueFromBlock fastResult = m_out.anchor(
7009 m_out.sensibleDoubleToInt(doubleValue));
7010 m_out.branch(
7011 m_out.equal(fastResult.value(), m_out.constInt32(0x80000000)),
7012 rarely(slowPath), usually(continuation));
7013
7014 LBasicBlock lastNext = m_out.appendTo(slowPath, continuation);
7015 ValueFromBlock slowResult = m_out.anchor(
7016 m_out.call(m_out.operation(toInt32), doubleValue));
7017 m_out.jump(continuation);
7018
7019 m_out.appendTo(continuation, lastNext);
7020 return m_out.phi(m_out.int32, fastResult, slowResult);
7021 }
7022
7023 void speculate(
7024 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
7025 {
7026 appendOSRExit(kind, lowValue, highValue, failCondition);
7027 }
7028
7029 void terminate(ExitKind kind)
7030 {
7031 speculate(kind, noValue(), nullptr, m_out.booleanTrue);
7032 didAlreadyTerminate();
7033 }
7034
7035 void didAlreadyTerminate()
7036 {
7037 m_state.setIsValid(false);
7038 }
7039
7040 void typeCheck(
7041 FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
7042 LValue failCondition)
7043 {
7044 appendTypeCheck(lowValue, highValue, typesPassedThrough, failCondition);
7045 }
7046
7047 void appendTypeCheck(
7048 FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
7049 LValue failCondition)
7050 {
7051 if (!m_interpreter.needsTypeCheck(highValue, typesPassedThrough))
7052 return;
7053 ASSERT(mayHaveTypeCheck(highValue.useKind()));
7054 appendOSRExit(BadType, lowValue, highValue.node(), failCondition);
7055 m_interpreter.filter(highValue, typesPassedThrough);
7056 }
7057
7058 LValue lowInt32(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
7059 {
7060 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == Int32Use || edge.useKind() == KnownInt32Use));
7061
7062 if (edge->hasConstant()) {
7063 JSValue value = edge->asJSValue();
7064 if (!value.isInt32()) {
7065 terminate(Uncountable);
7066 return m_out.int32Zero;
7067 }
7068 return m_out.constInt32(value.asInt32());
7069 }
7070
7071 LoweredNodeValue value = m_int32Values.get(edge.node());
7072 if (isValid(value))
7073 return value.value();
7074
7075 value = m_strictInt52Values.get(edge.node());
7076 if (isValid(value))
7077 return strictInt52ToInt32(edge, value.value());
7078
7079 value = m_int52Values.get(edge.node());
7080 if (isValid(value))
7081 return strictInt52ToInt32(edge, int52ToStrictInt52(value.value()));
7082
7083 value = m_jsValueValues.get(edge.node());
7084 if (isValid(value)) {
7085 LValue boxedResult = value.value();
7086 FTL_TYPE_CHECK(
7087 jsValueValue(boxedResult), edge, SpecInt32, isNotInt32(boxedResult));
7088 LValue result = unboxInt32(boxedResult);
7089 setInt32(edge.node(), result);
7090 return result;
7091 }
7092
7093 DFG_ASSERT(m_graph, m_node, !(provenType(edge) & SpecInt32));
7094 terminate(Uncountable);
7095 return m_out.int32Zero;
7096 }
7097
7098 enum Int52Kind { StrictInt52, Int52 };
7099 LValue lowInt52(Edge edge, Int52Kind kind)
7100 {
7101 DFG_ASSERT(m_graph, m_node, edge.useKind() == Int52RepUse);
7102
7103 LoweredNodeValue value;
7104
7105 switch (kind) {
7106 case Int52:
7107 value = m_int52Values.get(edge.node());
7108 if (isValid(value))
7109 return value.value();
7110
7111 value = m_strictInt52Values.get(edge.node());
7112 if (isValid(value))
7113 return strictInt52ToInt52(value.value());
7114 break;
7115
7116 case StrictInt52:
7117 value = m_strictInt52Values.get(edge.node());
7118 if (isValid(value))
7119 return value.value();
7120
7121 value = m_int52Values.get(edge.node());
7122 if (isValid(value))
7123 return int52ToStrictInt52(value.value());
7124 break;
7125 }
7126
7127 DFG_ASSERT(m_graph, m_node, !provenType(edge));
7128 terminate(Uncountable);
7129 return m_out.int64Zero;
7130 }
7131
7132 LValue lowInt52(Edge edge)
7133 {
7134 return lowInt52(edge, Int52);
7135 }
7136
7137 LValue lowStrictInt52(Edge edge)
7138 {
7139 return lowInt52(edge, StrictInt52);
7140 }
7141
7142 bool betterUseStrictInt52(Node* node)
7143 {
7144 return !isValid(m_int52Values.get(node));
7145 }
7146 bool betterUseStrictInt52(Edge edge)
7147 {
7148 return betterUseStrictInt52(edge.node());
7149 }
7150 template<typename T>
7151 Int52Kind bestInt52Kind(T node)
7152 {
7153 return betterUseStrictInt52(node) ? StrictInt52 : Int52;
7154 }
7155 Int52Kind opposite(Int52Kind kind)
7156 {
7157 switch (kind) {
7158 case Int52:
7159 return StrictInt52;
7160 case StrictInt52:
7161 return Int52;
7162 }
7163 DFG_CRASH(m_graph, m_node, "Bad use kind");
7164 return Int52;
7165 }
7166
7167 LValue lowWhicheverInt52(Edge edge, Int52Kind& kind)
7168 {
7169 kind = bestInt52Kind(edge);
7170 return lowInt52(edge, kind);
7171 }
7172
7173 LValue lowCell(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
7174 {
7175 DFG_ASSERT(m_graph, m_node, mode == ManualOperandSpeculation || DFG::isCell(edge.useKind()));
7176
7177 if (edge->op() == JSConstant) {
7178 JSValue value = edge->asJSValue();
7179 if (!value.isCell()) {
7180 terminate(Uncountable);
7181 return m_out.intPtrZero;
7182 }
7183 return m_out.constIntPtr(value.asCell());
7184 }
7185
7186 LoweredNodeValue value = m_jsValueValues.get(edge.node());
7187 if (isValid(value)) {
7188 LValue uncheckedValue = value.value();
7189 FTL_TYPE_CHECK(
7190 jsValueValue(uncheckedValue), edge, SpecCell, isNotCell(uncheckedValue));
7191 return uncheckedValue;
7192 }
7193
7194 DFG_ASSERT(m_graph, m_node, !(provenType(edge) & SpecCell));
7195 terminate(Uncountable);
7196 return m_out.intPtrZero;
7197 }
7198
7199 LValue lowObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
7200 {
7201 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == ObjectUse);
7202
7203 LValue result = lowCell(edge, mode);
7204 speculateObject(edge, result);
7205 return result;
7206 }
7207
7208 LValue lowString(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
7209 {
7210 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == StringUse || edge.useKind() == KnownStringUse || edge.useKind() == StringIdentUse);
7211
7212 LValue result = lowCell(edge, mode);
7213 speculateString(edge, result);
7214 return result;
7215 }
7216
7217 LValue lowStringIdent(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
7218 {
7219 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == StringIdentUse);
7220
7221 LValue string = lowString(edge, mode);
7222 LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
7223 speculateStringIdent(edge, string, stringImpl);
7224 return stringImpl;
7225 }
7226
7227 LValue lowNonNullObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
7228 {
7229 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == ObjectUse);
7230
7231 LValue result = lowCell(edge, mode);
7232 speculateNonNullObject(edge, result);
7233 return result;
7234 }
7235
7236 LValue lowBoolean(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
7237 {
7238 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == BooleanUse);
7239
7240 if (edge->hasConstant()) {
7241 JSValue value = edge->asJSValue();
7242 if (!value.isBoolean()) {
7243 terminate(Uncountable);
7244 return m_out.booleanFalse;
7245 }
7246 return m_out.constBool(value.asBoolean());
7247 }
7248
7249 LoweredNodeValue value = m_booleanValues.get(edge.node());
7250 if (isValid(value))
7251 return value.value();
7252
7253 value = m_jsValueValues.get(edge.node());
7254 if (isValid(value)) {
7255 LValue unboxedResult = value.value();
7256 FTL_TYPE_CHECK(
7257 jsValueValue(unboxedResult), edge, SpecBoolean, isNotBoolean(unboxedResult));
7258 LValue result = unboxBoolean(unboxedResult);
7259 setBoolean(edge.node(), result);
7260 return result;
7261 }
7262
7263 DFG_ASSERT(m_graph, m_node, !(provenType(edge) & SpecBoolean));
7264 terminate(Uncountable);
7265 return m_out.booleanFalse;
7266 }
7267
7268 LValue lowDouble(Edge edge)
7269 {
7270 DFG_ASSERT(m_graph, m_node, isDouble(edge.useKind()));
7271
7272 LoweredNodeValue value = m_doubleValues.get(edge.node());
7273 if (isValid(value))
7274 return value.value();
7275 DFG_ASSERT(m_graph, m_node, !provenType(edge));
7276 terminate(Uncountable);
7277 return m_out.doubleZero;
7278 }
7279
7280 LValue lowJSValue(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
7281 {
7282 DFG_ASSERT(m_graph, m_node, mode == ManualOperandSpeculation || edge.useKind() == UntypedUse);
7283 DFG_ASSERT(m_graph, m_node, !isDouble(edge.useKind()));
7284 DFG_ASSERT(m_graph, m_node, edge.useKind() != Int52RepUse);
7285
7286 if (edge->hasConstant())
7287 return m_out.constInt64(JSValue::encode(edge->asJSValue()));
7288
7289 LoweredNodeValue value = m_jsValueValues.get(edge.node());
7290 if (isValid(value))
7291 return value.value();
7292
7293 value = m_int32Values.get(edge.node());
7294 if (isValid(value)) {
7295 LValue result = boxInt32(value.value());
7296 setJSValue(edge.node(), result);
7297 return result;
7298 }
7299
7300 value = m_booleanValues.get(edge.node());
7301 if (isValid(value)) {
7302 LValue result = boxBoolean(value.value());
7303 setJSValue(edge.node(), result);
7304 return result;
7305 }
7306
7307 DFG_CRASH(m_graph, m_node, "Value not defined");
7308 return 0;
7309 }
7310
7311 LValue lowStorage(Edge edge)
7312 {
7313 LoweredNodeValue value = m_storageValues.get(edge.node());
7314 if (isValid(value))
7315 return value.value();
7316
7317 LValue result = lowCell(edge);
7318 setStorage(edge.node(), result);
7319 return result;
7320 }
7321
7322 LValue strictInt52ToInt32(Edge edge, LValue value)
7323 {
7324 LValue result = m_out.castToInt32(value);
7325 FTL_TYPE_CHECK(
7326 noValue(), edge, SpecInt32,
7327 m_out.notEqual(m_out.signExt(result, m_out.int64), value));
7328 setInt32(edge.node(), result);
7329 return result;
7330 }
7331
7332 LValue strictInt52ToDouble(LValue value)
7333 {
7334 return m_out.intToDouble(value);
7335 }
7336
7337 LValue strictInt52ToJSValue(LValue value)
7338 {
7339 LBasicBlock isInt32 = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue isInt32 case"));
7340 LBasicBlock isDouble = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue isDouble case"));
7341 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue continuation"));
7342
7343 Vector<ValueFromBlock, 2> results;
7344
7345 LValue int32Value = m_out.castToInt32(value);
7346 m_out.branch(
7347 m_out.equal(m_out.signExt(int32Value, m_out.int64), value),
7348 unsure(isInt32), unsure(isDouble));
7349
7350 LBasicBlock lastNext = m_out.appendTo(isInt32, isDouble);
7351
7352 results.append(m_out.anchor(boxInt32(int32Value)));
7353 m_out.jump(continuation);
7354
7355 m_out.appendTo(isDouble, continuation);
7356
7357 results.append(m_out.anchor(boxDouble(m_out.intToDouble(value))));
7358 m_out.jump(continuation);
7359
7360 m_out.appendTo(continuation, lastNext);
7361 return m_out.phi(m_out.int64, results);
7362 }
7363
7364 LValue strictInt52ToInt52(LValue value)
7365 {
7366 return m_out.shl(value, m_out.constInt64(JSValue::int52ShiftAmount));
7367 }
7368
7369 LValue int52ToStrictInt52(LValue value)
7370 {
7371 return m_out.aShr(value, m_out.constInt64(JSValue::int52ShiftAmount));
7372 }
7373
7374 LValue isInt32(LValue jsValue, SpeculatedType type = SpecFullTop)
7375 {
7376 if (LValue proven = isProvenValue(type, SpecInt32))
7377 return proven;
7378 return m_out.aboveOrEqual(jsValue, m_tagTypeNumber);
7379 }
7380 LValue isNotInt32(LValue jsValue, SpeculatedType type = SpecFullTop)
7381 {
7382 if (LValue proven = isProvenValue(type, ~SpecInt32))
7383 return proven;
7384 return m_out.below(jsValue, m_tagTypeNumber);
7385 }
7386 LValue unboxInt32(LValue jsValue)
7387 {
7388 return m_out.castToInt32(jsValue);
7389 }
7390 LValue boxInt32(LValue value)
7391 {
7392 return m_out.add(m_out.zeroExt(value, m_out.int64), m_tagTypeNumber);
7393 }
7394
7395 LValue isCellOrMisc(LValue jsValue, SpeculatedType type = SpecFullTop)
7396 {
7397 if (LValue proven = isProvenValue(type, SpecCell | SpecMisc))
7398 return proven;
7399 return m_out.testIsZero64(jsValue, m_tagTypeNumber);
7400 }
7401 LValue isNotCellOrMisc(LValue jsValue, SpeculatedType type = SpecFullTop)
7402 {
7403 if (LValue proven = isProvenValue(type, ~(SpecCell | SpecMisc)))
7404 return proven;
7405 return m_out.testNonZero64(jsValue, m_tagTypeNumber);
7406 }
7407
7408 LValue unboxDouble(LValue jsValue)
7409 {
7410 return m_out.bitCast(m_out.add(jsValue, m_tagTypeNumber), m_out.doubleType);
7411 }
7412 LValue boxDouble(LValue doubleValue)
7413 {
7414 return m_out.sub(m_out.bitCast(doubleValue, m_out.int64), m_tagTypeNumber);
7415 }
7416
7417 LValue jsValueToStrictInt52(Edge edge, LValue boxedValue)
7418 {
7419 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("jsValueToInt52 unboxing int case"));
7420 LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToInt52 unboxing double case"));
7421 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("jsValueToInt52 unboxing continuation"));
7422
7423 LValue isNotInt32;
7424 if (!m_interpreter.needsTypeCheck(edge, SpecInt32))
7425 isNotInt32 = m_out.booleanFalse;
7426 else if (!m_interpreter.needsTypeCheck(edge, ~SpecInt32))
7427 isNotInt32 = m_out.booleanTrue;
7428 else
7429 isNotInt32 = this->isNotInt32(boxedValue);
7430 m_out.branch(isNotInt32, unsure(doubleCase), unsure(intCase));
7431
7432 LBasicBlock lastNext = m_out.appendTo(intCase, doubleCase);
7433
7434 ValueFromBlock intToInt52 = m_out.anchor(
7435 m_out.signExt(unboxInt32(boxedValue), m_out.int64));
7436 m_out.jump(continuation);
7437
7438 m_out.appendTo(doubleCase, continuation);
7439
7440 LValue possibleResult = m_out.call(
7441 m_out.operation(operationConvertBoxedDoubleToInt52), boxedValue);
7442 FTL_TYPE_CHECK(
7443 jsValueValue(boxedValue), edge, SpecInt32 | SpecInt52AsDouble,
7444 m_out.equal(possibleResult, m_out.constInt64(JSValue::notInt52)));
7445
7446 ValueFromBlock doubleToInt52 = m_out.anchor(possibleResult);
7447 m_out.jump(continuation);
7448
7449 m_out.appendTo(continuation, lastNext);
7450
7451 return m_out.phi(m_out.int64, intToInt52, doubleToInt52);
7452 }
7453
7454 LValue doubleToStrictInt52(Edge edge, LValue value)
7455 {
7456 LValue possibleResult = m_out.call(
7457 m_out.operation(operationConvertDoubleToInt52), value);
7458 FTL_TYPE_CHECK(
7459 doubleValue(value), edge, SpecInt52AsDouble,
7460 m_out.equal(possibleResult, m_out.constInt64(JSValue::notInt52)));
7461
7462 return possibleResult;
7463 }
7464
7465 LValue convertDoubleToInt32(LValue value, bool shouldCheckNegativeZero)
7466 {
7467 LValue integerValue = m_out.fpToInt32(value);
7468 LValue integerValueConvertedToDouble = m_out.intToDouble(integerValue);
7469 LValue valueNotConvertibleToInteger = m_out.doubleNotEqualOrUnordered(value, integerValueConvertedToDouble);
7470 speculate(Overflow, FormattedValue(ValueFormatDouble, value), m_node, valueNotConvertibleToInteger);
7471
7472 if (shouldCheckNegativeZero) {
7473 LBasicBlock valueIsZero = FTL_NEW_BLOCK(m_out, ("ConvertDoubleToInt32 on zero"));
7474 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ConvertDoubleToInt32 continuation"));
7475 m_out.branch(m_out.isZero32(integerValue), unsure(valueIsZero), unsure(continuation));
7476
7477 LBasicBlock lastNext = m_out.appendTo(valueIsZero, continuation);
7478
7479 LValue doubleBitcastToInt64 = m_out.bitCast(value, m_out.int64);
7480 LValue signBitSet = m_out.lessThan(doubleBitcastToInt64, m_out.constInt64(0));
7481
7482 speculate(NegativeZero, FormattedValue(ValueFormatDouble, value), m_node, signBitSet);
7483 m_out.jump(continuation);
7484 m_out.appendTo(continuation, lastNext);
7485 }
7486 return integerValue;
7487 }
7488
7489 LValue isNumber(LValue jsValue, SpeculatedType type = SpecFullTop)
7490 {
7491 if (LValue proven = isProvenValue(type, SpecFullNumber))
7492 return proven;
7493 return isNotCellOrMisc(jsValue);
7494 }
7495 LValue isNotNumber(LValue jsValue, SpeculatedType type = SpecFullTop)
7496 {
7497 if (LValue proven = isProvenValue(type, ~SpecFullNumber))
7498 return proven;
7499 return isCellOrMisc(jsValue);
7500 }
7501
7502 LValue isNotCell(LValue jsValue, SpeculatedType type = SpecFullTop)
7503 {
7504 if (LValue proven = isProvenValue(type, ~SpecCell))
7505 return proven;
7506 return m_out.testNonZero64(jsValue, m_tagMask);
7507 }
7508
7509 LValue isCell(LValue jsValue, SpeculatedType type = SpecFullTop)
7510 {
7511 if (LValue proven = isProvenValue(type, SpecCell))
7512 return proven;
7513 return m_out.testIsZero64(jsValue, m_tagMask);
7514 }
7515
7516 LValue isNotMisc(LValue value, SpeculatedType type = SpecFullTop)
7517 {
7518 if (LValue proven = isProvenValue(type, ~SpecMisc))
7519 return proven;
7520 return m_out.above(value, m_out.constInt64(TagBitTypeOther | TagBitBool | TagBitUndefined));
7521 }
7522
7523 LValue isMisc(LValue value, SpeculatedType type = SpecFullTop)
7524 {
7525 if (LValue proven = isProvenValue(type, SpecMisc))
7526 return proven;
7527 return m_out.bitNot(isNotMisc(value));
7528 }
7529
7530 LValue isNotBoolean(LValue jsValue, SpeculatedType type = SpecFullTop)
7531 {
7532 if (LValue proven = isProvenValue(type, ~SpecBoolean))
7533 return proven;
7534 return m_out.testNonZero64(
7535 m_out.bitXor(jsValue, m_out.constInt64(ValueFalse)),
7536 m_out.constInt64(~1));
7537 }
7538 LValue isBoolean(LValue jsValue, SpeculatedType type = SpecFullTop)
7539 {
7540 if (LValue proven = isProvenValue(type, SpecBoolean))
7541 return proven;
7542 return m_out.bitNot(isNotBoolean(jsValue));
7543 }
7544 LValue unboxBoolean(LValue jsValue)
7545 {
7546 // We want to use a cast that guarantees that LLVM knows that even the integer
7547 // value is just 0 or 1. But for now we do it the dumb way.
7548 return m_out.notZero64(m_out.bitAnd(jsValue, m_out.constInt64(1)));
7549 }
7550 LValue boxBoolean(LValue value)
7551 {
7552 return m_out.select(
7553 value, m_out.constInt64(ValueTrue), m_out.constInt64(ValueFalse));
7554 }
7555
7556 LValue isNotOther(LValue value, SpeculatedType type = SpecFullTop)
7557 {
7558 if (LValue proven = isProvenValue(type, ~SpecOther))
7559 return proven;
7560 return m_out.notEqual(
7561 m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
7562 m_out.constInt64(ValueNull));
7563 }
7564 LValue isOther(LValue value, SpeculatedType type = SpecFullTop)
7565 {
7566 if (LValue proven = isProvenValue(type, SpecOther))
7567 return proven;
7568 return m_out.equal(
7569 m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
7570 m_out.constInt64(ValueNull));
7571 }
7572
7573 LValue isProvenValue(SpeculatedType provenType, SpeculatedType wantedType)
7574 {
7575 if (!(provenType & ~wantedType))
7576 return m_out.booleanTrue;
7577 if (!(provenType & wantedType))
7578 return m_out.booleanFalse;
7579 return nullptr;
7580 }
7581
7582 void speculate(Edge edge)
7583 {
7584 switch (edge.useKind()) {
7585 case UntypedUse:
7586 break;
7587 case KnownInt32Use:
7588 case KnownStringUse:
7589 case DoubleRepUse:
7590 case Int52RepUse:
7591 ASSERT(!m_interpreter.needsTypeCheck(edge));
7592 break;
7593 case Int32Use:
7594 speculateInt32(edge);
7595 break;
7596 case CellUse:
7597 speculateCell(edge);
7598 break;
7599 case KnownCellUse:
7600 ASSERT(!m_interpreter.needsTypeCheck(edge));
7601 break;
7602 case MachineIntUse:
7603 speculateMachineInt(edge);
7604 break;
7605 case ObjectUse:
7606 speculateObject(edge);
7607 break;
7608 case FunctionUse:
7609 speculateFunction(edge);
7610 break;
7611 case ObjectOrOtherUse:
7612 speculateObjectOrOther(edge);
7613 break;
7614 case FinalObjectUse:
7615 speculateFinalObject(edge);
7616 break;
7617 case StringUse:
7618 speculateString(edge);
7619 break;
7620 case StringIdentUse:
7621 speculateStringIdent(edge);
7622 break;
7623 case StringObjectUse:
7624 speculateStringObject(edge);
7625 break;
7626 case StringOrStringObjectUse:
7627 speculateStringOrStringObject(edge);
7628 break;
7629 case NumberUse:
7630 speculateNumber(edge);
7631 break;
7632 case RealNumberUse:
7633 speculateRealNumber(edge);
7634 break;
7635 case DoubleRepRealUse:
7636 speculateDoubleRepReal(edge);
7637 break;
7638 case DoubleRepMachineIntUse:
7639 speculateDoubleRepMachineInt(edge);
7640 break;
7641 case BooleanUse:
7642 speculateBoolean(edge);
7643 break;
7644 case NotStringVarUse:
7645 speculateNotStringVar(edge);
7646 break;
7647 case NotCellUse:
7648 speculateNotCell(edge);
7649 break;
7650 case OtherUse:
7651 speculateOther(edge);
7652 break;
7653 case MiscUse:
7654 speculateMisc(edge);
7655 break;
7656 default:
7657 DFG_CRASH(m_graph, m_node, "Unsupported speculation use kind");
7658 }
7659 }
7660
7661 void speculate(Node*, Edge edge)
7662 {
7663 speculate(edge);
7664 }
7665
7666 void speculateInt32(Edge edge)
7667 {
7668 lowInt32(edge);
7669 }
7670
7671 void speculateCell(Edge edge)
7672 {
7673 lowCell(edge);
7674 }
7675
7676 void speculateMachineInt(Edge edge)
7677 {
7678 if (!m_interpreter.needsTypeCheck(edge))
7679 return;
7680
7681 jsValueToStrictInt52(edge, lowJSValue(edge, ManualOperandSpeculation));
7682 }
7683
7684 LValue isObject(LValue cell, SpeculatedType type = SpecFullTop)
7685 {
7686 if (LValue proven = isProvenValue(type & SpecCell, SpecObject))
7687 return proven;
7688 return m_out.aboveOrEqual(
7689 m_out.load8(cell, m_heaps.JSCell_typeInfoType),
7690 m_out.constInt8(ObjectType));
7691 }
7692
7693 LValue isNotObject(LValue cell, SpeculatedType type = SpecFullTop)
7694 {
7695 if (LValue proven = isProvenValue(type & SpecCell, ~SpecObject))
7696 return proven;
7697 return m_out.below(
7698 m_out.load8(cell, m_heaps.JSCell_typeInfoType),
7699 m_out.constInt8(ObjectType));
7700 }
7701
7702 LValue isNotString(LValue cell, SpeculatedType type = SpecFullTop)
7703 {
7704 if (LValue proven = isProvenValue(type & SpecCell, ~SpecString))
7705 return proven;
7706 return m_out.notEqual(
7707 m_out.load32(cell, m_heaps.JSCell_structureID),
7708 m_out.constInt32(vm().stringStructure->id()));
7709 }
7710
7711 LValue isString(LValue cell, SpeculatedType type = SpecFullTop)
7712 {
7713 if (LValue proven = isProvenValue(type & SpecCell, SpecString))
7714 return proven;
7715 return m_out.equal(
7716 m_out.load32(cell, m_heaps.JSCell_structureID),
7717 m_out.constInt32(vm().stringStructure->id()));
7718 }
7719
7720 LValue isArrayType(LValue cell, ArrayMode arrayMode)
7721 {
7722 switch (arrayMode.type()) {
7723 case Array::Int32:
7724 case Array::Double:
7725 case Array::Contiguous: {
7726 LValue indexingType = m_out.load8(cell, m_heaps.JSCell_indexingType);
7727
7728 switch (arrayMode.arrayClass()) {
7729 case Array::OriginalArray:
7730 DFG_CRASH(m_graph, m_node, "Unexpected original array");
7731 return 0;
7732
7733 case Array::Array:
7734 return m_out.equal(
7735 m_out.bitAnd(indexingType, m_out.constInt8(IsArray | IndexingShapeMask)),
7736 m_out.constInt8(IsArray | arrayMode.shapeMask()));
7737
7738 case Array::NonArray:
7739 case Array::OriginalNonArray:
7740 return m_out.equal(
7741 m_out.bitAnd(indexingType, m_out.constInt8(IsArray | IndexingShapeMask)),
7742 m_out.constInt8(arrayMode.shapeMask()));
7743
7744 case Array::PossiblyArray:
7745 return m_out.equal(
7746 m_out.bitAnd(indexingType, m_out.constInt8(IndexingShapeMask)),
7747 m_out.constInt8(arrayMode.shapeMask()));
7748 }
7749
7750 DFG_CRASH(m_graph, m_node, "Corrupt array class");
7751 }
7752
7753 case Array::DirectArguments:
7754 return m_out.equal(
7755 m_out.load8(cell, m_heaps.JSCell_typeInfoType),
7756 m_out.constInt8(DirectArgumentsType));
7757
7758 case Array::ScopedArguments:
7759 return m_out.equal(
7760 m_out.load8(cell, m_heaps.JSCell_typeInfoType),
7761 m_out.constInt8(ScopedArgumentsType));
7762
7763 default:
7764 return m_out.equal(
7765 m_out.load8(cell, m_heaps.JSCell_typeInfoType),
7766 m_out.constInt8(typeForTypedArrayType(arrayMode.typedArrayType())));
7767 }
7768 }
7769
7770 LValue isFunction(LValue cell, SpeculatedType type = SpecFullTop)
7771 {
7772 if (LValue proven = isProvenValue(type & SpecCell, SpecFunction))
7773 return proven;
7774 return isType(cell, JSFunctionType);
7775 }
7776 LValue isNotFunction(LValue cell, SpeculatedType type = SpecFullTop)
7777 {
7778 if (LValue proven = isProvenValue(type & SpecCell, ~SpecFunction))
7779 return proven;
7780 return isNotType(cell, JSFunctionType);
7781 }
7782
7783 LValue isExoticForTypeof(LValue cell, SpeculatedType type = SpecFullTop)
7784 {
7785 if (!(type & SpecObjectOther))
7786 return m_out.booleanFalse;
7787 return m_out.testNonZero8(
7788 m_out.load8(cell, m_heaps.JSCell_typeInfoFlags),
7789 m_out.constInt8(MasqueradesAsUndefined | TypeOfShouldCallGetCallData));
7790 }
7791
7792 LValue isType(LValue cell, JSType type)
7793 {
7794 return m_out.equal(
7795 m_out.load8(cell, m_heaps.JSCell_typeInfoType),
7796 m_out.constInt8(type));
7797 }
7798
7799 LValue isNotType(LValue cell, JSType type)
7800 {
7801 return m_out.bitNot(isType(cell, type));
7802 }
7803
7804 void speculateObject(Edge edge, LValue cell)
7805 {
7806 FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecObject, isNotObject(cell));
7807 }
7808
7809 void speculateObject(Edge edge)
7810 {
7811 speculateObject(edge, lowCell(edge));
7812 }
7813
7814 void speculateFunction(Edge edge, LValue cell)
7815 {
7816 FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecFunction, isNotFunction(cell));
7817 }
7818
7819 void speculateFunction(Edge edge)
7820 {
7821 speculateFunction(edge, lowCell(edge));
7822 }
7823
7824 void speculateObjectOrOther(Edge edge)
7825 {
7826 if (!m_interpreter.needsTypeCheck(edge))
7827 return;
7828
7829 LValue value = lowJSValue(edge, ManualOperandSpeculation);
7830
7831 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther cell case"));
7832 LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther primitive case"));
7833 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther continuation"));
7834
7835 m_out.branch(isNotCell(value, provenType(edge)), unsure(primitiveCase), unsure(cellCase));
7836
7837 LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase);
7838
7839 FTL_TYPE_CHECK(
7840 jsValueValue(value), edge, (~SpecCell) | SpecObject, isNotObject(value));
7841
7842 m_out.jump(continuation);
7843
7844 m_out.appendTo(primitiveCase, continuation);
7845
7846 FTL_TYPE_CHECK(
7847 jsValueValue(value), edge, SpecCell | SpecOther, isNotOther(value));
7848
7849 m_out.jump(continuation);
7850
7851 m_out.appendTo(continuation, lastNext);
7852 }
7853
7854 void speculateFinalObject(Edge edge, LValue cell)
7855 {
7856 FTL_TYPE_CHECK(
7857 jsValueValue(cell), edge, SpecFinalObject, isNotType(cell, FinalObjectType));
7858 }
7859
7860 void speculateFinalObject(Edge edge)
7861 {
7862 speculateFinalObject(edge, lowCell(edge));
7863 }
7864
7865 void speculateString(Edge edge, LValue cell)
7866 {
7867 FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecString | ~SpecCell, isNotString(cell));
7868 }
7869
7870 void speculateString(Edge edge)
7871 {
7872 speculateString(edge, lowCell(edge));
7873 }
7874
7875 void speculateStringIdent(Edge edge, LValue string, LValue stringImpl)
7876 {
7877 if (!m_interpreter.needsTypeCheck(edge, SpecStringIdent | ~SpecString))
7878 return;
7879
7880 speculate(BadType, jsValueValue(string), edge.node(), m_out.isNull(stringImpl));
7881 speculate(
7882 BadType, jsValueValue(string), edge.node(),
7883 m_out.testIsZero32(
7884 m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags),
7885 m_out.constInt32(StringImpl::flagIsAtomic())));
7886 m_interpreter.filter(edge, SpecStringIdent | ~SpecString);
7887 }
7888
7889 void speculateStringIdent(Edge edge)
7890 {
7891 lowStringIdent(edge);
7892 }
7893
7894 void speculateStringObject(Edge edge)
7895 {
7896 if (!m_interpreter.needsTypeCheck(edge, SpecStringObject))
7897 return;
7898
7899 speculateStringObjectForCell(edge, lowCell(edge));
7900 m_interpreter.filter(edge, SpecStringObject);
7901 }
7902
7903 void speculateStringOrStringObject(Edge edge)
7904 {
7905 if (!m_interpreter.needsTypeCheck(edge, SpecString | SpecStringObject))
7906 return;
7907
7908 LBasicBlock notString = FTL_NEW_BLOCK(m_out, ("Speculate StringOrStringObject not string case"));
7909 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Speculate StringOrStringObject continuation"));
7910
7911 LValue structureID = m_out.load32(lowCell(edge), m_heaps.JSCell_structureID);
7912 m_out.branch(
7913 m_out.equal(structureID, m_out.constInt32(vm().stringStructure->id())),
7914 unsure(continuation), unsure(notString));
7915
7916 LBasicBlock lastNext = m_out.appendTo(notString, continuation);
7917 speculateStringObjectForStructureID(edge, structureID);
7918 m_out.jump(continuation);
7919
7920 m_out.appendTo(continuation, lastNext);
7921
7922 m_interpreter.filter(edge, SpecString | SpecStringObject);
7923 }
7924
7925 void speculateStringObjectForCell(Edge edge, LValue cell)
7926 {
7927 speculateStringObjectForStructureID(edge, m_out.load32(cell, m_heaps.JSCell_structureID));
7928 }
7929
7930 void speculateStringObjectForStructureID(Edge edge, LValue structureID)
7931 {
7932 Structure* stringObjectStructure =
7933 m_graph.globalObjectFor(m_node->origin.semantic)->stringObjectStructure();
7934
7935 if (abstractStructure(edge).isSubsetOf(StructureSet(stringObjectStructure)))
7936 return;
7937
7938 speculate(
7939 NotStringObject, noValue(), 0,
7940 m_out.notEqual(structureID, weakStructureID(stringObjectStructure)));
7941 }
7942
7943 void speculateNonNullObject(Edge edge, LValue cell)
7944 {
7945 FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecObject, isNotObject(cell));
7946 if (masqueradesAsUndefinedWatchpointIsStillValid())
7947 return;
7948
7949 speculate(
7950 BadType, jsValueValue(cell), edge.node(),
7951 m_out.testNonZero8(
7952 m_out.load8(cell, m_heaps.JSCell_typeInfoFlags),
7953 m_out.constInt8(MasqueradesAsUndefined)));
7954 }
7955
7956 void speculateNumber(Edge edge)
7957 {
7958 LValue value = lowJSValue(edge, ManualOperandSpeculation);
7959 FTL_TYPE_CHECK(jsValueValue(value), edge, SpecBytecodeNumber, isNotNumber(value));
7960 }
7961
7962 void speculateRealNumber(Edge edge)
7963 {
7964 // Do an early return here because lowDouble() can create a lot of control flow.
7965 if (!m_interpreter.needsTypeCheck(edge))
7966 return;
7967
7968 LValue value = lowJSValue(edge, ManualOperandSpeculation);
7969 LValue doubleValue = unboxDouble(value);
7970
7971 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("speculateRealNumber int case"));
7972 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("speculateRealNumber continuation"));
7973
7974 m_out.branch(
7975 m_out.doubleEqual(doubleValue, doubleValue),
7976 usually(continuation), rarely(intCase));
7977
7978 LBasicBlock lastNext = m_out.appendTo(intCase, continuation);
7979
7980 typeCheck(
7981 jsValueValue(value), m_node->child1(), SpecBytecodeRealNumber,
7982 isNotInt32(value, provenType(m_node->child1()) & ~SpecFullDouble));
7983 m_out.jump(continuation);
7984
7985 m_out.appendTo(continuation, lastNext);
7986 }
7987
7988 void speculateDoubleRepReal(Edge edge)
7989 {
7990 // Do an early return here because lowDouble() can create a lot of control flow.
7991 if (!m_interpreter.needsTypeCheck(edge))
7992 return;
7993
7994 LValue value = lowDouble(edge);
7995 FTL_TYPE_CHECK(
7996 doubleValue(value), edge, SpecDoubleReal,
7997 m_out.doubleNotEqualOrUnordered(value, value));
7998 }
7999
8000 void speculateDoubleRepMachineInt(Edge edge)
8001 {
8002 if (!m_interpreter.needsTypeCheck(edge))
8003 return;
8004
8005 doubleToStrictInt52(edge, lowDouble(edge));
8006 }
8007
8008 void speculateBoolean(Edge edge)
8009 {
8010 lowBoolean(edge);
8011 }
8012
8013 void speculateNotStringVar(Edge edge)
8014 {
8015 if (!m_interpreter.needsTypeCheck(edge, ~SpecStringVar))
8016 return;
8017
8018 LValue value = lowJSValue(edge, ManualOperandSpeculation);
8019
8020 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("Speculate NotStringVar is cell case"));
8021 LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, ("Speculate NotStringVar is string case"));
8022 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Speculate NotStringVar continuation"));
8023
8024 m_out.branch(isCell(value, provenType(edge)), unsure(isCellCase), unsure(continuation));
8025
8026 LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
8027 m_out.branch(isString(value, provenType(edge)), unsure(isStringCase), unsure(continuation));
8028
8029 m_out.appendTo(isStringCase, continuation);
8030 speculateStringIdent(edge, value, m_out.loadPtr(value, m_heaps.JSString_value));
8031 m_out.jump(continuation);
8032
8033 m_out.appendTo(continuation, lastNext);
8034 }
8035
8036 void speculateNotCell(Edge edge)
8037 {
8038 if (!m_interpreter.needsTypeCheck(edge))
8039 return;
8040
8041 LValue value = lowJSValue(edge, ManualOperandSpeculation);
8042 typeCheck(jsValueValue(value), edge, ~SpecCell, isCell(value));
8043 }
8044
8045 void speculateOther(Edge edge)
8046 {
8047 if (!m_interpreter.needsTypeCheck(edge))
8048 return;
8049
8050 LValue value = lowJSValue(edge, ManualOperandSpeculation);
8051 typeCheck(jsValueValue(value), edge, SpecOther, isNotOther(value));
8052 }
8053
8054 void speculateMisc(Edge edge)
8055 {
8056 if (!m_interpreter.needsTypeCheck(edge))
8057 return;
8058
8059 LValue value = lowJSValue(edge, ManualOperandSpeculation);
8060 typeCheck(jsValueValue(value), edge, SpecMisc, isNotMisc(value));
8061 }
8062
8063 bool masqueradesAsUndefinedWatchpointIsStillValid()
8064 {
8065 return m_graph.masqueradesAsUndefinedWatchpointIsStillValid(m_node->origin.semantic);
8066 }
8067
8068 LValue loadMarkByte(LValue base)
8069 {
8070 return m_out.load8(base, m_heaps.JSCell_gcData);
8071 }
8072
8073 void emitStoreBarrier(LValue base)
8074 {
8075#if ENABLE(GGC)
8076 LBasicBlock isMarkedAndNotRemembered = FTL_NEW_BLOCK(m_out, ("Store barrier is marked block"));
8077 LBasicBlock bufferHasSpace = FTL_NEW_BLOCK(m_out, ("Store barrier buffer has space"));
8078 LBasicBlock bufferIsFull = FTL_NEW_BLOCK(m_out, ("Store barrier buffer is full"));
8079 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Store barrier continuation"));
8080
8081 // Check the mark byte.
8082 m_out.branch(
8083 m_out.notZero8(loadMarkByte(base)), usually(continuation), rarely(isMarkedAndNotRemembered));
8084
8085 // Append to the write barrier buffer.
8086 LBasicBlock lastNext = m_out.appendTo(isMarkedAndNotRemembered, bufferHasSpace);
8087 LValue currentBufferIndex = m_out.load32(m_out.absolute(vm().heap.writeBarrierBuffer().currentIndexAddress()));
8088 LValue bufferCapacity = m_out.constInt32(vm().heap.writeBarrierBuffer().capacity());
8089 m_out.branch(
8090 m_out.lessThan(currentBufferIndex, bufferCapacity),
8091 usually(bufferHasSpace), rarely(bufferIsFull));
8092
8093 // Buffer has space, store to it.
8094 m_out.appendTo(bufferHasSpace, bufferIsFull);
8095 LValue writeBarrierBufferBase = m_out.constIntPtr(vm().heap.writeBarrierBuffer().buffer());
8096 m_out.storePtr(base, m_out.baseIndex(m_heaps.WriteBarrierBuffer_bufferContents, writeBarrierBufferBase, m_out.zeroExtPtr(currentBufferIndex)));
8097 m_out.store32(m_out.add(currentBufferIndex, m_out.constInt32(1)), m_out.absolute(vm().heap.writeBarrierBuffer().currentIndexAddress()));
8098 m_out.jump(continuation);
8099
8100 // Buffer is out of space, flush it.
8101 m_out.appendTo(bufferIsFull, continuation);
8102 vmCallNoExceptions(m_out.operation(operationFlushWriteBarrierBuffer), m_callFrame, base);
8103 m_out.jump(continuation);
8104
8105 m_out.appendTo(continuation, lastNext);
8106#else
8107 UNUSED_PARAM(base);
8108#endif
8109 }
8110
8111 template<typename... Args>
8112 LValue vmCall(LValue function, Args... args)
8113 {
8114 callPreflight();
8115 LValue result = m_out.call(function, args...);
8116 callCheck();
8117 return result;
8118 }
8119
8120 template<typename... Args>
8121 LValue vmCallNoExceptions(LValue function, Args... args)
8122 {
8123 callPreflight();
8124 LValue result = m_out.call(function, args...);
8125 return result;
8126 }
8127
8128 void callPreflight(CodeOrigin codeOrigin)
8129 {
8130 m_out.store32(
8131 m_out.constInt32(
8132 CallFrame::Location::encodeAsCodeOriginIndex(
8133 m_ftlState.jitCode->common.addCodeOrigin(codeOrigin))),
8134 tagFor(JSStack::ArgumentCount));
8135 }
8136 void callPreflight()
8137 {
8138 callPreflight(m_node->origin.semantic);
8139 }
8140
8141 void callCheck()
8142 {
8143 if (Options::enableExceptionFuzz())
8144 m_out.call(m_out.operation(operationExceptionFuzz));
8145
8146 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Exception check continuation"));
8147
8148 LValue exception = m_out.load64(m_out.absolute(vm().addressOfException()));
8149
8150 m_out.branch(
8151 m_out.notZero64(exception), rarely(m_handleExceptions), usually(continuation));
8152
8153 m_out.appendTo(continuation);
8154 }
8155
8156 LBasicBlock lowBlock(BasicBlock* block)
8157 {
8158 return m_blocks.get(block);
8159 }
8160
8161 void appendOSRExit(
8162 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
8163 {
8164 if (verboseCompilationEnabled()) {
8165 dataLog(" OSR exit #", m_ftlState.jitCode->osrExit.size(), " with availability: ", availabilityMap(), "\n");
8166 if (!m_availableRecoveries.isEmpty())
8167 dataLog(" Available recoveries: ", listDump(m_availableRecoveries), "\n");
8168 }
8169
8170 if (doOSRExitFuzzing()) {
8171 LValue numberOfFuzzChecks = m_out.add(
8172 m_out.load32(m_out.absolute(&g_numberOfOSRExitFuzzChecks)),
8173 m_out.int32One);
8174
8175 m_out.store32(numberOfFuzzChecks, m_out.absolute(&g_numberOfOSRExitFuzzChecks));
8176
8177 if (unsigned atOrAfter = Options::fireOSRExitFuzzAtOrAfter()) {
8178 failCondition = m_out.bitOr(
8179 failCondition,
8180 m_out.aboveOrEqual(numberOfFuzzChecks, m_out.constInt32(atOrAfter)));
8181 }
8182 if (unsigned at = Options::fireOSRExitFuzzAt()) {
8183 failCondition = m_out.bitOr(
8184 failCondition,
8185 m_out.equal(numberOfFuzzChecks, m_out.constInt32(at)));
8186 }
8187 }
8188
8189 ASSERT(m_ftlState.jitCode->osrExit.size() == m_ftlState.finalizer->osrExit.size());
8190
8191 m_ftlState.jitCode->osrExit.append(OSRExit(
8192 kind, lowValue.format(), m_graph.methodOfGettingAValueProfileFor(highValue),
8193 m_codeOriginForExitTarget, m_codeOriginForExitProfile,
8194 availabilityMap().m_locals.numberOfArguments(),
8195 availabilityMap().m_locals.numberOfLocals()));
8196 m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo());
8197
8198 OSRExit& exit = m_ftlState.jitCode->osrExit.last();
8199
8200 LBasicBlock lastNext = nullptr;
8201 LBasicBlock continuation = nullptr;
8202
8203 LBasicBlock failCase = FTL_NEW_BLOCK(m_out, ("OSR exit failCase for ", m_node));
8204 continuation = FTL_NEW_BLOCK(m_out, ("OSR exit continuation for ", m_node));
8205
8206 m_out.branch(failCondition, rarely(failCase), usually(continuation));
8207
8208 lastNext = m_out.appendTo(failCase, continuation);
8209
8210 emitOSRExitCall(exit, lowValue);
8211
8212 m_out.unreachable();
8213
8214 m_out.appendTo(continuation, lastNext);
8215 }
8216
8217 void emitOSRExitCall(OSRExit& exit, FormattedValue lowValue)
8218 {
8219 ExitArgumentList arguments;
8220
8221 CodeOrigin codeOrigin = exit.m_codeOrigin;
8222
8223 buildExitArguments(exit, arguments, lowValue, codeOrigin);
8224
8225 callStackmap(exit, arguments);
8226 }
8227
8228 void buildExitArguments(
8229 OSRExit& exit, ExitArgumentList& arguments, FormattedValue lowValue,
8230 CodeOrigin codeOrigin)
8231 {
8232 if (!!lowValue)
8233 arguments.append(lowValue.value());
8234
8235 AvailabilityMap availabilityMap = this->availabilityMap();
8236 availabilityMap.pruneByLiveness(m_graph, codeOrigin);
8237
8238 HashMap<Node*, ExitTimeObjectMaterialization*> map;
8239 availabilityMap.forEachAvailability(
8240 [&] (Availability availability) {
8241 if (!availability.shouldUseNode())
8242 return;
8243
8244 Node* node = availability.node();
8245 if (!node->isPhantomAllocation())
8246 return;
8247
8248 auto result = map.add(node, nullptr);
8249 if (result.isNewEntry) {
8250 result.iterator->value =
8251 exit.m_materializations.add(node->op(), node->origin.semantic);
8252 }
8253 });
8254
8255 for (unsigned i = 0; i < exit.m_values.size(); ++i) {
8256 int operand = exit.m_values.operandForIndex(i);
8257
8258 Availability availability = availabilityMap.m_locals[i];
8259
8260 if (Options::validateFTLOSRExitLiveness()) {
8261 DFG_ASSERT(
8262 m_graph, m_node,
8263 (!(availability.isDead() && m_graph.isLiveInBytecode(VirtualRegister(operand), codeOrigin))) || m_graph.m_plan.mode == FTLForOSREntryMode);
8264 }
8265
8266 exit.m_values[i] = exitValueForAvailability(arguments, map, availability);
8267 }
8268
8269 for (auto heapPair : availabilityMap.m_heap) {
8270 Node* node = heapPair.key.base();
8271 ExitTimeObjectMaterialization* materialization = map.get(node);
8272 materialization->add(
8273 heapPair.key.descriptor(),
8274 exitValueForAvailability(arguments, map, heapPair.value));
8275 }
8276
8277 if (verboseCompilationEnabled()) {
8278 dataLog(" Exit values: ", exit.m_values, "\n");
8279 if (!exit.m_materializations.isEmpty()) {
8280 dataLog(" Materializations: \n");
8281 for (ExitTimeObjectMaterialization* materialization : exit.m_materializations)
8282 dataLog(" ", pointerDump(materialization), "\n");
8283 }
8284 }
8285 }
8286
8287 void callStackmap(OSRExit& exit, ExitArgumentList& arguments)
8288 {
8289 exit.m_stackmapID = m_stackmapIDs++;
8290 arguments.insert(0, m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
8291 arguments.insert(0, m_out.constInt64(exit.m_stackmapID));
8292
8293 m_out.call(m_out.stackmapIntrinsic(), arguments);
8294 }
8295
8296 ExitValue exitValueForAvailability(
8297 ExitArgumentList& arguments, const HashMap<Node*, ExitTimeObjectMaterialization*>& map,
8298 Availability availability)
8299 {
8300 FlushedAt flush = availability.flushedAt();
8301 switch (flush.format()) {
8302 case DeadFlush:
8303 case ConflictingFlush:
8304 if (availability.hasNode())
8305 return exitValueForNode(arguments, map, availability.node());
8306
8307 // This means that the value is dead. It could be dead in bytecode or it could have
8308 // been killed by our DCE, which can sometimes kill things even if they were live in
8309 // bytecode.
8310 return ExitValue::dead();
8311
8312 case FlushedJSValue:
8313 case FlushedCell:
8314 case FlushedBoolean:
8315 return ExitValue::inJSStack(flush.virtualRegister());
8316
8317 case FlushedInt32:
8318 return ExitValue::inJSStackAsInt32(flush.virtualRegister());
8319
8320 case FlushedInt52:
8321 return ExitValue::inJSStackAsInt52(flush.virtualRegister());
8322
8323 case FlushedDouble:
8324 return ExitValue::inJSStackAsDouble(flush.virtualRegister());
8325 }
8326
8327 DFG_CRASH(m_graph, m_node, "Invalid flush format");
8328 return ExitValue::dead();
8329 }
8330
8331 ExitValue exitValueForNode(
8332 ExitArgumentList& arguments, const HashMap<Node*, ExitTimeObjectMaterialization*>& map,
8333 Node* node)
8334 {
8335 ASSERT(node->shouldGenerate());
8336 ASSERT(node->hasResult());
8337
8338 if (node) {
8339 switch (node->op()) {
8340 case BottomValue:
8341 // This might arise in object materializations. I actually doubt that it would,
8342 // but it seems worthwhile to be conservative.
8343 return ExitValue::dead();
8344
8345 case JSConstant:
8346 case Int52Constant:
8347 case DoubleConstant:
8348 return ExitValue::constant(node->asJSValue());
8349
8350 default:
8351 if (node->isPhantomAllocation())
8352 return ExitValue::materializeNewObject(map.get(node));
8353 break;
8354 }
8355 }
8356
8357 for (unsigned i = 0; i < m_availableRecoveries.size(); ++i) {
8358 AvailableRecovery recovery = m_availableRecoveries[i];
8359 if (recovery.node() != node)
8360 continue;
8361
8362 ExitValue result = ExitValue::recovery(
8363 recovery.opcode(), arguments.size(), arguments.size() + 1,
8364 recovery.format());
8365 arguments.append(recovery.left());
8366 arguments.append(recovery.right());
8367 return result;
8368 }
8369
8370 LoweredNodeValue value = m_int32Values.get(node);
8371 if (isValid(value))
8372 return exitArgument(arguments, ValueFormatInt32, value.value());
8373
8374 value = m_int52Values.get(node);
8375 if (isValid(value))
8376 return exitArgument(arguments, ValueFormatInt52, value.value());
8377
8378 value = m_strictInt52Values.get(node);
8379 if (isValid(value))
8380 return exitArgument(arguments, ValueFormatStrictInt52, value.value());
8381
8382 value = m_booleanValues.get(node);
8383 if (isValid(value)) {
8384 LValue valueToPass = m_out.zeroExt(value.value(), m_out.int32);
8385 return exitArgument(arguments, ValueFormatBoolean, valueToPass);
8386 }
8387
8388 value = m_jsValueValues.get(node);
8389 if (isValid(value))
8390 return exitArgument(arguments, ValueFormatJSValue, value.value());
8391
8392 value = m_doubleValues.get(node);
8393 if (isValid(value))
8394 return exitArgument(arguments, ValueFormatDouble, value.value());
8395
8396 DFG_CRASH(m_graph, m_node, toCString("Cannot find value for node: ", node).data());
8397 return ExitValue::dead();
8398 }
8399
8400 ExitValue exitArgument(ExitArgumentList& arguments, ValueFormat format, LValue value)
8401 {
8402 ExitValue result = ExitValue::exitArgument(ExitArgument(format, arguments.size()));
8403 arguments.append(value);
8404 return result;
8405 }
8406
8407 bool doesKill(Edge edge)
8408 {
8409 if (edge.doesNotKill())
8410 return false;
8411
8412 if (edge->hasConstant())
8413 return false;
8414
8415 return true;
8416 }
8417
8418 void addAvailableRecovery(
8419 Node* node, RecoveryOpcode opcode, LValue left, LValue right, ValueFormat format)
8420 {
8421 m_availableRecoveries.append(AvailableRecovery(node, opcode, left, right, format));
8422 }
8423
8424 void addAvailableRecovery(
8425 Edge edge, RecoveryOpcode opcode, LValue left, LValue right, ValueFormat format)
8426 {
8427 addAvailableRecovery(edge.node(), opcode, left, right, format);
8428 }
8429
8430 void setInt32(Node* node, LValue value)
8431 {
8432 m_int32Values.set(node, LoweredNodeValue(value, m_highBlock));
8433 }
8434 void setInt52(Node* node, LValue value)
8435 {
8436 m_int52Values.set(node, LoweredNodeValue(value, m_highBlock));
8437 }
8438 void setStrictInt52(Node* node, LValue value)
8439 {
8440 m_strictInt52Values.set(node, LoweredNodeValue(value, m_highBlock));
8441 }
8442 void setInt52(Node* node, LValue value, Int52Kind kind)
8443 {
8444 switch (kind) {
8445 case Int52:
8446 setInt52(node, value);
8447 return;
8448
8449 case StrictInt52:
8450 setStrictInt52(node, value);
8451 return;
8452 }
8453
8454 DFG_CRASH(m_graph, m_node, "Corrupt int52 kind");
8455 }
8456 void setJSValue(Node* node, LValue value)
8457 {
8458 m_jsValueValues.set(node, LoweredNodeValue(value, m_highBlock));
8459 }
8460 void setBoolean(Node* node, LValue value)
8461 {
8462 m_booleanValues.set(node, LoweredNodeValue(value, m_highBlock));
8463 }
8464 void setStorage(Node* node, LValue value)
8465 {
8466 m_storageValues.set(node, LoweredNodeValue(value, m_highBlock));
8467 }
8468 void setDouble(Node* node, LValue value)
8469 {
8470 m_doubleValues.set(node, LoweredNodeValue(value, m_highBlock));
8471 }
8472
8473 void setInt32(LValue value)
8474 {
8475 setInt32(m_node, value);
8476 }
8477 void setInt52(LValue value)
8478 {
8479 setInt52(m_node, value);
8480 }
8481 void setStrictInt52(LValue value)
8482 {
8483 setStrictInt52(m_node, value);
8484 }
8485 void setInt52(LValue value, Int52Kind kind)
8486 {
8487 setInt52(m_node, value, kind);
8488 }
8489 void setJSValue(LValue value)
8490 {
8491 setJSValue(m_node, value);
8492 }
8493 void setBoolean(LValue value)
8494 {
8495 setBoolean(m_node, value);
8496 }
8497 void setStorage(LValue value)
8498 {
8499 setStorage(m_node, value);
8500 }
8501 void setDouble(LValue value)
8502 {
8503 setDouble(m_node, value);
8504 }
8505
8506 bool isValid(const LoweredNodeValue& value)
8507 {
8508 if (!value)
8509 return false;
8510 if (!m_graph.m_dominators.dominates(value.block(), m_highBlock))
8511 return false;
8512 return true;
8513 }
8514
8515 void addWeakReference(JSCell* target)
8516 {
8517 m_graph.m_plan.weakReferences.addLazily(target);
8518 }
8519
8520 LValue loadStructure(LValue value)
8521 {
8522 LValue tableIndex = m_out.load32(value, m_heaps.JSCell_structureID);
8523 LValue tableBase = m_out.loadPtr(
8524 m_out.absolute(vm().heap.structureIDTable().base()));
8525 TypedPointer address = m_out.baseIndex(
8526 m_heaps.structureTable, tableBase, m_out.zeroExtPtr(tableIndex));
8527 return m_out.loadPtr(address);
8528 }
8529
8530 LValue weakPointer(JSCell* pointer)
8531 {
8532 addWeakReference(pointer);
8533 return m_out.constIntPtr(pointer);
8534 }
8535
8536 LValue weakStructureID(Structure* structure)
8537 {
8538 addWeakReference(structure);
8539 return m_out.constInt32(structure->id());
8540 }
8541
8542 LValue weakStructure(Structure* structure)
8543 {
8544 return weakPointer(structure);
8545 }
8546
8547 TypedPointer addressFor(LValue base, int operand, ptrdiff_t offset = 0)
8548 {
8549 return m_out.address(base, m_heaps.variables[operand], offset);
8550 }
8551 TypedPointer payloadFor(LValue base, int operand)
8552 {
8553 return addressFor(base, operand, PayloadOffset);
8554 }
8555 TypedPointer tagFor(LValue base, int operand)
8556 {
8557 return addressFor(base, operand, TagOffset);
8558 }
8559 TypedPointer addressFor(int operand, ptrdiff_t offset = 0)
8560 {
8561 return addressFor(VirtualRegister(operand), offset);
8562 }
8563 TypedPointer addressFor(VirtualRegister operand, ptrdiff_t offset = 0)
8564 {
8565 if (operand.isLocal())
8566 return addressFor(m_captured, operand.offset(), offset);
8567 return addressFor(m_callFrame, operand.offset(), offset);
8568 }
8569 TypedPointer payloadFor(int operand)
8570 {
8571 return payloadFor(VirtualRegister(operand));
8572 }
8573 TypedPointer payloadFor(VirtualRegister operand)
8574 {
8575 return addressFor(operand, PayloadOffset);
8576 }
8577 TypedPointer tagFor(int operand)
8578 {
8579 return tagFor(VirtualRegister(operand));
8580 }
8581 TypedPointer tagFor(VirtualRegister operand)
8582 {
8583 return addressFor(operand, TagOffset);
8584 }
8585
8586 AbstractValue abstractValue(Node* node)
8587 {
8588 return m_state.forNode(node);
8589 }
8590 AbstractValue abstractValue(Edge edge)
8591 {
8592 return abstractValue(edge.node());
8593 }
8594
8595 SpeculatedType provenType(Node* node)
8596 {
8597 return abstractValue(node).m_type;
8598 }
8599 SpeculatedType provenType(Edge edge)
8600 {
8601 return provenType(edge.node());
8602 }
8603
8604 JSValue provenValue(Node* node)
8605 {
8606 return abstractValue(node).m_value;
8607 }
8608 JSValue provenValue(Edge edge)
8609 {
8610 return provenValue(edge.node());
8611 }
8612
8613 StructureAbstractValue abstractStructure(Node* node)
8614 {
8615 return abstractValue(node).m_structure;
8616 }
8617 StructureAbstractValue abstractStructure(Edge edge)
8618 {
8619 return abstractStructure(edge.node());
8620 }
8621
8622 void crash()
8623 {
8624 crash(m_highBlock->index, m_node->index());
8625 }
8626 void crash(BlockIndex blockIndex, unsigned nodeIndex)
8627 {
8628#if ASSERT_DISABLED
8629 m_out.call(m_out.operation(ftlUnreachable));
8630 UNUSED_PARAM(blockIndex);
8631 UNUSED_PARAM(nodeIndex);
8632#else
8633 m_out.call(
8634 m_out.intToPtr(
8635 m_out.constIntPtr(ftlUnreachable),
8636 pointerType(
8637 functionType(
8638 m_out.voidType, m_out.intPtr, m_out.int32, m_out.int32))),
8639 m_out.constIntPtr(codeBlock()), m_out.constInt32(blockIndex),
8640 m_out.constInt32(nodeIndex));
8641#endif
8642 m_out.unreachable();
8643 }
8644
8645 AvailabilityMap& availabilityMap() { return m_availabilityCalculator.m_availability; }
8646
8647 VM& vm() { return m_graph.m_vm; }
8648 CodeBlock* codeBlock() { return m_graph.m_codeBlock; }
8649
8650 Graph& m_graph;
8651 State& m_ftlState;
8652 AbstractHeapRepository m_heaps;
8653 Output m_out;
8654
8655 LBasicBlock m_prologue;
8656 LBasicBlock m_handleExceptions;
8657 HashMap<BasicBlock*, LBasicBlock> m_blocks;
8658
8659 LValue m_execState;
8660 LValue m_execStorage;
8661 LValue m_callFrame;
8662 LValue m_captured;
8663 LValue m_tagTypeNumber;
8664 LValue m_tagMask;
8665
8666 HashMap<Node*, LoweredNodeValue> m_int32Values;
8667 HashMap<Node*, LoweredNodeValue> m_strictInt52Values;
8668 HashMap<Node*, LoweredNodeValue> m_int52Values;
8669 HashMap<Node*, LoweredNodeValue> m_jsValueValues;
8670 HashMap<Node*, LoweredNodeValue> m_booleanValues;
8671 HashMap<Node*, LoweredNodeValue> m_storageValues;
8672 HashMap<Node*, LoweredNodeValue> m_doubleValues;
8673
8674 // This is a bit of a hack. It prevents LLVM from having to do CSE on loading of arguments.
8675 // It's nice to have these optimizations on our end because we can guarantee them a bit better.
8676 // Probably also saves LLVM compile time.
8677 HashMap<Node*, LValue> m_loadedArgumentValues;
8678
8679 HashMap<Node*, LValue> m_phis;
8680
8681 LocalOSRAvailabilityCalculator m_availabilityCalculator;
8682
8683 Vector<AvailableRecovery, 3> m_availableRecoveries;
8684
8685 InPlaceAbstractState m_state;
8686 AbstractInterpreter<InPlaceAbstractState> m_interpreter;
8687 BasicBlock* m_highBlock;
8688 BasicBlock* m_nextHighBlock;
8689 LBasicBlock m_nextLowBlock;
8690
8691 CodeOrigin m_codeOriginForExitTarget;
8692 CodeOrigin m_codeOriginForExitProfile;
8693 unsigned m_nodeIndex;
8694 Node* m_node;
8695
8696 uint32_t m_stackmapIDs;
8697 unsigned m_tbaaKind;
8698 unsigned m_tbaaStructKind;
8699};
8700
8701} // anonymous namespace
8702
8703void lowerDFGToLLVM(State& state)
8704{
8705 LowerDFGToLLVM lowering(state);
8706 lowering.lower();
8707}
8708
8709} } // namespace JSC::FTL
8710
8711#endif // ENABLE(FTL_JIT)
8712