[JSC] Introduce LinkTimeConstant mechanism
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGByteCodeParser.cpp
1 /*
2  * Copyright (C) 2011-2019 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 "DFGByteCodeParser.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "ArithProfile.h"
32 #include "ArrayConstructor.h"
33 #include "BasicBlockLocation.h"
34 #include "BuiltinNames.h"
35 #include "BytecodeGenerator.h"
36 #include "CallLinkStatus.h"
37 #include "CodeBlock.h"
38 #include "CodeBlockWithJITType.h"
39 #include "CommonSlowPaths.h"
40 #include "DFGAbstractHeap.h"
41 #include "DFGArrayMode.h"
42 #include "DFGCFG.h"
43 #include "DFGCapabilities.h"
44 #include "DFGClobberize.h"
45 #include "DFGClobbersExitState.h"
46 #include "DFGGraph.h"
47 #include "DFGJITCode.h"
48 #include "FunctionCodeBlock.h"
49 #include "GetByIdStatus.h"
50 #include "GetterSetter.h"
51 #include "Heap.h"
52 #include "InByIdStatus.h"
53 #include "InstanceOfStatus.h"
54 #include "JSCInlines.h"
55 #include "JSFixedArray.h"
56 #include "JSImmutableButterfly.h"
57 #include "JSInternalPromise.h"
58 #include "JSInternalPromiseConstructor.h"
59 #include "JSModuleEnvironment.h"
60 #include "JSModuleNamespaceObject.h"
61 #include "JSPromiseConstructor.h"
62 #include "NumberConstructor.h"
63 #include "ObjectConstructor.h"
64 #include "OpcodeInlines.h"
65 #include "PreciseJumpTargets.h"
66 #include "PutByIdFlags.h"
67 #include "PutByIdStatus.h"
68 #include "RegExpPrototype.h"
69 #include "StackAlignment.h"
70 #include "StringConstructor.h"
71 #include "StructureStubInfo.h"
72 #include "SymbolConstructor.h"
73 #include "Watchdog.h"
74 #include <wtf/CommaPrinter.h>
75 #include <wtf/HashMap.h>
76 #include <wtf/MathExtras.h>
77 #include <wtf/SetForScope.h>
78 #include <wtf/StdLibExtras.h>
79
80 namespace JSC { namespace DFG {
81
82 namespace DFGByteCodeParserInternal {
83 #ifdef NDEBUG
84 static constexpr bool verbose = false;
85 #else
86 static constexpr bool verbose = true;
87 #endif
88 } // namespace DFGByteCodeParserInternal
89
90 #define VERBOSE_LOG(...) do { \
91 if (DFGByteCodeParserInternal::verbose && Options::verboseDFGBytecodeParsing()) \
92 dataLog(__VA_ARGS__); \
93 } while (false)
94
95 // === ByteCodeParser ===
96 //
97 // This class is used to compile the dataflow graph from a CodeBlock.
98 class ByteCodeParser {
99 public:
100     ByteCodeParser(Graph& graph)
101         : m_vm(&graph.m_vm)
102         , m_codeBlock(graph.m_codeBlock)
103         , m_profiledBlock(graph.m_profiledBlock)
104         , m_graph(graph)
105         , m_currentBlock(0)
106         , m_currentIndex(0)
107         , m_constantUndefined(graph.freeze(jsUndefined()))
108         , m_constantNull(graph.freeze(jsNull()))
109         , m_constantNaN(graph.freeze(jsNumber(PNaN)))
110         , m_constantOne(graph.freeze(jsNumber(1)))
111         , m_numArguments(m_codeBlock->numParameters())
112         , m_numLocals(m_codeBlock->numCalleeLocals())
113         , m_parameterSlots(0)
114         , m_numPassedVarArgs(0)
115         , m_inlineStackTop(0)
116         , m_currentInstruction(0)
117         , m_hasDebuggerEnabled(graph.hasDebuggerEnabled())
118     {
119         ASSERT(m_profiledBlock);
120     }
121     
122     // Parse a full CodeBlock of bytecode.
123     void parse();
124     
125 private:
126     struct InlineStackEntry;
127
128     // Just parse from m_currentIndex to the end of the current CodeBlock.
129     void parseCodeBlock();
130     
131     void ensureLocals(unsigned newNumLocals)
132     {
133         VERBOSE_LOG("   ensureLocals: trying to raise m_numLocals from ", m_numLocals, " to ", newNumLocals, "\n");
134         if (newNumLocals <= m_numLocals)
135             return;
136         m_numLocals = newNumLocals;
137         for (size_t i = 0; i < m_graph.numBlocks(); ++i)
138             m_graph.block(i)->ensureLocals(newNumLocals);
139     }
140
141     // Helper for min and max.
142     template<typename ChecksFunctor>
143     bool handleMinMax(VirtualRegister result, NodeType op, int registerOffset, int argumentCountIncludingThis, const ChecksFunctor& insertChecks);
144     
145     void refineStatically(CallLinkStatus&, Node* callTarget);
146     // Blocks can either be targetable (i.e. in the m_blockLinkingTargets of one InlineStackEntry) with a well-defined bytecodeBegin,
147     // or they can be untargetable, with bytecodeBegin==UINT_MAX, to be managed manually and not by the linkBlock machinery.
148     // This is used most notably when doing polyvariant inlining (it requires a fair bit of control-flow with no bytecode analog).
149     // It is also used when doing an early return from an inlined callee: it is easier to fix the bytecode index later on if needed
150     // than to move the right index all the way to the treatment of op_ret.
151     BasicBlock* allocateTargetableBlock(BytecodeIndex);
152     BasicBlock* allocateUntargetableBlock();
153     // An untargetable block can be given a bytecodeIndex to be later managed by linkBlock, but only once, and it can never go in the other direction
154     void makeBlockTargetable(BasicBlock*, BytecodeIndex);
155     void addJumpTo(BasicBlock*);
156     void addJumpTo(unsigned bytecodeIndex);
157     // Handle calls. This resolves issues surrounding inlining and intrinsics.
158     enum Terminality { Terminal, NonTerminal };
159     Terminality handleCall(
160         VirtualRegister result, NodeType op, InlineCallFrame::Kind, unsigned instructionSize,
161         Node* callTarget, int argumentCountIncludingThis, int registerOffset, CallLinkStatus,
162         SpeculatedType prediction);
163     template<typename CallOp>
164     Terminality handleCall(const Instruction* pc, NodeType op, CallMode);
165     template<typename CallOp>
166     Terminality handleVarargsCall(const Instruction* pc, NodeType op, CallMode);
167     void emitFunctionChecks(CallVariant, Node* callTarget, VirtualRegister thisArgumnt);
168     void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis);
169     Node* getArgumentCount();
170     template<typename ChecksFunctor>
171     bool handleRecursiveTailCall(Node* callTargetNode, CallVariant, int registerOffset, int argumentCountIncludingThis, const ChecksFunctor& emitFunctionCheckIfNeeded);
172     unsigned inliningCost(CallVariant, int argumentCountIncludingThis, InlineCallFrame::Kind); // Return UINT_MAX if it's not an inlining candidate. By convention, intrinsics have a cost of 1.
173     // Handle inlining. Return true if it succeeded, false if we need to plant a call.
174     bool handleVarargsInlining(Node* callTargetNode, VirtualRegister result, const CallLinkStatus&, int registerOffset, VirtualRegister thisArgument, VirtualRegister argumentsArgument, unsigned argumentsOffset, NodeType callOp, InlineCallFrame::Kind);
175     unsigned getInliningBalance(const CallLinkStatus&, CodeSpecializationKind);
176     enum class CallOptimizationResult { OptimizedToJump, Inlined, DidNothing };
177     CallOptimizationResult handleCallVariant(Node* callTargetNode, VirtualRegister result, CallVariant, int registerOffset, VirtualRegister thisArgument, int argumentCountIncludingThis, BytecodeIndex nextIndex, InlineCallFrame::Kind, SpeculatedType prediction, unsigned& inliningBalance, BasicBlock* continuationBlock, bool needsToCheckCallee);
178     CallOptimizationResult handleInlining(Node* callTargetNode, VirtualRegister result, const CallLinkStatus&, int registerOffset, VirtualRegister thisArgument, int argumentCountIncludingThis, BytecodeIndex nextIndex, NodeType callOp, InlineCallFrame::Kind, SpeculatedType prediction);
179     template<typename ChecksFunctor>
180     void inlineCall(Node* callTargetNode, VirtualRegister result, CallVariant, int registerOffset, int argumentCountIncludingThis, InlineCallFrame::Kind, BasicBlock* continuationBlock, const ChecksFunctor& insertChecks);
181     // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call.
182     template<typename ChecksFunctor>
183     bool handleIntrinsicCall(Node* callee, VirtualRegister result, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks);
184     template<typename ChecksFunctor>
185     bool handleDOMJITCall(Node* callee, VirtualRegister result, const DOMJIT::Signature*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks);
186     template<typename ChecksFunctor>
187     bool handleIntrinsicGetter(VirtualRegister result, SpeculatedType prediction, const GetByIdVariant& intrinsicVariant, Node* thisNode, const ChecksFunctor& insertChecks);
188     template<typename ChecksFunctor>
189     bool handleTypedArrayConstructor(VirtualRegister result, InternalFunction*, int registerOffset, int argumentCountIncludingThis, TypedArrayType, const ChecksFunctor& insertChecks);
190     template<typename ChecksFunctor>
191     bool handleConstantInternalFunction(Node* callTargetNode, VirtualRegister result, InternalFunction*, int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind, SpeculatedType, const ChecksFunctor& insertChecks);
192     Node* handlePutByOffset(Node* base, unsigned identifier, PropertyOffset, Node* value);
193     Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset, NodeType = GetByOffset);
194     bool handleDOMJITGetter(VirtualRegister result, const GetByIdVariant&, Node* thisNode, unsigned identifierNumber, SpeculatedType prediction);
195     bool handleModuleNamespaceLoad(VirtualRegister result, SpeculatedType, Node* base, GetByIdStatus);
196
197     template<typename Bytecode>
198     void handlePutByVal(Bytecode, unsigned instructionSize);
199     template <typename Bytecode>
200     void handlePutAccessorById(NodeType, Bytecode);
201     template <typename Bytecode>
202     void handlePutAccessorByVal(NodeType, Bytecode);
203     template <typename Bytecode>
204     void handleNewFunc(NodeType, Bytecode);
205     template <typename Bytecode>
206     void handleNewFuncExp(NodeType, Bytecode);
207     template <typename Bytecode>
208     void handleCreateInternalFieldObject(const ClassInfo*, NodeType createOp, NodeType newOp, Bytecode);
209
210     // Create a presence ObjectPropertyCondition based on some known offset and structure set. Does not
211     // check the validity of the condition, but it may return a null one if it encounters a contradiction.
212     ObjectPropertyCondition presenceLike(
213         JSObject* knownBase, UniquedStringImpl*, PropertyOffset, const StructureSet&);
214     
215     // Attempt to watch the presence of a property. It will watch that the property is present in the same
216     // way as in all of the structures in the set. It may emit code instead of just setting a watchpoint.
217     // Returns true if this all works out.
218     bool checkPresenceLike(JSObject* knownBase, UniquedStringImpl*, PropertyOffset, const StructureSet&);
219     void checkPresenceLike(Node* base, UniquedStringImpl*, PropertyOffset, const StructureSet&);
220     
221     // Works with both GetByIdVariant and the setter form of PutByIdVariant.
222     template<typename VariantType>
223     Node* load(SpeculatedType, Node* base, unsigned identifierNumber, const VariantType&);
224
225     Node* store(Node* base, unsigned identifier, const PutByIdVariant&, Node* value);
226
227     template<typename Op>
228     void parseGetById(const Instruction*);
229     void handleGetById(
230         VirtualRegister destination, SpeculatedType, Node* base, unsigned identifierNumber, GetByIdStatus, AccessType, unsigned instructionSize);
231     void emitPutById(
232         Node* base, unsigned identifierNumber, Node* value,  const PutByIdStatus&, bool isDirect);
233     void handlePutById(
234         Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus&,
235         bool isDirect, unsigned intructionSize);
236     
237     // Either register a watchpoint or emit a check for this condition. Returns false if the
238     // condition no longer holds, and therefore no reasonable check can be emitted.
239     bool check(const ObjectPropertyCondition&);
240     
241     GetByOffsetMethod promoteToConstant(GetByOffsetMethod);
242     
243     // Either register a watchpoint or emit a check for this condition. It must be a Presence
244     // condition. It will attempt to promote a Presence condition to an Equivalence condition.
245     // Emits code for the loaded value that the condition guards, and returns a node containing
246     // the loaded value. Returns null if the condition no longer holds.
247     GetByOffsetMethod planLoad(const ObjectPropertyCondition&);
248     Node* load(SpeculatedType, unsigned identifierNumber, const GetByOffsetMethod&, NodeType = GetByOffset);
249     Node* load(SpeculatedType, const ObjectPropertyCondition&, NodeType = GetByOffset);
250     
251     // Calls check() for each condition in the set: that is, it either emits checks or registers
252     // watchpoints (or a combination of the two) to make the conditions hold. If any of those
253     // conditions are no longer checkable, returns false.
254     bool check(const ObjectPropertyConditionSet&);
255     
256     // Calls check() for those conditions that aren't the slot base, and calls load() for the slot
257     // base. Does a combination of watchpoint registration and check emission to guard the
258     // conditions, and emits code to load the value from the slot base. Returns a node containing
259     // the loaded value. Returns null if any of the conditions were no longer checkable.
260     GetByOffsetMethod planLoad(const ObjectPropertyConditionSet&);
261     Node* load(SpeculatedType, const ObjectPropertyConditionSet&, NodeType = GetByOffset);
262
263     void prepareToParseBlock();
264     void clearCaches();
265
266     // Parse a single basic block of bytecode instructions.
267     void parseBlock(unsigned limit);
268     // Link block successors.
269     void linkBlock(BasicBlock*, Vector<BasicBlock*>& possibleTargets);
270     void linkBlocks(Vector<BasicBlock*>& unlinkedBlocks, Vector<BasicBlock*>& possibleTargets);
271     
272     VariableAccessData* newVariableAccessData(VirtualRegister operand)
273     {
274         ASSERT(!operand.isConstant());
275         
276         m_graph.m_variableAccessData.append(operand);
277         return &m_graph.m_variableAccessData.last();
278     }
279     
280     // Get/Set the operands/result of a bytecode instruction.
281     Node* getDirect(VirtualRegister operand)
282     {
283         ASSERT(!operand.isConstant());
284
285         // Is this an argument?
286         if (operand.isArgument())
287             return getArgument(operand);
288
289         // Must be a local.
290         return getLocal(operand);
291     }
292
293     Node* get(VirtualRegister operand)
294     {
295         if (operand.isConstant()) {
296             unsigned constantIndex = operand.toConstantIndex();
297             unsigned oldSize = m_constants.size();
298             if (constantIndex >= oldSize || !m_constants[constantIndex]) {
299                 const CodeBlock& codeBlock = *m_inlineStackTop->m_codeBlock;
300                 JSValue value = codeBlock.getConstant(operand.offset());
301                 SourceCodeRepresentation sourceCodeRepresentation = codeBlock.constantSourceCodeRepresentation(operand.offset());
302                 if (constantIndex >= oldSize) {
303                     m_constants.grow(constantIndex + 1);
304                     for (unsigned i = oldSize; i < m_constants.size(); ++i)
305                         m_constants[i] = nullptr;
306                 }
307
308                 Node* constantNode = nullptr;
309                 if (sourceCodeRepresentation == SourceCodeRepresentation::Double)
310                     constantNode = addToGraph(DoubleConstant, OpInfo(m_graph.freezeStrong(jsDoubleNumber(value.asNumber()))));
311                 else
312                     constantNode = addToGraph(JSConstant, OpInfo(m_graph.freezeStrong(value)));
313                 m_constants[constantIndex] = constantNode;
314             }
315             ASSERT(m_constants[constantIndex]);
316             return m_constants[constantIndex];
317         }
318         
319         if (inlineCallFrame()) {
320             if (!inlineCallFrame()->isClosureCall) {
321                 JSFunction* callee = inlineCallFrame()->calleeConstant();
322                 if (operand.offset() == CallFrameSlot::callee)
323                     return weakJSConstant(callee);
324             }
325         } else if (operand.offset() == CallFrameSlot::callee) {
326             // We have to do some constant-folding here because this enables CreateThis folding. Note
327             // that we don't have such watchpoint-based folding for inlined uses of Callee, since in that
328             // case if the function is a singleton then we already know it.
329             if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(*m_vm, m_codeBlock->ownerExecutable())) {
330                 if (JSFunction* function = executable->singleton().inferredValue()) {
331                     m_graph.watchpoints().addLazily(executable);
332                     return weakJSConstant(function);
333                 }
334             }
335             return addToGraph(GetCallee);
336         }
337         
338         return getDirect(m_inlineStackTop->remapOperand(operand));
339     }
340     
341     enum SetMode {
342         // A normal set which follows a two-phase commit that spans code origins. During
343         // the current code origin it issues a MovHint, and at the start of the next
344         // code origin there will be a SetLocal. If the local needs flushing, the second
345         // SetLocal will be preceded with a Flush.
346         NormalSet,
347         
348         // A set where the SetLocal happens immediately and there is still a Flush. This
349         // is relevant when assigning to a local in tricky situations for the delayed
350         // SetLocal logic but where we know that we have not performed any side effects
351         // within this code origin. This is a safe replacement for NormalSet anytime we
352         // know that we have not yet performed side effects in this code origin.
353         ImmediateSetWithFlush,
354         
355         // A set where the SetLocal happens immediately and we do not Flush it even if
356         // this is a local that is marked as needing it. This is relevant when
357         // initializing locals at the top of a function.
358         ImmediateNakedSet
359     };
360     Node* setDirect(VirtualRegister operand, Node* value, SetMode setMode = NormalSet)
361     {
362         addToGraph(MovHint, OpInfo(operand.offset()), value);
363
364         // We can't exit anymore because our OSR exit state has changed.
365         m_exitOK = false;
366
367         DelayedSetLocal delayed(currentCodeOrigin(), operand, value, setMode);
368         
369         if (setMode == NormalSet) {
370             m_setLocalQueue.append(delayed);
371             return nullptr;
372         }
373         
374         return delayed.execute(this);
375     }
376     
377     void processSetLocalQueue()
378     {
379         for (unsigned i = 0; i < m_setLocalQueue.size(); ++i)
380             m_setLocalQueue[i].execute(this);
381         m_setLocalQueue.shrink(0);
382     }
383
384     Node* set(VirtualRegister operand, Node* value, SetMode setMode = NormalSet)
385     {
386         return setDirect(m_inlineStackTop->remapOperand(operand), value, setMode);
387     }
388     
389     Node* injectLazyOperandSpeculation(Node* node)
390     {
391         ASSERT(node->op() == GetLocal);
392         ASSERT(node->origin.semantic.bytecodeIndex() == m_currentIndex);
393         ConcurrentJSLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
394         LazyOperandValueProfileKey key(m_currentIndex, node->local());
395         SpeculatedType prediction = m_inlineStackTop->m_lazyOperands.prediction(locker, key);
396         node->variableAccessData()->predict(prediction);
397         return node;
398     }
399
400     // Used in implementing get/set, above, where the operand is a local variable.
401     Node* getLocal(VirtualRegister operand)
402     {
403         unsigned local = operand.toLocal();
404
405         Node* node = m_currentBlock->variablesAtTail.local(local);
406         
407         // This has two goals: 1) link together variable access datas, and 2)
408         // try to avoid creating redundant GetLocals. (1) is required for
409         // correctness - no other phase will ensure that block-local variable
410         // access data unification is done correctly. (2) is purely opportunistic
411         // and is meant as an compile-time optimization only.
412         
413         VariableAccessData* variable;
414         
415         if (node) {
416             variable = node->variableAccessData();
417             
418             switch (node->op()) {
419             case GetLocal:
420                 return node;
421             case SetLocal:
422                 return node->child1().node();
423             default:
424                 break;
425             }
426         } else
427             variable = newVariableAccessData(operand);
428         
429         node = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variable)));
430         m_currentBlock->variablesAtTail.local(local) = node;
431         return node;
432     }
433     Node* setLocal(const CodeOrigin& semanticOrigin, VirtualRegister operand, Node* value, SetMode setMode = NormalSet)
434     {
435         SetForScope<CodeOrigin> originChange(m_currentSemanticOrigin, semanticOrigin);
436
437         unsigned local = operand.toLocal();
438         
439         if (setMode != ImmediateNakedSet) {
440             ArgumentPosition* argumentPosition = findArgumentPositionForLocal(operand);
441             if (argumentPosition)
442                 flushDirect(operand, argumentPosition);
443             else if (m_graph.needsScopeRegister() && operand == m_codeBlock->scopeRegister())
444                 flush(operand);
445         }
446
447         VariableAccessData* variableAccessData = newVariableAccessData(operand);
448         variableAccessData->mergeStructureCheckHoistingFailed(
449             m_inlineStackTop->m_exitProfile.hasExitSite(semanticOrigin.bytecodeIndex(), BadCache));
450         variableAccessData->mergeCheckArrayHoistingFailed(
451             m_inlineStackTop->m_exitProfile.hasExitSite(semanticOrigin.bytecodeIndex(), BadIndexingType));
452         Node* node = addToGraph(SetLocal, OpInfo(variableAccessData), value);
453         m_currentBlock->variablesAtTail.local(local) = node;
454         return node;
455     }
456
457     // Used in implementing get/set, above, where the operand is an argument.
458     Node* getArgument(VirtualRegister operand)
459     {
460         unsigned argument = operand.toArgument();
461         ASSERT(argument < m_numArguments);
462         
463         Node* node = m_currentBlock->variablesAtTail.argument(argument);
464
465         VariableAccessData* variable;
466         
467         if (node) {
468             variable = node->variableAccessData();
469             
470             switch (node->op()) {
471             case GetLocal:
472                 return node;
473             case SetLocal:
474                 return node->child1().node();
475             default:
476                 break;
477             }
478         } else
479             variable = newVariableAccessData(operand);
480         
481         node = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variable)));
482         m_currentBlock->variablesAtTail.argument(argument) = node;
483         return node;
484     }
485     Node* setArgument(const CodeOrigin& semanticOrigin, VirtualRegister operand, Node* value, SetMode setMode = NormalSet)
486     {
487         SetForScope<CodeOrigin> originChange(m_currentSemanticOrigin, semanticOrigin);
488
489         unsigned argument = operand.toArgument();
490         ASSERT(argument < m_numArguments);
491         
492         VariableAccessData* variableAccessData = newVariableAccessData(operand);
493
494         // Always flush arguments, except for 'this'. If 'this' is created by us,
495         // then make sure that it's never unboxed.
496         if (argument || m_graph.needsFlushedThis()) {
497             if (setMode != ImmediateNakedSet)
498                 flushDirect(operand);
499         }
500         
501         if (!argument && m_codeBlock->specializationKind() == CodeForConstruct)
502             variableAccessData->mergeShouldNeverUnbox(true);
503         
504         variableAccessData->mergeStructureCheckHoistingFailed(
505             m_inlineStackTop->m_exitProfile.hasExitSite(semanticOrigin.bytecodeIndex(), BadCache));
506         variableAccessData->mergeCheckArrayHoistingFailed(
507             m_inlineStackTop->m_exitProfile.hasExitSite(semanticOrigin.bytecodeIndex(), BadIndexingType));
508         Node* node = addToGraph(SetLocal, OpInfo(variableAccessData), value);
509         m_currentBlock->variablesAtTail.argument(argument) = node;
510         return node;
511     }
512     
513     ArgumentPosition* findArgumentPositionForArgument(int argument)
514     {
515         InlineStackEntry* stack = m_inlineStackTop;
516         while (stack->m_inlineCallFrame)
517             stack = stack->m_caller;
518         return stack->m_argumentPositions[argument];
519     }
520     
521     ArgumentPosition* findArgumentPositionForLocal(VirtualRegister operand)
522     {
523         for (InlineStackEntry* stack = m_inlineStackTop; ; stack = stack->m_caller) {
524             InlineCallFrame* inlineCallFrame = stack->m_inlineCallFrame;
525             if (!inlineCallFrame)
526                 break;
527             if (operand.offset() < static_cast<int>(inlineCallFrame->stackOffset + CallFrame::headerSizeInRegisters))
528                 continue;
529             if (operand.offset() >= static_cast<int>(inlineCallFrame->stackOffset + CallFrame::thisArgumentOffset() + inlineCallFrame->argumentsWithFixup.size()))
530                 continue;
531             int argument = VirtualRegister(operand.offset() - inlineCallFrame->stackOffset).toArgument();
532             return stack->m_argumentPositions[argument];
533         }
534         return 0;
535     }
536     
537     ArgumentPosition* findArgumentPosition(VirtualRegister operand)
538     {
539         if (operand.isArgument())
540             return findArgumentPositionForArgument(operand.toArgument());
541         return findArgumentPositionForLocal(operand);
542     }
543
544     template<typename AddFlushDirectFunc>
545     void flushImpl(InlineCallFrame* inlineCallFrame, const AddFlushDirectFunc& addFlushDirect)
546     {
547         int numArguments;
548         if (inlineCallFrame) {
549             ASSERT(!m_graph.hasDebuggerEnabled());
550             numArguments = inlineCallFrame->argumentsWithFixup.size();
551             if (inlineCallFrame->isClosureCall)
552                 addFlushDirect(inlineCallFrame, remapOperand(inlineCallFrame, VirtualRegister(CallFrameSlot::callee)));
553             if (inlineCallFrame->isVarargs())
554                 addFlushDirect(inlineCallFrame, remapOperand(inlineCallFrame, VirtualRegister(CallFrameSlot::argumentCount)));
555         } else
556             numArguments = m_graph.baselineCodeBlockFor(inlineCallFrame)->numParameters();
557
558         for (unsigned argument = numArguments; argument--;)
559             addFlushDirect(inlineCallFrame, remapOperand(inlineCallFrame, virtualRegisterForArgument(argument)));
560
561         if (m_graph.needsScopeRegister())
562             addFlushDirect(nullptr, m_graph.m_codeBlock->scopeRegister());
563     }
564
565     template<typename AddFlushDirectFunc, typename AddPhantomLocalDirectFunc>
566     void flushForTerminalImpl(CodeOrigin origin, const AddFlushDirectFunc& addFlushDirect, const AddPhantomLocalDirectFunc& addPhantomLocalDirect)
567     {
568         origin.walkUpInlineStack(
569             [&] (CodeOrigin origin) {
570                 BytecodeIndex bytecodeIndex = origin.bytecodeIndex();
571                 InlineCallFrame* inlineCallFrame = origin.inlineCallFrame();
572                 flushImpl(inlineCallFrame, addFlushDirect);
573
574                 CodeBlock* codeBlock = m_graph.baselineCodeBlockFor(inlineCallFrame);
575                 FullBytecodeLiveness& fullLiveness = m_graph.livenessFor(codeBlock);
576                 const FastBitVector& livenessAtBytecode = fullLiveness.getLiveness(bytecodeIndex);
577
578                 for (unsigned local = codeBlock->numCalleeLocals(); local--;) {
579                     if (livenessAtBytecode[local])
580                         addPhantomLocalDirect(inlineCallFrame, remapOperand(inlineCallFrame, virtualRegisterForLocal(local)));
581                 }
582             });
583     }
584
585     void flush(VirtualRegister operand)
586     {
587         flushDirect(m_inlineStackTop->remapOperand(operand));
588     }
589     
590     void flushDirect(VirtualRegister operand)
591     {
592         flushDirect(operand, findArgumentPosition(operand));
593     }
594
595     void flushDirect(VirtualRegister operand, ArgumentPosition* argumentPosition)
596     {
597         addFlushOrPhantomLocal<Flush>(operand, argumentPosition);
598     }
599
600     template<NodeType nodeType>
601     void addFlushOrPhantomLocal(VirtualRegister operand, ArgumentPosition* argumentPosition)
602     {
603         ASSERT(!operand.isConstant());
604         
605         Node* node = m_currentBlock->variablesAtTail.operand(operand);
606         
607         VariableAccessData* variable;
608         
609         if (node)
610             variable = node->variableAccessData();
611         else
612             variable = newVariableAccessData(operand);
613         
614         node = addToGraph(nodeType, OpInfo(variable));
615         m_currentBlock->variablesAtTail.operand(operand) = node;
616         if (argumentPosition)
617             argumentPosition->addVariable(variable);
618     }
619
620     void phantomLocalDirect(VirtualRegister operand)
621     {
622         addFlushOrPhantomLocal<PhantomLocal>(operand, findArgumentPosition(operand));
623     }
624
625     void flush(InlineStackEntry* inlineStackEntry)
626     {
627         auto addFlushDirect = [&] (InlineCallFrame*, VirtualRegister reg) { flushDirect(reg); };
628         flushImpl(inlineStackEntry->m_inlineCallFrame, addFlushDirect);
629     }
630
631     void flushForTerminal()
632     {
633         auto addFlushDirect = [&] (InlineCallFrame*, VirtualRegister reg) { flushDirect(reg); };
634         auto addPhantomLocalDirect = [&] (InlineCallFrame*, VirtualRegister reg) { phantomLocalDirect(reg); };
635         flushForTerminalImpl(currentCodeOrigin(), addFlushDirect, addPhantomLocalDirect);
636     }
637
638     void flushForReturn()
639     {
640         flush(m_inlineStackTop);
641     }
642     
643     void flushIfTerminal(SwitchData& data)
644     {
645         if (data.fallThrough.bytecodeIndex() > m_currentIndex.offset())
646             return;
647         
648         for (unsigned i = data.cases.size(); i--;) {
649             if (data.cases[i].target.bytecodeIndex() > m_currentIndex.offset())
650                 return;
651         }
652         
653         flushForTerminal();
654     }
655
656     // Assumes that the constant should be strongly marked.
657     Node* jsConstant(JSValue constantValue)
658     {
659         return addToGraph(JSConstant, OpInfo(m_graph.freezeStrong(constantValue)));
660     }
661
662     Node* weakJSConstant(JSValue constantValue)
663     {
664         return addToGraph(JSConstant, OpInfo(m_graph.freeze(constantValue)));
665     }
666
667     // Helper functions to get/set the this value.
668     Node* getThis()
669     {
670         return get(m_inlineStackTop->m_codeBlock->thisRegister());
671     }
672
673     void setThis(Node* value)
674     {
675         set(m_inlineStackTop->m_codeBlock->thisRegister(), value);
676     }
677
678     InlineCallFrame* inlineCallFrame()
679     {
680         return m_inlineStackTop->m_inlineCallFrame;
681     }
682
683     bool allInlineFramesAreTailCalls()
684     {
685         return !inlineCallFrame() || !inlineCallFrame()->getCallerSkippingTailCalls();
686     }
687
688     CodeOrigin currentCodeOrigin()
689     {
690         return CodeOrigin(m_currentIndex, inlineCallFrame());
691     }
692
693     NodeOrigin currentNodeOrigin()
694     {
695         CodeOrigin semantic;
696         CodeOrigin forExit;
697
698         if (m_currentSemanticOrigin.isSet())
699             semantic = m_currentSemanticOrigin;
700         else
701             semantic = currentCodeOrigin();
702
703         forExit = currentCodeOrigin();
704
705         return NodeOrigin(semantic, forExit, m_exitOK);
706     }
707     
708     BranchData* branchData(unsigned taken, unsigned notTaken)
709     {
710         // We assume that branches originating from bytecode always have a fall-through. We
711         // use this assumption to avoid checking for the creation of terminal blocks.
712         ASSERT((taken > m_currentIndex.offset()) || (notTaken > m_currentIndex.offset()));
713         BranchData* data = m_graph.m_branchData.add();
714         *data = BranchData::withBytecodeIndices(taken, notTaken);
715         return data;
716     }
717     
718     Node* addToGraph(Node* node)
719     {
720         VERBOSE_LOG("        appended ", node, " ", Graph::opName(node->op()), "\n");
721
722         m_hasAnyForceOSRExits |= (node->op() == ForceOSRExit);
723
724         m_currentBlock->append(node);
725         if (clobbersExitState(m_graph, node))
726             m_exitOK = false;
727         return node;
728     }
729     
730     Node* addToGraph(NodeType op, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
731     {
732         Node* result = m_graph.addNode(
733             op, currentNodeOrigin(), Edge(child1), Edge(child2),
734             Edge(child3));
735         return addToGraph(result);
736     }
737     Node* addToGraph(NodeType op, Edge child1, Edge child2 = Edge(), Edge child3 = Edge())
738     {
739         Node* result = m_graph.addNode(
740             op, currentNodeOrigin(), child1, child2, child3);
741         return addToGraph(result);
742     }
743     Node* addToGraph(NodeType op, OpInfo info, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
744     {
745         Node* result = m_graph.addNode(
746             op, currentNodeOrigin(), info, Edge(child1), Edge(child2),
747             Edge(child3));
748         return addToGraph(result);
749     }
750     Node* addToGraph(NodeType op, OpInfo info, Edge child1, Edge child2 = Edge(), Edge child3 = Edge())
751     {
752         Node* result = m_graph.addNode(op, currentNodeOrigin(), info, child1, child2, child3);
753         return addToGraph(result);
754     }
755     Node* addToGraph(NodeType op, OpInfo info1, OpInfo info2, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
756     {
757         Node* result = m_graph.addNode(
758             op, currentNodeOrigin(), info1, info2,
759             Edge(child1), Edge(child2), Edge(child3));
760         return addToGraph(result);
761     }
762     Node* addToGraph(NodeType op, OpInfo info1, OpInfo info2, Edge child1, Edge child2 = Edge(), Edge child3 = Edge())
763     {
764         Node* result = m_graph.addNode(
765             op, currentNodeOrigin(), info1, info2, child1, child2, child3);
766         return addToGraph(result);
767     }
768     
769     Node* addToGraph(Node::VarArgTag, NodeType op, OpInfo info1, OpInfo info2 = OpInfo())
770     {
771         Node* result = m_graph.addNode(
772             Node::VarArg, op, currentNodeOrigin(), info1, info2,
773             m_graph.m_varArgChildren.size() - m_numPassedVarArgs, m_numPassedVarArgs);
774         addToGraph(result);
775         
776         m_numPassedVarArgs = 0;
777         
778         return result;
779     }
780     
781     void addVarArgChild(Node* child)
782     {
783         m_graph.m_varArgChildren.append(Edge(child));
784         m_numPassedVarArgs++;
785     }
786
787     void addVarArgChild(Edge child)
788     {
789         m_graph.m_varArgChildren.append(child);
790         m_numPassedVarArgs++;
791     }
792     
793     Node* addCallWithoutSettingResult(
794         NodeType op, OpInfo opInfo, Node* callee, int argCount, int registerOffset,
795         OpInfo prediction)
796     {
797         addVarArgChild(callee);
798         size_t parameterSlots = Graph::parameterSlotsForArgCount(argCount);
799
800         if (parameterSlots > m_parameterSlots)
801             m_parameterSlots = parameterSlots;
802
803         for (int i = 0; i < argCount; ++i)
804             addVarArgChild(get(virtualRegisterForArgument(i, registerOffset)));
805
806         return addToGraph(Node::VarArg, op, opInfo, prediction);
807     }
808     
809     Node* addCall(
810         VirtualRegister result, NodeType op, const DOMJIT::Signature* signature, Node* callee, int argCount, int registerOffset,
811         SpeculatedType prediction)
812     {
813         if (op == TailCall) {
814             if (allInlineFramesAreTailCalls())
815                 return addCallWithoutSettingResult(op, OpInfo(signature), callee, argCount, registerOffset, OpInfo());
816             op = TailCallInlinedCaller;
817         }
818
819
820         Node* call = addCallWithoutSettingResult(
821             op, OpInfo(signature), callee, argCount, registerOffset, OpInfo(prediction));
822         if (result.isValid())
823             set(result, call);
824         return call;
825     }
826     
827     Node* cellConstantWithStructureCheck(JSCell* object, Structure* structure)
828     {
829         // FIXME: This should route to emitPropertyCheck, not the other way around. But currently,
830         // this gets no profit from using emitPropertyCheck() since we'll non-adaptively watch the
831         // object's structure as soon as we make it a weakJSCosntant.
832         Node* objectNode = weakJSConstant(object);
833         addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structure)), objectNode);
834         return objectNode;
835     }
836     
837     SpeculatedType getPredictionWithoutOSRExit(BytecodeIndex bytecodeIndex)
838     {
839         auto getValueProfilePredictionFromForCodeBlockAndBytecodeOffset = [&] (CodeBlock* codeBlock, const CodeOrigin& codeOrigin)
840         {
841             SpeculatedType prediction;
842             {
843                 ConcurrentJSLocker locker(codeBlock->m_lock);
844                 prediction = codeBlock->valueProfilePredictionForBytecodeIndex(locker, codeOrigin.bytecodeIndex());
845             }
846             auto* fuzzerAgent = m_vm->fuzzerAgent();
847             if (UNLIKELY(fuzzerAgent))
848                 return fuzzerAgent->getPrediction(codeBlock, codeOrigin, prediction) & SpecBytecodeTop;
849             return prediction;
850         };
851
852         SpeculatedType prediction = getValueProfilePredictionFromForCodeBlockAndBytecodeOffset(m_inlineStackTop->m_profiledBlock, CodeOrigin(bytecodeIndex, inlineCallFrame()));
853         if (prediction != SpecNone)
854             return prediction;
855
856         // If we have no information about the values this
857         // node generates, we check if by any chance it is
858         // a tail call opcode. In that case, we walk up the
859         // inline frames to find a call higher in the call
860         // chain and use its prediction. If we only have
861         // inlined tail call frames, we use SpecFullTop
862         // to avoid a spurious OSR exit.
863         auto instruction = m_inlineStackTop->m_profiledBlock->instructions().at(bytecodeIndex.offset());
864         OpcodeID opcodeID = instruction->opcodeID();
865
866         switch (opcodeID) {
867         case op_tail_call:
868         case op_tail_call_varargs:
869         case op_tail_call_forward_arguments: {
870             // Things should be more permissive to us returning BOTTOM instead of TOP here.
871             // Currently, this will cause us to Force OSR exit. This is bad because returning
872             // TOP will cause anything that transitively touches this speculated type to
873             // also become TOP during prediction propagation.
874             // https://bugs.webkit.org/show_bug.cgi?id=164337
875             if (!inlineCallFrame())
876                 return SpecFullTop;
877
878             CodeOrigin* codeOrigin = inlineCallFrame()->getCallerSkippingTailCalls();
879             if (!codeOrigin)
880                 return SpecFullTop;
881
882             InlineStackEntry* stack = m_inlineStackTop;
883             while (stack->m_inlineCallFrame != codeOrigin->inlineCallFrame())
884                 stack = stack->m_caller;
885
886             return getValueProfilePredictionFromForCodeBlockAndBytecodeOffset(stack->m_profiledBlock, *codeOrigin);
887         }
888
889         default:
890             return SpecNone;
891         }
892
893         RELEASE_ASSERT_NOT_REACHED();
894         return SpecNone;
895     }
896
897     SpeculatedType getPrediction(BytecodeIndex bytecodeIndex)
898     {
899         SpeculatedType prediction = getPredictionWithoutOSRExit(bytecodeIndex);
900
901         if (prediction == SpecNone) {
902             // We have no information about what values this node generates. Give up
903             // on executing this code, since we're likely to do more damage than good.
904             addToGraph(ForceOSRExit);
905         }
906         
907         return prediction;
908     }
909     
910     SpeculatedType getPredictionWithoutOSRExit()
911     {
912         return getPredictionWithoutOSRExit(m_currentIndex);
913     }
914     
915     SpeculatedType getPrediction()
916     {
917         return getPrediction(m_currentIndex);
918     }
919     
920     ArrayMode getArrayMode(Array::Action action)
921     {
922         CodeBlock* codeBlock = m_inlineStackTop->m_profiledBlock;
923         ArrayProfile* profile = codeBlock->getArrayProfile(codeBlock->bytecodeIndex(m_currentInstruction));
924         return getArrayMode(*profile, action);
925     }
926
927     ArrayMode getArrayMode(ArrayProfile& profile, Array::Action action)
928     {
929         ConcurrentJSLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
930         profile.computeUpdatedPrediction(locker, m_inlineStackTop->m_profiledBlock);
931         bool makeSafe = profile.outOfBounds(locker);
932         return ArrayMode::fromObserved(locker, &profile, action, makeSafe);
933     }
934
935     Node* makeSafe(Node* node)
936     {
937         if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
938             node->mergeFlags(NodeMayOverflowInt32InDFG);
939         if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero))
940             node->mergeFlags(NodeMayNegZeroInDFG);
941         
942         if (!isX86() && (node->op() == ArithMod || node->op() == ValueMod))
943             return node;
944
945         {
946             ArithProfile* arithProfile = m_inlineStackTop->m_profiledBlock->arithProfileForBytecodeIndex(m_currentIndex);
947             if (arithProfile) {
948                 switch (node->op()) {
949                 case ArithAdd:
950                 case ArithSub:
951                 case ValueAdd:
952                     if (arithProfile->didObserveDouble())
953                         node->mergeFlags(NodeMayHaveDoubleResult);
954                     if (arithProfile->didObserveNonNumeric())
955                         node->mergeFlags(NodeMayHaveNonNumericResult);
956                     if (arithProfile->didObserveBigInt())
957                         node->mergeFlags(NodeMayHaveBigIntResult);
958                     break;
959
960                 case ValueMul:
961                 case ArithMul: {
962                     if (arithProfile->didObserveInt52Overflow())
963                         node->mergeFlags(NodeMayOverflowInt52);
964                     if (arithProfile->didObserveInt32Overflow() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
965                         node->mergeFlags(NodeMayOverflowInt32InBaseline);
966                     if (arithProfile->didObserveNegZeroDouble() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero))
967                         node->mergeFlags(NodeMayNegZeroInBaseline);
968                     if (arithProfile->didObserveDouble())
969                         node->mergeFlags(NodeMayHaveDoubleResult);
970                     if (arithProfile->didObserveNonNumeric())
971                         node->mergeFlags(NodeMayHaveNonNumericResult);
972                     if (arithProfile->didObserveBigInt())
973                         node->mergeFlags(NodeMayHaveBigIntResult);
974                     break;
975                 }
976                 case ValueNegate:
977                 case ArithNegate: {
978                     if (arithProfile->lhsObservedType().sawNumber() || arithProfile->didObserveDouble())
979                         node->mergeFlags(NodeMayHaveDoubleResult);
980                     if (arithProfile->didObserveNegZeroDouble() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero))
981                         node->mergeFlags(NodeMayNegZeroInBaseline);
982                     if (arithProfile->didObserveInt32Overflow() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
983                         node->mergeFlags(NodeMayOverflowInt32InBaseline);
984                     if (arithProfile->didObserveNonNumeric())
985                         node->mergeFlags(NodeMayHaveNonNumericResult);
986                     if (arithProfile->didObserveBigInt())
987                         node->mergeFlags(NodeMayHaveBigIntResult);
988                     break;
989                 }
990
991                 default:
992                     break;
993                 }
994             }
995         }
996         
997         if (m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex)) {
998             switch (node->op()) {
999             case UInt32ToNumber:
1000             case ArithAdd:
1001             case ArithSub:
1002             case ValueAdd:
1003             case ValueMod:
1004             case ArithMod: // for ArithMod "MayOverflow" means we tried to divide by zero, or we saw double.
1005                 node->mergeFlags(NodeMayOverflowInt32InBaseline);
1006                 break;
1007                 
1008             default:
1009                 break;
1010             }
1011         }
1012         
1013         return node;
1014     }
1015     
1016     Node* makeDivSafe(Node* node)
1017     {
1018         ASSERT(node->op() == ArithDiv || node->op() == ValueDiv);
1019         
1020         if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
1021             node->mergeFlags(NodeMayOverflowInt32InDFG);
1022         if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero))
1023             node->mergeFlags(NodeMayNegZeroInDFG);
1024         
1025         // The main slow case counter for op_div in the old JIT counts only when
1026         // the operands are not numbers. We don't care about that since we already
1027         // have speculations in place that take care of that separately. We only
1028         // care about when the outcome of the division is not an integer, which
1029         // is what the special fast case counter tells us.
1030         
1031         if (!m_inlineStackTop->m_profiledBlock->couldTakeSpecialArithFastCase(m_currentIndex))
1032             return node;
1033         
1034         // FIXME: It might be possible to make this more granular.
1035         node->mergeFlags(NodeMayOverflowInt32InBaseline | NodeMayNegZeroInBaseline);
1036         
1037         ArithProfile* arithProfile = m_inlineStackTop->m_profiledBlock->arithProfileForBytecodeIndex(m_currentIndex);
1038         if (arithProfile->didObserveBigInt())
1039             node->mergeFlags(NodeMayHaveBigIntResult);
1040
1041         return node;
1042     }
1043     
1044     void noticeArgumentsUse()
1045     {
1046         // All of the arguments in this function need to be formatted as JSValues because we will
1047         // load from them in a random-access fashion and we don't want to have to switch on
1048         // format.
1049         
1050         for (ArgumentPosition* argument : m_inlineStackTop->m_argumentPositions)
1051             argument->mergeShouldNeverUnbox(true);
1052     }
1053
1054     bool needsDynamicLookup(ResolveType, OpcodeID);
1055
1056     VM* m_vm;
1057     CodeBlock* m_codeBlock;
1058     CodeBlock* m_profiledBlock;
1059     Graph& m_graph;
1060
1061     // The current block being generated.
1062     BasicBlock* m_currentBlock;
1063     // The bytecode index of the current instruction being generated.
1064     BytecodeIndex m_currentIndex;
1065     // The semantic origin of the current node if different from the current Index.
1066     CodeOrigin m_currentSemanticOrigin;
1067     // True if it's OK to OSR exit right now.
1068     bool m_exitOK { false };
1069
1070     FrozenValue* m_constantUndefined;
1071     FrozenValue* m_constantNull;
1072     FrozenValue* m_constantNaN;
1073     FrozenValue* m_constantOne;
1074     Vector<Node*, 16> m_constants;
1075
1076     HashMap<InlineCallFrame*, Vector<ArgumentPosition*>, WTF::DefaultHash<InlineCallFrame*>::Hash, WTF::NullableHashTraits<InlineCallFrame*>> m_inlineCallFrameToArgumentPositions;
1077
1078     // The number of arguments passed to the function.
1079     unsigned m_numArguments;
1080     // The number of locals (vars + temporaries) used in the function.
1081     unsigned m_numLocals;
1082     // The number of slots (in units of sizeof(Register)) that we need to
1083     // preallocate for arguments to outgoing calls from this frame. This
1084     // number includes the CallFrame slots that we initialize for the callee
1085     // (but not the callee-initialized CallerFrame and ReturnPC slots).
1086     // This number is 0 if and only if this function is a leaf.
1087     unsigned m_parameterSlots;
1088     // The number of var args passed to the next var arg node.
1089     unsigned m_numPassedVarArgs;
1090
1091     struct InlineStackEntry {
1092         ByteCodeParser* m_byteCodeParser;
1093         
1094         CodeBlock* m_codeBlock;
1095         CodeBlock* m_profiledBlock;
1096         InlineCallFrame* m_inlineCallFrame;
1097         
1098         ScriptExecutable* executable() { return m_codeBlock->ownerExecutable(); }
1099         
1100         QueryableExitProfile m_exitProfile;
1101         
1102         // Remapping of identifier and constant numbers from the code block being
1103         // inlined (inline callee) to the code block that we're inlining into
1104         // (the machine code block, which is the transitive, though not necessarily
1105         // direct, caller).
1106         Vector<unsigned> m_identifierRemap;
1107         Vector<unsigned> m_switchRemap;
1108         
1109         // These are blocks whose terminal is a Jump, Branch or Switch, and whose target has not yet been linked.
1110         // Their terminal instead refers to a bytecode index, and the right BB can be found in m_blockLinkingTargets.
1111         Vector<BasicBlock*> m_unlinkedBlocks;
1112         
1113         // Potential block linking targets. Must be sorted by bytecodeBegin, and
1114         // cannot have two blocks that have the same bytecodeBegin.
1115         Vector<BasicBlock*> m_blockLinkingTargets;
1116
1117         // Optional: a continuation block for returns to jump to. It is set by early returns if it does not exist.
1118         BasicBlock* m_continuationBlock;
1119
1120         VirtualRegister m_returnValue;
1121         
1122         // Speculations about variable types collected from the profiled code block,
1123         // which are based on OSR exit profiles that past DFG compilations of this
1124         // code block had gathered.
1125         LazyOperandValueProfileParser m_lazyOperands;
1126         
1127         ICStatusMap m_baselineMap;
1128         ICStatusContext m_optimizedContext;
1129         
1130         // Pointers to the argument position trackers for this slice of code.
1131         Vector<ArgumentPosition*> m_argumentPositions;
1132         
1133         InlineStackEntry* m_caller;
1134         
1135         InlineStackEntry(
1136             ByteCodeParser*,
1137             CodeBlock*,
1138             CodeBlock* profiledBlock,
1139             JSFunction* callee, // Null if this is a closure call.
1140             VirtualRegister returnValueVR,
1141             VirtualRegister inlineCallFrameStart,
1142             int argumentCountIncludingThis,
1143             InlineCallFrame::Kind,
1144             BasicBlock* continuationBlock);
1145         
1146         ~InlineStackEntry();
1147         
1148         VirtualRegister remapOperand(VirtualRegister operand) const
1149         {
1150             if (!m_inlineCallFrame)
1151                 return operand;
1152             
1153             ASSERT(!operand.isConstant());
1154
1155             return VirtualRegister(operand.offset() + m_inlineCallFrame->stackOffset);
1156         }
1157     };
1158     
1159     InlineStackEntry* m_inlineStackTop;
1160     
1161     ICStatusContextStack m_icContextStack;
1162     
1163     struct DelayedSetLocal {
1164         CodeOrigin m_origin;
1165         VirtualRegister m_operand;
1166         Node* m_value;
1167         SetMode m_setMode;
1168         
1169         DelayedSetLocal() { }
1170         DelayedSetLocal(const CodeOrigin& origin, VirtualRegister operand, Node* value, SetMode setMode)
1171             : m_origin(origin)
1172             , m_operand(operand)
1173             , m_value(value)
1174             , m_setMode(setMode)
1175         {
1176             RELEASE_ASSERT(operand.isValid());
1177         }
1178         
1179         Node* execute(ByteCodeParser* parser)
1180         {
1181             if (m_operand.isArgument())
1182                 return parser->setArgument(m_origin, m_operand, m_value, m_setMode);
1183             return parser->setLocal(m_origin, m_operand, m_value, m_setMode);
1184         }
1185     };
1186     
1187     Vector<DelayedSetLocal, 2> m_setLocalQueue;
1188
1189     const Instruction* m_currentInstruction;
1190     bool m_hasDebuggerEnabled;
1191     bool m_hasAnyForceOSRExits { false };
1192 };
1193
1194 BasicBlock* ByteCodeParser::allocateTargetableBlock(BytecodeIndex bytecodeIndex)
1195 {
1196     ASSERT(bytecodeIndex);
1197     Ref<BasicBlock> block = adoptRef(*new BasicBlock(bytecodeIndex, m_numArguments, m_numLocals, 1));
1198     BasicBlock* blockPtr = block.ptr();
1199     // m_blockLinkingTargets must always be sorted in increasing order of bytecodeBegin
1200     if (m_inlineStackTop->m_blockLinkingTargets.size())
1201         ASSERT(m_inlineStackTop->m_blockLinkingTargets.last()->bytecodeBegin.offset() < bytecodeIndex.offset());
1202     m_inlineStackTop->m_blockLinkingTargets.append(blockPtr);
1203     m_graph.appendBlock(WTFMove(block));
1204     return blockPtr;
1205 }
1206
1207 BasicBlock* ByteCodeParser::allocateUntargetableBlock()
1208 {
1209     Ref<BasicBlock> block = adoptRef(*new BasicBlock(BytecodeIndex(), m_numArguments, m_numLocals, 1));
1210     BasicBlock* blockPtr = block.ptr();
1211     m_graph.appendBlock(WTFMove(block));
1212     return blockPtr;
1213 }
1214
1215 void ByteCodeParser::makeBlockTargetable(BasicBlock* block, BytecodeIndex bytecodeIndex)
1216 {
1217     RELEASE_ASSERT(!block->bytecodeBegin);
1218     block->bytecodeBegin = bytecodeIndex;
1219     // m_blockLinkingTargets must always be sorted in increasing order of bytecodeBegin
1220     if (m_inlineStackTop->m_blockLinkingTargets.size())
1221         ASSERT(m_inlineStackTop->m_blockLinkingTargets.last()->bytecodeBegin.offset() < bytecodeIndex.offset());
1222     m_inlineStackTop->m_blockLinkingTargets.append(block);
1223 }
1224
1225 void ByteCodeParser::addJumpTo(BasicBlock* block)
1226 {
1227     ASSERT(!m_currentBlock->terminal());
1228     Node* jumpNode = addToGraph(Jump);
1229     jumpNode->targetBlock() = block;
1230     m_currentBlock->didLink();
1231 }
1232
1233 void ByteCodeParser::addJumpTo(unsigned bytecodeIndex)
1234 {
1235     ASSERT(!m_currentBlock->terminal());
1236     addToGraph(Jump, OpInfo(bytecodeIndex));
1237     m_inlineStackTop->m_unlinkedBlocks.append(m_currentBlock);
1238 }
1239
1240 template<typename CallOp>
1241 ByteCodeParser::Terminality ByteCodeParser::handleCall(const Instruction* pc, NodeType op, CallMode callMode)
1242 {
1243     auto bytecode = pc->as<CallOp>();
1244     Node* callTarget = get(bytecode.m_callee);
1245     int registerOffset = -static_cast<int>(bytecode.m_argv);
1246
1247     CallLinkStatus callLinkStatus = CallLinkStatus::computeFor(
1248         m_inlineStackTop->m_profiledBlock, currentCodeOrigin(),
1249         m_inlineStackTop->m_baselineMap, m_icContextStack);
1250
1251     InlineCallFrame::Kind kind = InlineCallFrame::kindFor(callMode);
1252
1253     return handleCall(bytecode.m_dst, op, kind, pc->size(), callTarget,
1254         bytecode.m_argc, registerOffset, callLinkStatus, getPrediction());
1255 }
1256
1257 void ByteCodeParser::refineStatically(CallLinkStatus& callLinkStatus, Node* callTarget)
1258 {
1259     if (callTarget->isCellConstant())
1260         callLinkStatus.setProvenConstantCallee(CallVariant(callTarget->asCell()));
1261 }
1262
1263 ByteCodeParser::Terminality ByteCodeParser::handleCall(
1264     VirtualRegister result, NodeType op, InlineCallFrame::Kind kind, unsigned instructionSize,
1265     Node* callTarget, int argumentCountIncludingThis, int registerOffset,
1266     CallLinkStatus callLinkStatus, SpeculatedType prediction)
1267 {
1268     ASSERT(registerOffset <= 0);
1269
1270     refineStatically(callLinkStatus, callTarget);
1271     
1272     VERBOSE_LOG("    Handling call at ", currentCodeOrigin(), ": ", callLinkStatus, "\n");
1273     
1274     // If we have profiling information about this call, and it did not behave too polymorphically,
1275     // we may be able to inline it, or in the case of recursive tail calls turn it into a jump.
1276     if (callLinkStatus.canOptimize()) {
1277         addToGraph(FilterCallLinkStatus, OpInfo(m_graph.m_plan.recordedStatuses().addCallLinkStatus(currentCodeOrigin(), callLinkStatus)), callTarget);
1278
1279         VirtualRegister thisArgument = virtualRegisterForArgument(0, registerOffset);
1280         auto optimizationResult = handleInlining(callTarget, result, callLinkStatus, registerOffset, thisArgument,
1281             argumentCountIncludingThis, BytecodeIndex(m_currentIndex.offset() + instructionSize), op, kind, prediction);
1282         if (optimizationResult == CallOptimizationResult::OptimizedToJump)
1283             return Terminal;
1284         if (optimizationResult == CallOptimizationResult::Inlined) {
1285             if (UNLIKELY(m_graph.compilation()))
1286                 m_graph.compilation()->noticeInlinedCall();
1287             return NonTerminal;
1288         }
1289     }
1290     
1291     Node* callNode = addCall(result, op, nullptr, callTarget, argumentCountIncludingThis, registerOffset, prediction);
1292     ASSERT(callNode->op() != TailCallVarargs && callNode->op() != TailCallForwardVarargs);
1293     return callNode->op() == TailCall ? Terminal : NonTerminal;
1294 }
1295
1296 template<typename CallOp>
1297 ByteCodeParser::Terminality ByteCodeParser::handleVarargsCall(const Instruction* pc, NodeType op, CallMode callMode)
1298 {
1299     auto bytecode = pc->as<CallOp>();
1300     int firstFreeReg = bytecode.m_firstFree.offset();
1301     int firstVarArgOffset = bytecode.m_firstVarArg;
1302     
1303     SpeculatedType prediction = getPrediction();
1304     
1305     Node* callTarget = get(bytecode.m_callee);
1306     
1307     CallLinkStatus callLinkStatus = CallLinkStatus::computeFor(
1308         m_inlineStackTop->m_profiledBlock, currentCodeOrigin(),
1309         m_inlineStackTop->m_baselineMap, m_icContextStack);
1310     refineStatically(callLinkStatus, callTarget);
1311     
1312     VERBOSE_LOG("    Varargs call link status at ", currentCodeOrigin(), ": ", callLinkStatus, "\n");
1313     
1314     if (callLinkStatus.canOptimize()) {
1315         addToGraph(FilterCallLinkStatus, OpInfo(m_graph.m_plan.recordedStatuses().addCallLinkStatus(currentCodeOrigin(), callLinkStatus)), callTarget);
1316
1317         if (handleVarargsInlining(callTarget, bytecode.m_dst,
1318             callLinkStatus, firstFreeReg, bytecode.m_thisValue, bytecode.m_arguments,
1319             firstVarArgOffset, op,
1320             InlineCallFrame::varargsKindFor(callMode))) {
1321             if (UNLIKELY(m_graph.compilation()))
1322                 m_graph.compilation()->noticeInlinedCall();
1323             return NonTerminal;
1324         }
1325     }
1326     
1327     CallVarargsData* data = m_graph.m_callVarargsData.add();
1328     data->firstVarArgOffset = firstVarArgOffset;
1329     
1330     Node* thisChild = get(bytecode.m_thisValue);
1331     Node* argumentsChild = nullptr;
1332     if (op != TailCallForwardVarargs)
1333         argumentsChild = get(bytecode.m_arguments);
1334
1335     if (op == TailCallVarargs || op == TailCallForwardVarargs) {
1336         if (allInlineFramesAreTailCalls()) {
1337             addToGraph(op, OpInfo(data), OpInfo(), callTarget, thisChild, argumentsChild);
1338             return Terminal;
1339         }
1340         op = op == TailCallVarargs ? TailCallVarargsInlinedCaller : TailCallForwardVarargsInlinedCaller;
1341     }
1342
1343     Node* call = addToGraph(op, OpInfo(data), OpInfo(prediction), callTarget, thisChild, argumentsChild);
1344     if (bytecode.m_dst.isValid())
1345         set(bytecode.m_dst, call);
1346     return NonTerminal;
1347 }
1348
1349 void ByteCodeParser::emitFunctionChecks(CallVariant callee, Node* callTarget, VirtualRegister thisArgumentReg)
1350 {
1351     Node* thisArgument;
1352     if (thisArgumentReg.isValid())
1353         thisArgument = get(thisArgumentReg);
1354     else
1355         thisArgument = nullptr;
1356
1357     JSCell* calleeCell;
1358     Node* callTargetForCheck;
1359     if (callee.isClosureCall()) {
1360         calleeCell = callee.executable();
1361         callTargetForCheck = addToGraph(GetExecutable, callTarget);
1362     } else {
1363         calleeCell = callee.nonExecutableCallee();
1364         callTargetForCheck = callTarget;
1365     }
1366     
1367     ASSERT(calleeCell);
1368     addToGraph(CheckCell, OpInfo(m_graph.freeze(calleeCell)), callTargetForCheck);
1369     if (thisArgument)
1370         addToGraph(Phantom, thisArgument);
1371 }
1372
1373 Node* ByteCodeParser::getArgumentCount()
1374 {
1375     Node* argumentCount;
1376     if (m_inlineStackTop->m_inlineCallFrame && !m_inlineStackTop->m_inlineCallFrame->isVarargs())
1377         argumentCount = jsConstant(m_graph.freeze(jsNumber(m_inlineStackTop->m_inlineCallFrame->argumentCountIncludingThis))->value());
1378     else
1379         argumentCount = addToGraph(GetArgumentCountIncludingThis, OpInfo(m_inlineStackTop->m_inlineCallFrame), OpInfo(SpecInt32Only));
1380     return argumentCount;
1381 }
1382
1383 void ByteCodeParser::emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis)
1384 {
1385     for (int i = 0; i < argumentCountIncludingThis; ++i)
1386         addToGraph(Phantom, get(virtualRegisterForArgument(i, registerOffset)));
1387 }
1388
1389 template<typename ChecksFunctor>
1390 bool ByteCodeParser::handleRecursiveTailCall(Node* callTargetNode, CallVariant callVariant, int registerOffset, int argumentCountIncludingThis, const ChecksFunctor& emitFunctionCheckIfNeeded)
1391 {
1392     if (UNLIKELY(!Options::optimizeRecursiveTailCalls()))
1393         return false;
1394
1395     auto targetExecutable = callVariant.executable();
1396     InlineStackEntry* stackEntry = m_inlineStackTop;
1397     do {
1398         if (targetExecutable != stackEntry->executable())
1399             continue;
1400         VERBOSE_LOG("   We found a recursive tail call, trying to optimize it into a jump.\n");
1401
1402         if (auto* callFrame = stackEntry->m_inlineCallFrame) {
1403             // FIXME: We only accept jump to CallFrame which has exact same argumentCountIncludingThis. But we can remove this by fixing up arguments.
1404             // And we can also allow jumping into CallFrame with Varargs if the passing number of arguments is greater than or equal to mandatoryMinimum of CallFrame.
1405             // https://bugs.webkit.org/show_bug.cgi?id=202317
1406
1407             // Some code may statically use the argument count from the InlineCallFrame, so it would be invalid to loop back if it does not match.
1408             // We "continue" instead of returning false in case another stack entry further on the stack has the right number of arguments.
1409             if (argumentCountIncludingThis != static_cast<int>(callFrame->argumentCountIncludingThis))
1410                 continue;
1411             // If the target InlineCallFrame is Varargs, we do not know how many arguments are actually filled by LoadVarargs. Varargs InlineCallFrame's
1412             // argumentCountIncludingThis is maximum number of potentially filled arguments by LoadVarargs. We "continue" to the upper frame which may be
1413             // a good target to jump into.
1414             if (callFrame->isVarargs())
1415                 continue;
1416         } else {
1417             // We are in the machine code entry (i.e. the original caller).
1418             // If we have more arguments than the number of parameters to the function, it is not clear where we could put them on the stack.
1419             if (argumentCountIncludingThis > m_codeBlock->numParameters())
1420                 return false;
1421         }
1422
1423         // If an InlineCallFrame is not a closure, it was optimized using a constant callee.
1424         // Check if this is the same callee that we try to inline here.
1425         if (stackEntry->m_inlineCallFrame && !stackEntry->m_inlineCallFrame->isClosureCall) {
1426             if (stackEntry->m_inlineCallFrame->calleeConstant() != callVariant.function())
1427                 continue;
1428         }
1429
1430         // We must add some check that the profiling information was correct and the target of this call is what we thought.
1431         emitFunctionCheckIfNeeded();
1432         // We flush everything, as if we were in the backedge of a loop (see treatment of op_jmp in parseBlock).
1433         flushForTerminal();
1434
1435         // We must set the callee to the right value
1436         if (stackEntry->m_inlineCallFrame) {
1437             if (stackEntry->m_inlineCallFrame->isClosureCall)
1438                 setDirect(stackEntry->remapOperand(VirtualRegister(CallFrameSlot::callee)), callTargetNode, NormalSet);
1439         } else
1440             addToGraph(SetCallee, callTargetNode);
1441
1442         // We must set the arguments to the right values
1443         if (!stackEntry->m_inlineCallFrame)
1444             addToGraph(SetArgumentCountIncludingThis, OpInfo(argumentCountIncludingThis));
1445         int argIndex = 0;
1446         for (; argIndex < argumentCountIncludingThis; ++argIndex) {
1447             Node* value = get(virtualRegisterForArgument(argIndex, registerOffset));
1448             setDirect(stackEntry->remapOperand(virtualRegisterForArgument(argIndex)), value, NormalSet);
1449         }
1450         Node* undefined = addToGraph(JSConstant, OpInfo(m_constantUndefined));
1451         for (; argIndex < stackEntry->m_codeBlock->numParameters(); ++argIndex)
1452             setDirect(stackEntry->remapOperand(virtualRegisterForArgument(argIndex)), undefined, NormalSet);
1453
1454         // We must repeat the work of op_enter here as we will jump right after it.
1455         // We jump right after it and not before it, because of some invariant saying that a CFG root cannot have predecessors in the IR.
1456         for (int i = 0; i < stackEntry->m_codeBlock->numVars(); ++i)
1457             setDirect(stackEntry->remapOperand(virtualRegisterForLocal(i)), undefined, NormalSet);
1458
1459         // We want to emit the SetLocals with an exit origin that points to the place we are jumping to.
1460         BytecodeIndex oldIndex = m_currentIndex;
1461         auto oldStackTop = m_inlineStackTop;
1462         m_inlineStackTop = stackEntry;
1463         m_currentIndex = BytecodeIndex(opcodeLengths[op_enter]);
1464         m_exitOK = true;
1465         processSetLocalQueue();
1466         m_currentIndex = oldIndex;
1467         m_inlineStackTop = oldStackTop;
1468         m_exitOK = false;
1469
1470         BasicBlock** entryBlockPtr = tryBinarySearch<BasicBlock*, BytecodeIndex>(stackEntry->m_blockLinkingTargets, stackEntry->m_blockLinkingTargets.size(), BytecodeIndex(opcodeLengths[op_enter]), getBytecodeBeginForBlock);
1471         RELEASE_ASSERT(entryBlockPtr);
1472         addJumpTo(*entryBlockPtr);
1473         return true;
1474         // It would be unsound to jump over a non-tail call: the "tail" call is not really a tail call in that case.
1475     } while (stackEntry->m_inlineCallFrame && stackEntry->m_inlineCallFrame->kind == InlineCallFrame::TailCall && (stackEntry = stackEntry->m_caller));
1476
1477     // The tail call was not recursive
1478     return false;
1479 }
1480
1481 unsigned ByteCodeParser::inliningCost(CallVariant callee, int argumentCountIncludingThis, InlineCallFrame::Kind kind)
1482 {
1483     CallMode callMode = InlineCallFrame::callModeFor(kind);
1484     CodeSpecializationKind specializationKind = specializationKindFor(callMode);
1485     VERBOSE_LOG("Considering inlining ", callee, " into ", currentCodeOrigin(), "\n");
1486     
1487     if (m_hasDebuggerEnabled) {
1488         VERBOSE_LOG("    Failing because the debugger is in use.\n");
1489         return UINT_MAX;
1490     }
1491
1492     FunctionExecutable* executable = callee.functionExecutable();
1493     if (!executable) {
1494         VERBOSE_LOG("    Failing because there is no function executable.\n");
1495         return UINT_MAX;
1496     }
1497     
1498     // Do we have a code block, and does the code block's size match the heuristics/requirements for
1499     // being an inline candidate? We might not have a code block (1) if code was thrown away,
1500     // (2) if we simply hadn't actually made this call yet or (3) code is a builtin function and
1501     // specialization kind is construct. In the former 2 cases, we could still theoretically attempt
1502     // to inline it if we had a static proof of what was being called; this might happen for example
1503     // if you call a global function, where watchpointing gives us static information. Overall,
1504     // it's a rare case because we expect that any hot callees would have already been compiled.
1505     CodeBlock* codeBlock = executable->baselineCodeBlockFor(specializationKind);
1506     if (!codeBlock) {
1507         VERBOSE_LOG("    Failing because no code block available.\n");
1508         return UINT_MAX;
1509     }
1510
1511     if (!Options::useArityFixupInlining()) {
1512         if (codeBlock->numParameters() > argumentCountIncludingThis) {
1513             VERBOSE_LOG("    Failing because of arity mismatch.\n");
1514             return UINT_MAX;
1515         }
1516     }
1517
1518     CapabilityLevel capabilityLevel = inlineFunctionForCapabilityLevel(
1519         codeBlock, specializationKind, callee.isClosureCall());
1520     VERBOSE_LOG("    Call mode: ", callMode, "\n");
1521     VERBOSE_LOG("    Is closure call: ", callee.isClosureCall(), "\n");
1522     VERBOSE_LOG("    Capability level: ", capabilityLevel, "\n");
1523     VERBOSE_LOG("    Might inline function: ", mightInlineFunctionFor(codeBlock, specializationKind), "\n");
1524     VERBOSE_LOG("    Might compile function: ", mightCompileFunctionFor(codeBlock, specializationKind), "\n");
1525     VERBOSE_LOG("    Is supported for inlining: ", isSupportedForInlining(codeBlock), "\n");
1526     VERBOSE_LOG("    Is inlining candidate: ", codeBlock->ownerExecutable()->isInliningCandidate(), "\n");
1527     if (!canInline(capabilityLevel)) {
1528         VERBOSE_LOG("    Failing because the function is not inlineable.\n");
1529         return UINT_MAX;
1530     }
1531     
1532     // Check if the caller is already too large. We do this check here because that's just
1533     // where we happen to also have the callee's code block, and we want that for the
1534     // purpose of unsetting SABI.
1535     if (!isSmallEnoughToInlineCodeInto(m_codeBlock)) {
1536         codeBlock->m_shouldAlwaysBeInlined = false;
1537         VERBOSE_LOG("    Failing because the caller is too large.\n");
1538         return UINT_MAX;
1539     }
1540     
1541     // FIXME: this should be better at predicting how much bloat we will introduce by inlining
1542     // this function.
1543     // https://bugs.webkit.org/show_bug.cgi?id=127627
1544     
1545     // FIXME: We currently inline functions that have run in LLInt but not in Baseline. These
1546     // functions have very low fidelity profiling, and presumably they weren't very hot if they
1547     // haven't gotten to Baseline yet. Consider not inlining these functions.
1548     // https://bugs.webkit.org/show_bug.cgi?id=145503
1549     
1550     // Have we exceeded inline stack depth, or are we trying to inline a recursive call to
1551     // too many levels? If either of these are detected, then don't inline. We adjust our
1552     // heuristics if we are dealing with a function that cannot otherwise be compiled.
1553     
1554     unsigned depth = 0;
1555     unsigned recursion = 0;
1556     
1557     for (InlineStackEntry* entry = m_inlineStackTop; entry; entry = entry->m_caller) {
1558         ++depth;
1559         if (depth >= Options::maximumInliningDepth()) {
1560             VERBOSE_LOG("    Failing because depth exceeded.\n");
1561             return UINT_MAX;
1562         }
1563         
1564         if (entry->executable() == executable) {
1565             ++recursion;
1566             if (recursion >= Options::maximumInliningRecursion()) {
1567                 VERBOSE_LOG("    Failing because recursion detected.\n");
1568                 return UINT_MAX;
1569             }
1570         }
1571     }
1572     
1573     VERBOSE_LOG("    Inlining should be possible.\n");
1574     
1575     // It might be possible to inline.
1576     return codeBlock->bytecodeCost();
1577 }
1578
1579 template<typename ChecksFunctor>
1580 void ByteCodeParser::inlineCall(Node* callTargetNode, VirtualRegister result, CallVariant callee, int registerOffset, int argumentCountIncludingThis, InlineCallFrame::Kind kind, BasicBlock* continuationBlock, const ChecksFunctor& insertChecks)
1581 {
1582     const Instruction* savedCurrentInstruction = m_currentInstruction;
1583     CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind);
1584
1585     CodeBlock* codeBlock = callee.functionExecutable()->baselineCodeBlockFor(specializationKind);
1586     insertChecks(codeBlock);
1587
1588     // FIXME: Don't flush constants!
1589
1590     // arityFixupCount and numberOfStackPaddingSlots are different. While arityFixupCount does not consider about stack alignment,
1591     // numberOfStackPaddingSlots consider alignment. Consider the following case,
1592     //
1593     // before: [ ... ][arg0][header]
1594     // after:  [ ... ][ext ][arg1][arg0][header]
1595     //
1596     // In the above case, arityFixupCount is 1. But numberOfStackPaddingSlots is 2 because the stack needs to be aligned.
1597     // We insert extra slots to align stack.
1598     int arityFixupCount = std::max<int>(codeBlock->numParameters() - argumentCountIncludingThis, 0);
1599     int numberOfStackPaddingSlots = CommonSlowPaths::numberOfStackPaddingSlots(codeBlock, argumentCountIncludingThis);
1600     ASSERT(!(numberOfStackPaddingSlots % stackAlignmentRegisters()));
1601     int registerOffsetAfterFixup = registerOffset - numberOfStackPaddingSlots;
1602     
1603     int inlineCallFrameStart = m_inlineStackTop->remapOperand(VirtualRegister(registerOffsetAfterFixup)).offset() + CallFrame::headerSizeInRegisters;
1604     
1605     ensureLocals(
1606         VirtualRegister(inlineCallFrameStart).toLocal() + 1 +
1607         CallFrame::headerSizeInRegisters + codeBlock->numCalleeLocals());
1608     
1609     size_t argumentPositionStart = m_graph.m_argumentPositions.size();
1610
1611     if (result.isValid())
1612         result = m_inlineStackTop->remapOperand(result);
1613
1614     VariableAccessData* calleeVariable = nullptr;
1615     if (callee.isClosureCall()) {
1616         Node* calleeSet = set(
1617             VirtualRegister(registerOffsetAfterFixup + CallFrameSlot::callee), callTargetNode, ImmediateNakedSet);
1618         
1619         calleeVariable = calleeSet->variableAccessData();
1620         calleeVariable->mergeShouldNeverUnbox(true);
1621     }
1622
1623     InlineStackEntry* callerStackTop = m_inlineStackTop;
1624     InlineStackEntry inlineStackEntry(this, codeBlock, codeBlock, callee.function(), result,
1625         (VirtualRegister)inlineCallFrameStart, argumentCountIncludingThis, kind, continuationBlock);
1626
1627     // This is where the actual inlining really happens.
1628     BytecodeIndex oldIndex = m_currentIndex;
1629     m_currentIndex = BytecodeIndex(0);
1630
1631     switch (kind) {
1632     case InlineCallFrame::GetterCall:
1633     case InlineCallFrame::SetterCall: {
1634         // When inlining getter and setter calls, we setup a stack frame which does not appear in the bytecode.
1635         // Because Inlining can switch on executable, we could have a graph like this.
1636         //
1637         // BB#0
1638         //     ...
1639         //     30: GetSetter
1640         //     31: MovHint(loc10)
1641         //     32: SetLocal(loc10)
1642         //     33: MovHint(loc9)
1643         //     34: SetLocal(loc9)
1644         //     ...
1645         //     37: GetExecutable(@30)
1646         //     ...
1647         //     41: Switch(@37)
1648         //
1649         // BB#2
1650         //     42: GetLocal(loc12, bc#7 of caller)
1651         //     ...
1652         //     --> callee: loc9 and loc10 are arguments of callee.
1653         //       ...
1654         //       <HERE, exit to callee, loc9 and loc10 are required in the bytecode>
1655         //
1656         // When we prune OSR availability at the beginning of BB#2 (bc#7 in the caller), we prune loc9 and loc10's liveness because the caller does not actually have loc9 and loc10.
1657         // However, when we begin executing the callee, we need OSR exit to be aware of where it can recover the arguments to the setter, loc9 and loc10. The MovHints in the inlined
1658         // callee make it so that if we exit at <HERE>, we can recover loc9 and loc10.
1659         for (int index = 0; index < argumentCountIncludingThis; ++index) {
1660             VirtualRegister argumentToGet = callerStackTop->remapOperand(virtualRegisterForArgument(index, registerOffset));
1661             Node* value = getDirect(argumentToGet);
1662             addToGraph(MovHint, OpInfo(argumentToGet.offset()), value);
1663             m_setLocalQueue.append(DelayedSetLocal { currentCodeOrigin(), argumentToGet, value, ImmediateNakedSet });
1664         }
1665         break;
1666     }
1667     default:
1668         break;
1669     }
1670
1671     if (arityFixupCount) {
1672         // Note: we do arity fixup in two phases:
1673         // 1. We get all the values we need and MovHint them to the expected locals.
1674         // 2. We SetLocal them after that. This way, if we exit, the callee's
1675         //    frame is already set up. If any SetLocal exits, we have a valid exit state.
1676         //    This is required because if we didn't do this in two phases, we may exit in
1677         //    the middle of arity fixup from the callee's CodeOrigin. This is unsound because exited
1678         //    code does not have arity fixup so that remaining necessary fixups are not executed.
1679         //    For example, consider if we need to pad two args:
1680         //    [arg3][arg2][arg1][arg0]
1681         //    [fix ][fix ][arg3][arg2][arg1][arg0]
1682         //    We memcpy starting from arg0 in the direction of arg3. If we were to exit at a type check
1683         //    for arg3's SetLocal in the callee's CodeOrigin, we'd exit with a frame like so:
1684         //    [arg3][arg2][arg1][arg2][arg1][arg0]
1685         //    Since we do not perform arity fixup in the callee, this is the frame used by the callee.
1686         //    And the callee would then just end up thinking its argument are:
1687         //    [fix ][fix ][arg3][arg2][arg1][arg0]
1688         //    which is incorrect.
1689
1690         Node* undefined = addToGraph(JSConstant, OpInfo(m_constantUndefined));
1691         // The stack needs to be aligned due to the JS calling convention. Thus, we have a hole if the count of arguments is not aligned.
1692         // We call this hole "extra slot". Consider the following case, the number of arguments is 2. If this argument
1693         // count does not fulfill the stack alignment requirement, we already inserted extra slots.
1694         //
1695         // before: [ ... ][ext ][arg1][arg0][header]
1696         //
1697         // In the above case, one extra slot is inserted. If the code's parameter count is 3, we will fixup arguments.
1698         // At that time, we can simply use this extra slots. So the fixuped stack is the following.
1699         //
1700         // before: [ ... ][ext ][arg1][arg0][header]
1701         // after:  [ ... ][arg2][arg1][arg0][header]
1702         //
1703         // In such cases, we do not need to move frames.
1704         if (registerOffsetAfterFixup != registerOffset) {
1705             for (int index = 0; index < argumentCountIncludingThis; ++index) {
1706                 VirtualRegister argumentToGet = callerStackTop->remapOperand(virtualRegisterForArgument(index, registerOffset));
1707                 Node* value = getDirect(argumentToGet);
1708                 VirtualRegister argumentToSet = m_inlineStackTop->remapOperand(virtualRegisterForArgument(index));
1709                 addToGraph(MovHint, OpInfo(argumentToSet.offset()), value);
1710                 m_setLocalQueue.append(DelayedSetLocal { currentCodeOrigin(), argumentToSet, value, ImmediateNakedSet });
1711             }
1712         }
1713         for (int index = 0; index < arityFixupCount; ++index) {
1714             VirtualRegister argumentToSet = m_inlineStackTop->remapOperand(virtualRegisterForArgument(argumentCountIncludingThis + index));
1715             addToGraph(MovHint, OpInfo(argumentToSet.offset()), undefined);
1716             m_setLocalQueue.append(DelayedSetLocal { currentCodeOrigin(), argumentToSet, undefined, ImmediateNakedSet });
1717         }
1718
1719         // At this point, it's OK to OSR exit because we finished setting up
1720         // our callee's frame. We emit an ExitOK below.
1721     }
1722
1723     // At this point, it's again OK to OSR exit.
1724     m_exitOK = true;
1725     addToGraph(ExitOK);
1726
1727     processSetLocalQueue();
1728
1729     InlineVariableData inlineVariableData;
1730     inlineVariableData.inlineCallFrame = m_inlineStackTop->m_inlineCallFrame;
1731     inlineVariableData.argumentPositionStart = argumentPositionStart;
1732     inlineVariableData.calleeVariable = 0;
1733     
1734     RELEASE_ASSERT(
1735         m_inlineStackTop->m_inlineCallFrame->isClosureCall
1736         == callee.isClosureCall());
1737     if (callee.isClosureCall()) {
1738         RELEASE_ASSERT(calleeVariable);
1739         inlineVariableData.calleeVariable = calleeVariable;
1740     }
1741     
1742     m_graph.m_inlineVariableData.append(inlineVariableData);
1743
1744     parseCodeBlock();
1745     clearCaches(); // Reset our state now that we're back to the outer code.
1746     
1747     m_currentIndex = oldIndex;
1748     m_exitOK = false;
1749
1750     linkBlocks(inlineStackEntry.m_unlinkedBlocks, inlineStackEntry.m_blockLinkingTargets);
1751     
1752     // Most functions have at least one op_ret and thus set up the continuation block.
1753     // In some rare cases, a function ends in op_unreachable, forcing us to allocate a new continuationBlock here.
1754     if (inlineStackEntry.m_continuationBlock)
1755         m_currentBlock = inlineStackEntry.m_continuationBlock;
1756     else
1757         m_currentBlock = allocateUntargetableBlock();
1758     ASSERT(!m_currentBlock->terminal());
1759
1760     prepareToParseBlock();
1761     m_currentInstruction = savedCurrentInstruction;
1762 }
1763
1764 ByteCodeParser::CallOptimizationResult ByteCodeParser::handleCallVariant(Node* callTargetNode, VirtualRegister result, CallVariant callee, int registerOffset, VirtualRegister thisArgument, int argumentCountIncludingThis, BytecodeIndex nextIndex, InlineCallFrame::Kind kind, SpeculatedType prediction, unsigned& inliningBalance, BasicBlock* continuationBlock, bool needsToCheckCallee)
1765 {
1766     VERBOSE_LOG("    Considering callee ", callee, "\n");
1767
1768     bool didInsertChecks = false;
1769     auto insertChecksWithAccounting = [&] () {
1770         if (needsToCheckCallee)
1771             emitFunctionChecks(callee, callTargetNode, thisArgument);
1772         didInsertChecks = true;
1773     };
1774
1775     if (kind == InlineCallFrame::TailCall && ByteCodeParser::handleRecursiveTailCall(callTargetNode, callee, registerOffset, argumentCountIncludingThis, insertChecksWithAccounting)) {
1776         RELEASE_ASSERT(didInsertChecks);
1777         return CallOptimizationResult::OptimizedToJump;
1778     }
1779     RELEASE_ASSERT(!didInsertChecks);
1780
1781     if (!inliningBalance)
1782         return CallOptimizationResult::DidNothing;
1783
1784     CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind);
1785
1786     auto endSpecialCase = [&] () {
1787         RELEASE_ASSERT(didInsertChecks);
1788         addToGraph(Phantom, callTargetNode);
1789         emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
1790         inliningBalance--;
1791         if (continuationBlock) {
1792             m_currentIndex = nextIndex;
1793             m_exitOK = true;
1794             processSetLocalQueue();
1795             addJumpTo(continuationBlock);
1796         }
1797     };
1798
1799     if (InternalFunction* function = callee.internalFunction()) {
1800         if (handleConstantInternalFunction(callTargetNode, result, function, registerOffset, argumentCountIncludingThis, specializationKind, prediction, insertChecksWithAccounting)) {
1801             endSpecialCase();
1802             return CallOptimizationResult::Inlined;
1803         }
1804         RELEASE_ASSERT(!didInsertChecks);
1805         return CallOptimizationResult::DidNothing;
1806     }
1807
1808     Intrinsic intrinsic = callee.intrinsicFor(specializationKind);
1809     if (intrinsic != NoIntrinsic) {
1810         if (handleIntrinsicCall(callTargetNode, result, intrinsic, registerOffset, argumentCountIncludingThis, prediction, insertChecksWithAccounting)) {
1811             endSpecialCase();
1812             return CallOptimizationResult::Inlined;
1813         }
1814         RELEASE_ASSERT(!didInsertChecks);
1815         // We might still try to inline the Intrinsic because it might be a builtin JS function.
1816     }
1817
1818     if (Options::useDOMJIT()) {
1819         if (const DOMJIT::Signature* signature = callee.signatureFor(specializationKind)) {
1820             if (handleDOMJITCall(callTargetNode, result, signature, registerOffset, argumentCountIncludingThis, prediction, insertChecksWithAccounting)) {
1821                 endSpecialCase();
1822                 return CallOptimizationResult::Inlined;
1823             }
1824             RELEASE_ASSERT(!didInsertChecks);
1825         }
1826     }
1827     
1828     unsigned myInliningCost = inliningCost(callee, argumentCountIncludingThis, kind);
1829     if (myInliningCost > inliningBalance)
1830         return CallOptimizationResult::DidNothing;
1831
1832     auto insertCheck = [&] (CodeBlock*) {
1833         if (needsToCheckCallee)
1834             emitFunctionChecks(callee, callTargetNode, thisArgument);
1835     };
1836     inlineCall(callTargetNode, result, callee, registerOffset, argumentCountIncludingThis, kind, continuationBlock, insertCheck);
1837     inliningBalance -= myInliningCost;
1838     return CallOptimizationResult::Inlined;
1839 }
1840
1841 bool ByteCodeParser::handleVarargsInlining(Node* callTargetNode, VirtualRegister result,
1842     const CallLinkStatus& callLinkStatus, int firstFreeReg, VirtualRegister thisArgument,
1843     VirtualRegister argumentsArgument, unsigned argumentsOffset,
1844     NodeType callOp, InlineCallFrame::Kind kind)
1845 {
1846     VERBOSE_LOG("Handling inlining (Varargs)...\nStack: ", currentCodeOrigin(), "\n");
1847     if (callLinkStatus.maxArgumentCountIncludingThis() > Options::maximumVarargsForInlining()) {
1848         VERBOSE_LOG("Bailing inlining: too many arguments for varargs inlining.\n");
1849         return false;
1850     }
1851     if (callLinkStatus.couldTakeSlowPath() || callLinkStatus.size() != 1) {
1852         VERBOSE_LOG("Bailing inlining: polymorphic inlining is not yet supported for varargs.\n");
1853         return false;
1854     }
1855
1856     CallVariant callVariant = callLinkStatus[0];
1857
1858     unsigned mandatoryMinimum;
1859     if (FunctionExecutable* functionExecutable = callVariant.functionExecutable())
1860         mandatoryMinimum = functionExecutable->parameterCount();
1861     else
1862         mandatoryMinimum = 0;
1863     
1864     // includes "this"
1865     unsigned maxArgumentCountIncludingThis = std::max(callLinkStatus.maxArgumentCountIncludingThis(), mandatoryMinimum + 1);
1866
1867     CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind);
1868     if (inliningCost(callVariant, maxArgumentCountIncludingThis, kind) > getInliningBalance(callLinkStatus, specializationKind)) {
1869         VERBOSE_LOG("Bailing inlining: inlining cost too high.\n");
1870         return false;
1871     }
1872     
1873     int registerOffset = firstFreeReg;
1874     registerOffset -= maxArgumentCountIncludingThis;
1875     registerOffset -= CallFrame::headerSizeInRegisters;
1876     registerOffset = -WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -registerOffset);
1877
1878     auto insertChecks = [&] (CodeBlock* codeBlock) {
1879         emitFunctionChecks(callVariant, callTargetNode, thisArgument);
1880         
1881         int remappedRegisterOffset =
1882         m_inlineStackTop->remapOperand(VirtualRegister(registerOffset)).offset();
1883         
1884         ensureLocals(VirtualRegister(remappedRegisterOffset).toLocal());
1885         
1886         int argumentStart = registerOffset + CallFrame::headerSizeInRegisters;
1887         int remappedArgumentStart = m_inlineStackTop->remapOperand(VirtualRegister(argumentStart)).offset();
1888         
1889         LoadVarargsData* data = m_graph.m_loadVarargsData.add();
1890         data->start = VirtualRegister(remappedArgumentStart + 1);
1891         data->count = VirtualRegister(remappedRegisterOffset + CallFrameSlot::argumentCount);
1892         data->offset = argumentsOffset;
1893         data->limit = maxArgumentCountIncludingThis;
1894         data->mandatoryMinimum = mandatoryMinimum;
1895         
1896         if (callOp == TailCallForwardVarargs)
1897             addToGraph(ForwardVarargs, OpInfo(data));
1898         else
1899             addToGraph(LoadVarargs, OpInfo(data), get(argumentsArgument));
1900         
1901         // LoadVarargs may OSR exit. Hence, we need to keep alive callTargetNode, thisArgument
1902         // and argumentsArgument for the baseline JIT. However, we only need a Phantom for
1903         // callTargetNode because the other 2 are still in use and alive at this point.
1904         addToGraph(Phantom, callTargetNode);
1905         
1906         // In DFG IR before SSA, we cannot insert control flow between after the
1907         // LoadVarargs and the last SetArgumentDefinitely. This isn't a problem once we get to DFG
1908         // SSA. Fortunately, we also have other reasons for not inserting control flow
1909         // before SSA.
1910         
1911         VariableAccessData* countVariable = newVariableAccessData(VirtualRegister(remappedRegisterOffset + CallFrameSlot::argumentCount));
1912         // This is pretty lame, but it will force the count to be flushed as an int. This doesn't
1913         // matter very much, since our use of a SetArgumentDefinitely and Flushes for this local slot is
1914         // mostly just a formality.
1915         countVariable->predict(SpecInt32Only);
1916         countVariable->mergeIsProfitableToUnbox(true);
1917         Node* setArgumentCount = addToGraph(SetArgumentDefinitely, OpInfo(countVariable));
1918         m_currentBlock->variablesAtTail.setOperand(countVariable->local(), setArgumentCount);
1919         
1920         set(VirtualRegister(argumentStart), get(thisArgument), ImmediateNakedSet);
1921         unsigned numSetArguments = 0;
1922         for (unsigned argument = 1; argument < maxArgumentCountIncludingThis; ++argument) {
1923             VariableAccessData* variable = newVariableAccessData(VirtualRegister(remappedArgumentStart + argument));
1924             variable->mergeShouldNeverUnbox(true); // We currently have nowhere to put the type check on the LoadVarargs. LoadVarargs is effectful, so after it finishes, we cannot exit.
1925             
1926             // For a while it had been my intention to do things like this inside the
1927             // prediction injection phase. But in this case it's really best to do it here,
1928             // because it's here that we have access to the variable access datas for the
1929             // inlining we're about to do.
1930             //
1931             // Something else that's interesting here is that we'd really love to get
1932             // predictions from the arguments loaded at the callsite, rather than the
1933             // arguments received inside the callee. But that probably won't matter for most
1934             // calls.
1935             if (codeBlock && argument < static_cast<unsigned>(codeBlock->numParameters())) {
1936                 ConcurrentJSLocker locker(codeBlock->m_lock);
1937                 ValueProfile& profile = codeBlock->valueProfileForArgument(argument);
1938                 variable->predict(profile.computeUpdatedPrediction(locker));
1939             }
1940             
1941             Node* setArgument = addToGraph(numSetArguments >= mandatoryMinimum ? SetArgumentMaybe : SetArgumentDefinitely, OpInfo(variable));
1942             m_currentBlock->variablesAtTail.setOperand(variable->local(), setArgument);
1943             ++numSetArguments;
1944         }
1945     };
1946
1947     // Intrinsics and internal functions can only be inlined if we're not doing varargs. This is because
1948     // we currently don't have any way of getting profiling information for arguments to non-JS varargs
1949     // calls. The prediction propagator won't be of any help because LoadVarargs obscures the data flow,
1950     // and there are no callsite value profiles and native function won't have callee value profiles for
1951     // those arguments. Even worse, if the intrinsic decides to exit, it won't really have anywhere to
1952     // exit to: LoadVarargs is effectful and it's part of the op_call_varargs, so we can't exit without
1953     // calling LoadVarargs twice.
1954     inlineCall(callTargetNode, result, callVariant, registerOffset, maxArgumentCountIncludingThis, kind, nullptr, insertChecks);
1955
1956
1957     VERBOSE_LOG("Successful inlining (varargs, monomorphic).\nStack: ", currentCodeOrigin(), "\n");
1958     return true;
1959 }
1960
1961 unsigned ByteCodeParser::getInliningBalance(const CallLinkStatus& callLinkStatus, CodeSpecializationKind specializationKind)
1962 {
1963     unsigned inliningBalance = Options::maximumFunctionForCallInlineCandidateBytecodeCost();
1964     if (specializationKind == CodeForConstruct)
1965         inliningBalance = std::min(inliningBalance, Options::maximumFunctionForConstructInlineCandidateBytecoodeCost());
1966     if (callLinkStatus.isClosureCall())
1967         inliningBalance = std::min(inliningBalance, Options::maximumFunctionForClosureCallInlineCandidateBytecodeCost());
1968     return inliningBalance;
1969 }
1970
1971 ByteCodeParser::CallOptimizationResult ByteCodeParser::handleInlining(
1972     Node* callTargetNode, VirtualRegister result, const CallLinkStatus& callLinkStatus,
1973     int registerOffset, VirtualRegister thisArgument,
1974     int argumentCountIncludingThis,
1975     BytecodeIndex nextIndex, NodeType callOp, InlineCallFrame::Kind kind, SpeculatedType prediction)
1976 {
1977     VERBOSE_LOG("Handling inlining...\nStack: ", currentCodeOrigin(), "\n");
1978     
1979     CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind);
1980     unsigned inliningBalance = getInliningBalance(callLinkStatus, specializationKind);
1981
1982     // First check if we can avoid creating control flow. Our inliner does some CFG
1983     // simplification on the fly and this helps reduce compile times, but we can only leverage
1984     // this in cases where we don't need control flow diamonds to check the callee.
1985     if (!callLinkStatus.couldTakeSlowPath() && callLinkStatus.size() == 1) {
1986         return handleCallVariant(
1987             callTargetNode, result, callLinkStatus[0], registerOffset, thisArgument,
1988             argumentCountIncludingThis, nextIndex, kind, prediction, inliningBalance, nullptr, true);
1989     }
1990
1991     // We need to create some kind of switch over callee. For now we only do this if we believe that
1992     // we're in the top tier. We have two reasons for this: first, it provides us an opportunity to
1993     // do more detailed polyvariant/polymorphic profiling; and second, it reduces compile times in
1994     // the DFG. And by polyvariant profiling we mean polyvariant profiling of *this* call. Note that
1995     // we could improve that aspect of this by doing polymorphic inlining but having the profiling
1996     // also.
1997     if (!m_graph.m_plan.isFTL() || !Options::usePolymorphicCallInlining()) {
1998         VERBOSE_LOG("Bailing inlining (hard).\nStack: ", currentCodeOrigin(), "\n");
1999         return CallOptimizationResult::DidNothing;
2000     }
2001     
2002     // If the claim is that this did not originate from a stub, then we don't want to emit a switch
2003     // statement. Whenever the non-stub profiling says that it could take slow path, it really means that
2004     // it has no idea.
2005     if (!Options::usePolymorphicCallInliningForNonStubStatus()
2006         && !callLinkStatus.isBasedOnStub()) {
2007         VERBOSE_LOG("Bailing inlining (non-stub polymorphism).\nStack: ", currentCodeOrigin(), "\n");
2008         return CallOptimizationResult::DidNothing;
2009     }
2010
2011     bool allAreClosureCalls = true;
2012     bool allAreDirectCalls = true;
2013     for (unsigned i = callLinkStatus.size(); i--;) {
2014         if (callLinkStatus[i].isClosureCall())
2015             allAreDirectCalls = false;
2016         else
2017             allAreClosureCalls = false;
2018     }
2019
2020     Node* thingToSwitchOn;
2021     if (allAreDirectCalls)
2022         thingToSwitchOn = callTargetNode;
2023     else if (allAreClosureCalls)
2024         thingToSwitchOn = addToGraph(GetExecutable, callTargetNode);
2025     else {
2026         // FIXME: We should be able to handle this case, but it's tricky and we don't know of cases
2027         // where it would be beneficial. It might be best to handle these cases as if all calls were
2028         // closure calls.
2029         // https://bugs.webkit.org/show_bug.cgi?id=136020
2030         VERBOSE_LOG("Bailing inlining (mix).\nStack: ", currentCodeOrigin(), "\n");
2031         return CallOptimizationResult::DidNothing;
2032     }
2033
2034     VERBOSE_LOG("Doing hard inlining...\nStack: ", currentCodeOrigin(), "\n");
2035
2036     // This makes me wish that we were in SSA all the time. We need to pick a variable into which to
2037     // store the callee so that it will be accessible to all of the blocks we're about to create. We
2038     // get away with doing an immediate-set here because we wouldn't have performed any side effects
2039     // yet.
2040     VERBOSE_LOG("Register offset: ", registerOffset);
2041     VirtualRegister calleeReg(registerOffset + CallFrameSlot::callee);
2042     calleeReg = m_inlineStackTop->remapOperand(calleeReg);
2043     VERBOSE_LOG("Callee is going to be ", calleeReg, "\n");
2044     setDirect(calleeReg, callTargetNode, ImmediateSetWithFlush);
2045
2046     // It's OK to exit right now, even though we set some locals. That's because those locals are not
2047     // user-visible.
2048     m_exitOK = true;
2049     addToGraph(ExitOK);
2050     
2051     SwitchData& data = *m_graph.m_switchData.add();
2052     data.kind = SwitchCell;
2053     addToGraph(Switch, OpInfo(&data), thingToSwitchOn);
2054     m_currentBlock->didLink();
2055     
2056     BasicBlock* continuationBlock = allocateUntargetableBlock();
2057     VERBOSE_LOG("Adding untargetable block ", RawPointer(continuationBlock), " (continuation)\n");
2058     
2059     // We may force this true if we give up on inlining any of the edges.
2060     bool couldTakeSlowPath = callLinkStatus.couldTakeSlowPath();
2061     
2062     VERBOSE_LOG("About to loop over functions at ", currentCodeOrigin(), ".\n");
2063
2064     BytecodeIndex oldIndex = m_currentIndex;
2065     for (unsigned i = 0; i < callLinkStatus.size(); ++i) {
2066         m_currentIndex = oldIndex;
2067         BasicBlock* calleeEntryBlock = allocateUntargetableBlock();
2068         m_currentBlock = calleeEntryBlock;
2069         prepareToParseBlock();
2070
2071         // At the top of each switch case, we can exit.
2072         m_exitOK = true;
2073         
2074         Node* myCallTargetNode = getDirect(calleeReg);
2075         
2076         auto inliningResult = handleCallVariant(
2077             myCallTargetNode, result, callLinkStatus[i], registerOffset,
2078             thisArgument, argumentCountIncludingThis, nextIndex, kind, prediction,
2079             inliningBalance, continuationBlock, false);
2080         
2081         if (inliningResult == CallOptimizationResult::DidNothing) {
2082             // That failed so we let the block die. Nothing interesting should have been added to
2083             // the block. We also give up on inlining any of the (less frequent) callees.
2084             ASSERT(m_graph.m_blocks.last() == m_currentBlock);
2085             m_graph.killBlockAndItsContents(m_currentBlock);
2086             m_graph.m_blocks.removeLast();
2087             VERBOSE_LOG("Inlining of a poly call failed, we will have to go through a slow path\n");
2088
2089             // The fact that inlining failed means we need a slow path.
2090             couldTakeSlowPath = true;
2091             break;
2092         }
2093         
2094         JSCell* thingToCaseOn;
2095         if (allAreDirectCalls)
2096             thingToCaseOn = callLinkStatus[i].nonExecutableCallee();
2097         else {
2098             ASSERT(allAreClosureCalls);
2099             thingToCaseOn = callLinkStatus[i].executable();
2100         }
2101         data.cases.append(SwitchCase(m_graph.freeze(thingToCaseOn), calleeEntryBlock));
2102         VERBOSE_LOG("Finished optimizing ", callLinkStatus[i], " at ", currentCodeOrigin(), ".\n");
2103     }
2104
2105     // Slow path block
2106     m_currentBlock = allocateUntargetableBlock();
2107     m_currentIndex = oldIndex;
2108     m_exitOK = true;
2109     data.fallThrough = BranchTarget(m_currentBlock);
2110     prepareToParseBlock();
2111     Node* myCallTargetNode = getDirect(calleeReg);
2112     if (couldTakeSlowPath) {
2113         addCall(
2114             result, callOp, nullptr, myCallTargetNode, argumentCountIncludingThis,
2115             registerOffset, prediction);
2116         VERBOSE_LOG("We added a call in the slow path\n");
2117     } else {
2118         addToGraph(CheckBadCell);
2119         addToGraph(Phantom, myCallTargetNode);
2120         emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
2121         
2122         if (result.isValid())
2123             set(result, addToGraph(BottomValue));
2124         VERBOSE_LOG("couldTakeSlowPath was false\n");
2125     }
2126
2127     m_currentIndex = nextIndex;
2128     m_exitOK = true; // Origin changed, so it's fine to exit again.
2129     processSetLocalQueue();
2130
2131     if (Node* terminal = m_currentBlock->terminal())
2132         ASSERT_UNUSED(terminal, terminal->op() == TailCall || terminal->op() == TailCallVarargs || terminal->op() == TailCallForwardVarargs);
2133     else {
2134         addJumpTo(continuationBlock);
2135     }
2136
2137     prepareToParseBlock();
2138     
2139     m_currentIndex = oldIndex;
2140     m_currentBlock = continuationBlock;
2141     m_exitOK = true;
2142     
2143     VERBOSE_LOG("Done inlining (hard).\nStack: ", currentCodeOrigin(), "\n");
2144     return CallOptimizationResult::Inlined;
2145 }
2146
2147 template<typename ChecksFunctor>
2148 bool ByteCodeParser::handleMinMax(VirtualRegister result, NodeType op, int registerOffset, int argumentCountIncludingThis, const ChecksFunctor& insertChecks)
2149 {
2150     ASSERT(op == ArithMin || op == ArithMax);
2151
2152     if (argumentCountIncludingThis == 1) {
2153         insertChecks();
2154         double limit = op == ArithMax ? -std::numeric_limits<double>::infinity() : +std::numeric_limits<double>::infinity();
2155         set(result, addToGraph(JSConstant, OpInfo(m_graph.freeze(jsDoubleNumber(limit)))));
2156         return true;
2157     }
2158      
2159     if (argumentCountIncludingThis == 2) {
2160         insertChecks();
2161         Node* resultNode = get(VirtualRegister(virtualRegisterForArgument(1, registerOffset)));
2162         addToGraph(Phantom, Edge(resultNode, NumberUse));
2163         set(result, resultNode);
2164         return true;
2165     }
2166     
2167     if (argumentCountIncludingThis == 3) {
2168         insertChecks();
2169         set(result, addToGraph(op, get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset))));
2170         return true;
2171     }
2172     
2173     // Don't handle >=3 arguments for now.
2174     return false;
2175 }
2176
2177 template<typename ChecksFunctor>
2178 bool ByteCodeParser::handleIntrinsicCall(Node* callee, VirtualRegister result, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks)
2179 {
2180     VERBOSE_LOG("       The intrinsic is ", intrinsic, "\n");
2181
2182     if (!isOpcodeShape<OpCallShape>(m_currentInstruction))
2183         return false;
2184
2185     // It so happens that the code below doesn't handle the invalid result case. We could fix that, but
2186     // it would only benefit intrinsics called as setters, like if you do:
2187     //
2188     //     o.__defineSetter__("foo", Math.pow)
2189     //
2190     // Which is extremely amusing, but probably not worth optimizing.
2191     if (!result.isValid())
2192         return false;
2193
2194     bool didSetResult = false;
2195     auto setResult = [&] (Node* node) {
2196         RELEASE_ASSERT(!didSetResult);
2197         set(result, node);
2198         didSetResult = true;
2199     };
2200
2201     auto inlineIntrinsic = [&] {
2202         switch (intrinsic) {
2203
2204         // Intrinsic Functions:
2205
2206         case AbsIntrinsic: {
2207             if (argumentCountIncludingThis == 1) { // Math.abs()
2208                 insertChecks();
2209                 setResult(addToGraph(JSConstant, OpInfo(m_constantNaN)));
2210                 return true;
2211             }
2212
2213             if (!MacroAssembler::supportsFloatingPointAbs())
2214                 return false;
2215
2216             insertChecks();
2217             Node* node = addToGraph(ArithAbs, get(virtualRegisterForArgument(1, registerOffset)));
2218             if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
2219                 node->mergeFlags(NodeMayOverflowInt32InDFG);
2220             setResult(node);
2221             return true;
2222         }
2223
2224         case MinIntrinsic:
2225         case MaxIntrinsic:
2226             if (handleMinMax(result, intrinsic == MinIntrinsic ? ArithMin : ArithMax, registerOffset, argumentCountIncludingThis, insertChecks)) {
2227                 didSetResult = true;
2228                 return true;
2229             }
2230             return false;
2231
2232 #define DFG_ARITH_UNARY(capitalizedName, lowerName) \
2233         case capitalizedName##Intrinsic:
2234         FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY)
2235 #undef DFG_ARITH_UNARY
2236         {
2237             if (argumentCountIncludingThis == 1) {
2238                 insertChecks();
2239                 setResult(addToGraph(JSConstant, OpInfo(m_constantNaN)));
2240                 return true;
2241             }
2242             Arith::UnaryType type = Arith::UnaryType::Sin;
2243             switch (intrinsic) {
2244 #define DFG_ARITH_UNARY(capitalizedName, lowerName) \
2245             case capitalizedName##Intrinsic: \
2246                 type = Arith::UnaryType::capitalizedName; \
2247                 break;
2248         FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY)
2249 #undef DFG_ARITH_UNARY
2250             default:
2251                 RELEASE_ASSERT_NOT_REACHED();
2252             }
2253             insertChecks();
2254             setResult(addToGraph(ArithUnary, OpInfo(static_cast<std::underlying_type<Arith::UnaryType>::type>(type)), get(virtualRegisterForArgument(1, registerOffset))));
2255             return true;
2256         }
2257
2258         case FRoundIntrinsic:
2259         case SqrtIntrinsic: {
2260             if (argumentCountIncludingThis == 1) {
2261                 insertChecks();
2262                 setResult(addToGraph(JSConstant, OpInfo(m_constantNaN)));
2263                 return true;
2264             }
2265
2266             NodeType nodeType = Unreachable;
2267             switch (intrinsic) {
2268             case FRoundIntrinsic:
2269                 nodeType = ArithFRound;
2270                 break;
2271             case SqrtIntrinsic:
2272                 nodeType = ArithSqrt;
2273                 break;
2274             default:
2275                 RELEASE_ASSERT_NOT_REACHED();
2276             }
2277             insertChecks();
2278             setResult(addToGraph(nodeType, get(virtualRegisterForArgument(1, registerOffset))));
2279             return true;
2280         }
2281
2282         case PowIntrinsic: {
2283             if (argumentCountIncludingThis < 3) {
2284                 // Math.pow() and Math.pow(x) return NaN.
2285                 insertChecks();
2286                 setResult(addToGraph(JSConstant, OpInfo(m_constantNaN)));
2287                 return true;
2288             }
2289             insertChecks();
2290             VirtualRegister xOperand = virtualRegisterForArgument(1, registerOffset);
2291             VirtualRegister yOperand = virtualRegisterForArgument(2, registerOffset);
2292             setResult(addToGraph(ArithPow, get(xOperand), get(yOperand)));
2293             return true;
2294         }
2295             
2296         case ArrayPushIntrinsic: {
2297             if (static_cast<unsigned>(argumentCountIncludingThis) >= MIN_SPARSE_ARRAY_INDEX)
2298                 return false;
2299             
2300             ArrayMode arrayMode = getArrayMode(Array::Write);
2301             if (!arrayMode.isJSArray())
2302                 return false;
2303             switch (arrayMode.type()) {
2304             case Array::Int32:
2305             case Array::Double:
2306             case Array::Contiguous:
2307             case Array::ArrayStorage: {
2308                 insertChecks();
2309
2310                 addVarArgChild(nullptr); // For storage.
2311                 for (int i = 0; i < argumentCountIncludingThis; ++i)
2312                     addVarArgChild(get(virtualRegisterForArgument(i, registerOffset)));
2313                 Node* arrayPush = addToGraph(Node::VarArg, ArrayPush, OpInfo(arrayMode.asWord()), OpInfo(prediction));
2314                 setResult(arrayPush);
2315                 return true;
2316             }
2317                 
2318             default:
2319                 return false;
2320             }
2321         }
2322
2323         case ArraySliceIntrinsic: {
2324             if (argumentCountIncludingThis < 1)
2325                 return false;
2326
2327             if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantCache)
2328                 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache))
2329                 return false;
2330
2331             ArrayMode arrayMode = getArrayMode(Array::Read);
2332             if (!arrayMode.isJSArray())
2333                 return false;
2334
2335             if (!arrayMode.isJSArrayWithOriginalStructure())
2336                 return false;
2337
2338             switch (arrayMode.type()) {
2339             case Array::Double:
2340             case Array::Int32:
2341             case Array::Contiguous: {
2342                 JSGlobalObject* globalObject = m_graph.globalObjectFor(currentNodeOrigin().semantic);
2343
2344                 Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(*m_vm);
2345                 Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(*m_vm);
2346
2347                 // FIXME: We could easily relax the Array/Object.prototype transition as long as we OSR exitted if we saw a hole.
2348                 // https://bugs.webkit.org/show_bug.cgi?id=173171
2349                 if (globalObject->arraySpeciesWatchpointSet().state() == IsWatched
2350                     && globalObject->havingABadTimeWatchpoint()->isStillValid()
2351                     && arrayPrototypeStructure->transitionWatchpointSetIsStillValid()
2352                     && objectPrototypeStructure->transitionWatchpointSetIsStillValid()
2353                     && globalObject->arrayPrototypeChainIsSane()) {
2354
2355                     m_graph.watchpoints().addLazily(globalObject->arraySpeciesWatchpointSet());
2356                     m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
2357                     m_graph.registerAndWatchStructureTransition(arrayPrototypeStructure);
2358                     m_graph.registerAndWatchStructureTransition(objectPrototypeStructure);
2359
2360                     insertChecks();
2361
2362                     Node* array = get(virtualRegisterForArgument(0, registerOffset));
2363                     // We do a few things here to prove that we aren't skipping doing side-effects in an observable way:
2364                     // 1. We ensure that the "constructor" property hasn't been changed (because the observable
2365                     // effects of slice require that we perform a Get(array, "constructor") and we can skip
2366                     // that if we're an original array structure. (We can relax this in the future by using
2367                     // TryGetById and CheckCell).
2368                     //
2369                     // 2. We check that the array we're calling slice on has the same global object as the lexical
2370                     // global object that this code is running in. This requirement is necessary because we setup the
2371                     // watchpoints above on the lexical global object. This means that code that calls slice on
2372                     // arrays produced by other global objects won't get this optimization. We could relax this
2373                     // requirement in the future by checking that the watchpoint hasn't fired at runtime in the code
2374                     // we generate instead of registering it as a watchpoint that would invalidate the compilation.
2375                     //
2376                     // 3. By proving we're an original array structure, we guarantee that the incoming array
2377                     // isn't a subclass of Array.
2378
2379                     StructureSet structureSet;
2380                     structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32));
2381                     structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous));
2382                     structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble));
2383                     structureSet.add(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithInt32));
2384                     structureSet.add(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithContiguous));
2385                     structureSet.add(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithDouble));
2386                     addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structureSet)), array);
2387
2388                     addVarArgChild(array);
2389                     if (argumentCountIncludingThis >= 2)
2390                         addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); // Start index.
2391                     if (argumentCountIncludingThis >= 3)
2392                         addVarArgChild(get(virtualRegisterForArgument(2, registerOffset))); // End index.
2393                     addVarArgChild(addToGraph(GetButterfly, array));
2394
2395                     Node* arraySlice = addToGraph(Node::VarArg, ArraySlice, OpInfo(), OpInfo());
2396                     setResult(arraySlice);
2397                     return true;
2398                 }
2399
2400                 return false;
2401             }
2402             default:
2403                 return false;
2404             }
2405
2406             RELEASE_ASSERT_NOT_REACHED();
2407             return false;
2408         }
2409
2410         case ArrayIndexOfIntrinsic: {
2411             if (argumentCountIncludingThis < 2)
2412                 return false;
2413
2414             if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType)
2415                 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantCache)
2416                 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)
2417                 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
2418                 return false;
2419
2420             ArrayMode arrayMode = getArrayMode(Array::Read);
2421             if (!arrayMode.isJSArray())
2422                 return false;
2423
2424             if (!arrayMode.isJSArrayWithOriginalStructure())
2425                 return false;
2426
2427             // We do not want to convert arrays into one type just to perform indexOf.
2428             if (arrayMode.doesConversion())
2429                 return false;
2430
2431             switch (arrayMode.type()) {
2432             case Array::Double:
2433             case Array::Int32:
2434             case Array::Contiguous: {
2435                 JSGlobalObject* globalObject = m_graph.globalObjectFor(currentNodeOrigin().semantic);
2436
2437                 Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(*m_vm);
2438                 Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(*m_vm);
2439
2440                 // FIXME: We could easily relax the Array/Object.prototype transition as long as we OSR exitted if we saw a hole.
2441                 // https://bugs.webkit.org/show_bug.cgi?id=173171
2442                 if (arrayPrototypeStructure->transitionWatchpointSetIsStillValid()
2443                     && objectPrototypeStructure->transitionWatchpointSetIsStillValid()
2444                     && globalObject->arrayPrototypeChainIsSane()) {
2445
2446                     m_graph.registerAndWatchStructureTransition(arrayPrototypeStructure);
2447                     m_graph.registerAndWatchStructureTransition(objectPrototypeStructure);
2448
2449                     insertChecks();
2450
2451                     Node* array = get(virtualRegisterForArgument(0, registerOffset));
2452                     addVarArgChild(array);
2453                     addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); // Search element.
2454                     if (argumentCountIncludingThis >= 3)
2455                         addVarArgChild(get(virtualRegisterForArgument(2, registerOffset))); // Start index.
2456                     addVarArgChild(nullptr);
2457
2458                     Node* node = addToGraph(Node::VarArg, ArrayIndexOf, OpInfo(arrayMode.asWord()), OpInfo());
2459                     setResult(node);
2460                     return true;
2461                 }
2462
2463                 return false;
2464             }
2465             default:
2466                 return false;
2467             }
2468
2469             RELEASE_ASSERT_NOT_REACHED();
2470             return false;
2471
2472         }
2473             
2474         case ArrayPopIntrinsic: {
2475             ArrayMode arrayMode = getArrayMode(Array::Write);
2476             if (!arrayMode.isJSArray())
2477                 return false;
2478             switch (arrayMode.type()) {
2479             case Array::Int32:
2480             case Array::Double:
2481             case Array::Contiguous:
2482             case Array::ArrayStorage: {
2483                 insertChecks();
2484                 Node* arrayPop = addToGraph(ArrayPop, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)));
2485                 setResult(arrayPop);
2486                 return true;
2487             }
2488                 
2489             default:
2490                 return false;
2491             }
2492         }
2493             
2494         case AtomicsAddIntrinsic:
2495         case AtomicsAndIntrinsic:
2496         case AtomicsCompareExchangeIntrinsic:
2497         case AtomicsExchangeIntrinsic:
2498         case AtomicsIsLockFreeIntrinsic:
2499         case AtomicsLoadIntrinsic:
2500         case AtomicsOrIntrinsic:
2501         case AtomicsStoreIntrinsic:
2502         case AtomicsSubIntrinsic:
2503         case AtomicsXorIntrinsic: {
2504             if (!is64Bit())
2505                 return false;
2506             
2507             NodeType op = LastNodeType;
2508             Array::Action action = Array::Write;
2509             unsigned numArgs = 0; // Number of actual args; we add one for the backing store pointer.
2510             switch (intrinsic) {
2511             case AtomicsAddIntrinsic:
2512                 op = AtomicsAdd;
2513                 numArgs = 3;
2514                 break;
2515             case AtomicsAndIntrinsic:
2516                 op = AtomicsAnd;
2517                 numArgs = 3;
2518                 break;
2519             case AtomicsCompareExchangeIntrinsic:
2520                 op = AtomicsCompareExchange;
2521                 numArgs = 4;
2522                 break;
2523             case AtomicsExchangeIntrinsic:
2524                 op = AtomicsExchange;
2525                 numArgs = 3;
2526                 break;
2527             case AtomicsIsLockFreeIntrinsic:
2528                 // This gets no backing store, but we need no special logic for this since this also does
2529                 // not need varargs.
2530                 op = AtomicsIsLockFree;
2531                 numArgs = 1;
2532                 break;
2533             case AtomicsLoadIntrinsic:
2534                 op = AtomicsLoad;
2535                 numArgs = 2;
2536                 action = Array::Read;
2537                 break;
2538             case AtomicsOrIntrinsic:
2539                 op = AtomicsOr;
2540                 numArgs = 3;
2541                 break;
2542             case AtomicsStoreIntrinsic:
2543                 op = AtomicsStore;
2544                 numArgs = 3;
2545                 break;
2546             case AtomicsSubIntrinsic:
2547                 op = AtomicsSub;
2548                 numArgs = 3;
2549                 break;
2550             case AtomicsXorIntrinsic:
2551                 op = AtomicsXor;
2552                 numArgs = 3;
2553                 break;
2554             default:
2555                 RELEASE_ASSERT_NOT_REACHED();
2556                 break;
2557             }
2558             
2559             if (static_cast<unsigned>(argumentCountIncludingThis) < 1 + numArgs)
2560                 return false;
2561             
2562             insertChecks();
2563             
2564             Vector<Node*, 3> args;
2565             for (unsigned i = 0; i < numArgs; ++i)
2566                 args.append(get(virtualRegisterForArgument(1 + i, registerOffset)));
2567             
2568             Node* resultNode;
2569             if (numArgs + 1 <= 3) {
2570                 while (args.size() < 3)
2571                     args.append(nullptr);
2572                 resultNode = addToGraph(op, OpInfo(ArrayMode(Array::SelectUsingPredictions, action).asWord()), OpInfo(prediction), args[0], args[1], args[2]);
2573             } else {
2574                 for (Node* node : args)
2575                     addVarArgChild(node);
2576                 addVarArgChild(nullptr);
2577                 resultNode = addToGraph(Node::VarArg, op, OpInfo(ArrayMode(Array::SelectUsingPredictions, action).asWord()), OpInfo(prediction));
2578             }
2579             
2580             setResult(resultNode);
2581             return true;
2582         }
2583
2584         case ParseIntIntrinsic: {
2585             if (argumentCountIncludingThis < 2)
2586                 return false;
2587
2588             if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell) || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
2589                 return false;
2590
2591             insertChecks();
2592             VirtualRegister valueOperand = virtualRegisterForArgument(1, registerOffset);
2593             Node* parseInt;
2594             if (argumentCountIncludingThis == 2)
2595                 parseInt = addToGraph(ParseInt, OpInfo(), OpInfo(prediction), get(valueOperand));
2596             else {
2597                 ASSERT(argumentCountIncludingThis > 2);
2598                 VirtualRegister radixOperand = virtualRegisterForArgument(2, registerOffset);
2599                 parseInt = addToGraph(ParseInt, OpInfo(), OpInfo(prediction), get(valueOperand), get(radixOperand));
2600             }
2601             setResult(parseInt);
2602             return true;
2603         }
2604
2605         case CharCodeAtIntrinsic: {
2606             if (argumentCountIncludingThis < 2)
2607                 return false;
2608
2609             if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Uncountable) || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
2610                 return false;
2611
2612             insertChecks();
2613             VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset);
2614             VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset);
2615             Node* charCode = addToGraph(StringCharCodeAt, OpInfo(ArrayMode(Array::String, Array::Read).asWord()), get(thisOperand), get(indexOperand));
2616
2617             setResult(charCode);
2618             return true;
2619         }
2620
2621         case StringPrototypeCodePointAtIntrinsic: {
2622             if (!is64Bit())
2623                 return false;
2624
2625             if (argumentCountIncludingThis < 2)
2626                 return false;
2627
2628             if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Uncountable) || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
2629                 return false;
2630
2631             insertChecks();
2632             VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset);
2633             VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset);
2634             Node* result = addToGraph(StringCodePointAt, OpInfo(ArrayMode(Array::String, Array::Read).asWord()), get(thisOperand), get(indexOperand));
2635
2636             setResult(result);
2637             return true;
2638         }
2639
2640         case CharAtIntrinsic: {
2641             if (argumentCountIncludingThis < 2)
2642                 return false;
2643
2644             if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
2645                 return false;
2646
2647             // FIXME: String#charAt returns empty string when index is out-of-bounds, and this does not break the AI's claim.
2648             // Only FTL supports out-of-bounds version now. We should support out-of-bounds version even in DFG.
2649             // https://bugs.webkit.org/show_bug.cgi?id=201678
2650
2651             insertChecks();
2652             VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset);
2653             VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset);
2654             Node* charCode = addToGraph(StringCharAt, OpInfo(ArrayMode(Array::String, Array::Read).asWord()), get(thisOperand), get(indexOperand));
2655
2656             setResult(charCode);
2657             return true;
2658         }
2659         case Clz32Intrinsic: {
2660             insertChecks();
2661             if (argumentCountIncludingThis == 1)
2662                 setResult(addToGraph(JSConstant, OpInfo(m_graph.freeze(jsNumber(32)))));
2663             else {
2664                 Node* operand = get(virtualRegisterForArgument(1, registerOffset));
2665                 setResult(addToGraph(ArithClz32, operand));
2666             }
2667             return true;
2668         }
2669         case FromCharCodeIntrinsic: {
2670             if (argumentCountIncludingThis != 2)
2671                 return false;
2672
2673             insertChecks();
2674             VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset);
2675             Node* charCode = addToGraph(StringFromCharCode, get(indexOperand));
2676
2677             setResult(charCode);
2678
2679             return true;
2680         }
2681
2682         case RegExpExecIntrinsic: {
2683             if (argumentCountIncludingThis < 2)
2684                 return false;
2685             
2686             insertChecks();
2687             Node* regExpExec = addToGraph(RegExpExec, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)));
2688             setResult(regExpExec);
2689             
2690             return true;
2691         }
2692             
2693         case RegExpTestIntrinsic:
2694         case RegExpTestFastIntrinsic: {
2695             if (argumentCountIncludingThis < 2)
2696                 return false;
2697
2698             if (intrinsic == RegExpTestIntrinsic) {
2699                 // Don't inline intrinsic if we exited due to one of the primordial RegExp checks failing.
2700                 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell))
2701                     return false;
2702
2703                 JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
2704                 Structure* regExpStructure = globalObject->regExpStructure();
2705                 m_graph.registerStructure(regExpStructure);
2706                 ASSERT(regExpStructure->storedPrototype().isObject());
2707                 ASSERT(regExpStructure->storedPrototype().asCell()->classInfo(*m_vm) == RegExpPrototype::info());
2708
2709                 FrozenValue* regExpPrototypeObjectValue = m_graph.freeze(regExpStructure->storedPrototype());
2710                 Structure* regExpPrototypeStructure = regExpPrototypeObjectValue->structure();
2711
2712                 auto isRegExpPropertySame = [&] (JSValue primordialProperty, UniquedStringImpl* propertyUID) {
2713                     JSValue currentProperty;
2714                     if (!m_graph.getRegExpPrototypeProperty(regExpStructure->storedPrototypeObject(), regExpPrototypeStructure, propertyUID, currentProperty))
2715                         return false;
2716                     
2717                     return currentProperty == primordialProperty;
2718                 };
2719
2720                 // Check that RegExp.exec is still the primordial RegExp.prototype.exec
2721                 if (!isRegExpPropertySame(globalObject->regExpProtoExecFunction(), m_vm->propertyNames->exec.impl()))
2722                     return false;
2723
2724                 // Check that regExpObject is actually a RegExp object.
2725                 Node* regExpObject = get(virtualRegisterForArgument(0, registerOffset));
2726                 addToGraph(Check, Edge(regExpObject, RegExpObjectUse));
2727
2728                 // Check that regExpObject's exec is actually the primodial RegExp.prototype.exec.
2729                 UniquedStringImpl* execPropertyID = m_vm->propertyNames->exec.impl();
2730                 unsigned execIndex = m_graph.identifiers().ensure(execPropertyID);
2731                 Node* actualProperty = addToGraph(TryGetById, OpInfo(execIndex), OpInfo(SpecFunction), Edge(regExpObject, CellUse));
2732                 FrozenValue* regExpPrototypeExec = m_graph.freeze(globalObject->regExpProtoExecFunction());
2733                 addToGraph(CheckCell, OpInfo(regExpPrototypeExec), Edge(actualProperty, CellUse));
2734             }
2735
2736             insertChecks();
2737             Node* regExpObject = get(virtualRegisterForArgument(0, registerOffset));
2738             Node* regExpExec = addToGraph(RegExpTest, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), regExpObject, get(virtualRegisterForArgument(1, registerOffset)));
2739             setResult(regExpExec);
2740             
2741             return true;
2742         }
2743
2744         case RegExpMatchFastIntrinsic: {
2745             RELEASE_ASSERT(argumentCountIncludingThis == 2);
2746
2747             insertChecks();
2748             Node* regExpMatch = addToGraph(RegExpMatchFast, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)));
2749             setResult(regExpMatch);
2750             return true;
2751         }
2752
2753         case ObjectCreateIntrinsic: {
2754             if (argumentCountIncludingThis != 2)
2755                 return false;
2756
2757             insertChecks();
2758             setResult(addToGraph(ObjectCreate, get(virtualRegisterForArgument(1, registerOffset))));
2759             return true;
2760         }
2761
2762         case ObjectGetPrototypeOfIntrinsic: {
2763             if (argumentCountIncludingThis < 2)
2764                 return false;
2765
2766             insertChecks();
2767             setResult(addToGraph(GetPrototypeOf, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(1, registerOffset))));
2768             return true;
2769         }
2770
2771         case ObjectIsIntrinsic: {
2772             if (argumentCountIncludingThis < 3)
2773                 return false;
2774
2775             insertChecks();
2776             setResult(addToGraph(SameValue, get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset))));
2777             return true;
2778         }
2779
2780         case ObjectKeysIntrinsic: {
2781             if (argumentCountIncludingThis < 2)
2782                 return false;
2783
2784             insertChecks();
2785             setResult(addToGraph(ObjectKeys, get(virtualRegisterForArgument(1, registerOffset))));
2786             return true;
2787         }
2788
2789         case ReflectGetPrototypeOfIntrinsic: {
2790             if (argumentCountIncludingThis < 2)
2791                 return false;
2792
2793             insertChecks();
2794             setResult(addToGraph(GetPrototypeOf, OpInfo(0), OpInfo(prediction), Edge(get(virtualRegisterForArgument(1, registerOffset)), ObjectUse)));
2795             return true;
2796         }
2797
2798         case IsTypedArrayViewIntrinsic: {
2799             ASSERT(argumentCountIncludingThis == 2);
2800
2801             insertChecks();
2802             setResult(addToGraph(IsTypedArrayView, OpInfo(prediction), get(virtualRegisterForArgument(1, registerOffset))));
2803             return true;
2804         }
2805
2806         case StringPrototypeValueOfIntrinsic: {
2807             insertChecks();
2808             Node* value = get(virtualRegisterForArgument(0, registerOffset));
2809             setResult(addToGraph(StringValueOf, value));
2810             return true;
2811         }
2812
2813         case StringPrototypeReplaceIntrinsic: {
2814             if (argumentCountIncludingThis < 3)
2815                 return false;
2816
2817             // Don't inline intrinsic if we exited due to "search" not being a RegExp or String object.
2818             if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
2819                 return false;
2820
2821             // Don't inline intrinsic if we exited due to one of the primordial RegExp checks failing.
2822             if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell))
2823                 return false;
2824
2825             JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
2826             Structure* regExpStructure = globalObject->regExpStructure();
2827             m_graph.registerStructure(regExpStructure);
2828             ASSERT(regExpStructure->storedPrototype().isObject());
2829             ASSERT(regExpStructure->storedPrototype().asCell()->classInfo(*m_vm) == RegExpPrototype::info());
2830
2831             FrozenValue* regExpPrototypeObjectValue = m_graph.freeze(regExpStructure->storedPrototype());
2832             Structure* regExpPrototypeStructure = regExpPrototypeObjectValue->structure();
2833
2834             auto isRegExpPropertySame = [&] (JSValue primordialProperty, UniquedStringImpl* propertyUID) {
2835                 JSValue currentProperty;
2836                 if (!m_graph.getRegExpPrototypeProperty(regExpStructure->storedPrototypeObject(), regExpPrototypeStructure, propertyUID, currentProperty))
2837                     return false;
2838
2839                 return currentProperty == primordialProperty;
2840             };
2841
2842             // Check that searchRegExp.exec is still the primordial RegExp.prototype.exec
2843             if (!isRegExpPropertySame(globalObject->regExpProtoExecFunction(), m_vm->propertyNames->exec.impl()))
2844                 return false;
2845
2846             // Check that searchRegExp.global is still the primordial RegExp.prototype.global
2847             if (!isRegExpPropertySame(globalObject->regExpProtoGlobalGetter(), m_vm->propertyNames->global.impl()))
2848                 return false;
2849
2850             // Check that searchRegExp.unicode is still the primordial RegExp.prototype.unicode
2851             if (!isRegExpPropertySame(globalObject->regExpProtoUnicodeGetter(), m_vm->propertyNames->unicode.impl()))
2852                 return false;
2853
2854             // Check that searchRegExp[Symbol.match] is still the primordial RegExp.prototype[Symbol.replace]
2855             if (!isRegExpPropertySame(globalObject->regExpProtoSymbolReplaceFunction(), m_vm->propertyNames->replaceSymbol.impl()))
2856                 return false;
2857
2858             insertChecks();
2859
2860             Node* resultNode = addToGraph(StringReplace, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset)));
2861             setResult(resultNode);
2862             return true;
2863         }
2864             
2865         case StringPrototypeReplaceRegExpIntrinsic: {
2866             if (argumentCountIncludingThis < 3)
2867                 return false;
2868             
2869             insertChecks();
2870             Node* resultNode = addToGraph(StringReplaceRegExp, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset)));
2871             setResult(resultNode);
2872             return true;
2873         }
2874             
2875         case RoundIntrinsic:
2876         case FloorIntrinsic:
2877         case CeilIntrinsic:
2878         case TruncIntrinsic: {
2879             if (argumentCountIncludingThis == 1) {
2880                 insertChecks();
2881                 setResult(addToGraph(JSConstant, OpInfo(m_constantNaN)));
2882                 return true;
2883             }
2884             insertChecks();
2885             Node* operand = get(virtualRegisterForArgument(1, registerOffset));
2886             NodeType op;
2887             if (intrinsic == RoundIntrinsic)
2888                 op = ArithRound;
2889             else if (intrinsic == FloorIntrinsic)
2890                 op = ArithFloor;
2891             else if (intrinsic == CeilIntrinsic)
2892                 op = ArithCeil;
2893             else {
2894                 ASSERT(intrinsic == TruncIntrinsic);
2895                 op = ArithTrunc;
2896             }
2897             Node* roundNode = addToGraph(op, OpInfo(0), OpInfo(prediction), operand);
2898             setResult(roundNode);
2899             return true;
2900         }
2901         case IMulIntrinsic: {
2902             if (argumentCountIncludingThis < 3)
2903                 return false;
2904             insertChecks();
2905             VirtualRegister leftOperand = virtualRegisterForArgument(1, registerOffset);
2906             VirtualRegister rightOperand = virtualRegisterForArgument(2, registerOffset);
2907             Node* left = get(leftOperand);
2908             Node* right = get(rightOperand);
2909             setResult(addToGraph(ArithIMul, left, right));
2910             return true;
2911         }
2912
2913         case RandomIntrinsic: {
2914             insertChecks();
2915             setResult(addToGraph(ArithRandom));
2916             return true;
2917         }
2918             
2919         case DFGTrueIntrinsic: {
2920             insertChecks();
2921             setResult(jsConstant(jsBoolean(true)));
2922             return true;
2923         }
2924
2925         case FTLTrueIntrinsic: {
2926             insertChecks();
2927             setResult(jsConstant(jsBoolean(m_graph.m_plan.isFTL())));
2928             return true;
2929         }
2930             
2931         case OSRExitIntrinsic: {
2932             insertChecks();
2933             addToGraph(ForceOSRExit);
2934             setResult(addToGraph(JSConstant, OpInfo(m_constantUndefined)));
2935             return true;
2936         }
2937             
2938         case IsFinalTierIntrinsic: {
2939             insertChecks();
2940             setResult(jsConstant(jsBoolean(Options::useFTLJIT() ? m_graph.m_plan.isFTL() : true)));
2941             return true;
2942         }
2943             
2944         case SetInt32HeapPredictionIntrinsic: {
2945             insertChecks();
2946             for (int i = 1; i < argumentCountIncludingThis; ++i) {
2947                 Node* node = get(virtualRegisterForArgument(i, registerOffset));
2948                 if (node->hasHeapPrediction())
2949                     node->setHeapPrediction(SpecInt32Only);
2950             }
2951             setResult(addToGraph(JSConstant, OpInfo(m_constantUndefined)));
2952             return true;
2953         }
2954             
2955         case CheckInt32Intrinsic: {
2956             insertChecks();
2957             for (int i = 1; i < argumentCountIncludingThis; ++i) {
2958                 Node* node = get(virtualRegisterForArgument(i, registerOffset));
2959                 addToGraph(Phantom, Edge(node, Int32Use));
2960             }
2961             setResult(jsConstant(jsBoolean(true)));
2962             return true;
2963         }
2964             
2965         case FiatInt52Intrinsic: {
2966             if (argumentCountIncludingThis < 2)
2967                 return false;
2968             insertChecks();
2969             VirtualRegister operand = virtualRegisterForArgument(1, registerOffset);
2970             if (enableInt52())
2971                 setResult(addToGraph(FiatInt52, get(operand)));
2972             else
2973                 setResult(get(operand));
2974             return true;
2975         }
2976
2977         case JSMapGetIntrinsic: {
2978             if (argumentCountIncludingThis < 2)
2979                 return false;
2980
2981             insertChecks();
2982             Node* map = get(virtualRegisterForArgument(0, registerOffset));
2983             Node* key = get(virtualRegisterForArgument(1, registerOffset));
2984             Node* normalizedKey = addToGraph(NormalizeMapKey, key);
2985             Node* hash = addToGraph(MapHash, normalizedKey);
2986             Node* bucket = addToGraph(GetMapBucket, Edge(map, MapObjectUse), Edge(normalizedKey), Edge(hash));
2987             Node* resultNode = addToGraph(LoadValueFromMapBucket, OpInfo(BucketOwnerType::Map), OpInfo(prediction), bucket);
2988             setResult(resultNode);
2989             return true;
2990         }
2991
2992         case JSSetHasIntrinsic:
2993         case JSMapHasIntrinsic: {
2994             if (argumentCountIncludingThis < 2)
2995                 return false;
2996
2997             insertChecks();
2998             Node* mapOrSet = get(virtualRegisterForArgument(0, registerOffset));
2999             Node* key = get(virtualRegisterForArgument(1, registerOffset));
3000             Node* normalizedKey = addToGraph(NormalizeMapKey, key);
3001             Node* hash = addToGraph(MapHash, normalizedKey);
3002             UseKind useKind = intrinsic == JSSetHasIntrinsic ? SetObjectUse : MapObjectUse;
3003             Node* bucket = addToGraph(GetMapBucket, OpInfo(0), Edge(mapOrSet, useKind), Edge(normalizedKey), Edge(hash));
3004             JSCell* sentinel = nullptr;
3005             if (intrinsic == JSMapHasIntrinsic)
3006                 sentinel = m_vm->sentinelMapBucket();
3007             else
3008                 sentinel = m_vm->sentinelSetBucket();
3009
3010             FrozenValue* frozenPointer = m_graph.freeze(sentinel);
3011             Node* invertedResult = addToGraph(CompareEqPtr, OpInfo(frozenPointer), bucket);
3012             Node* resultNode = addToGraph(LogicalNot, invertedResult);
3013             setResult(resultNode);
3014             return true;
3015         }
3016
3017         case JSSetAddIntrinsic: {
3018             if (argumentCountIncludingThis < 2)
3019                 return false;
3020
3021             insertChecks();
3022             Node* base = get(virtualRegisterForArgument(0, registerOffset));
3023             Node* key = get(virtualRegisterForArgument(1, registerOffset));
3024             Node* normalizedKey = addToGraph(NormalizeMapKey, key);
3025             Node* hash = addToGraph(MapHash, normalizedKey);
3026             addToGraph(SetAdd, base, normalizedKey, hash);
3027             setResult(base);
3028             return true;
3029         }
3030
3031         case JSMapSetIntrinsic: {
3032             if (argumentCountIncludingThis < 3)
3033                 return false;
3034
3035             insertChecks();
3036             Node* base = get(virtualRegisterForArgument(0, registerOffset));
3037             Node* key = get(virtualRegisterForArgument(1, registerOffset));
3038             Node* value = get(virtualRegisterForArgument(2, registerOffset));
3039
3040             Node* normalizedKey = addToGraph(NormalizeMapKey, key);
3041             Node* hash = addToGraph(MapHash, normalizedKey);
3042
3043             addVarArgChild(base);
3044             addVarArgChild(normalizedKey);
3045             addVarArgChild(value);
3046             addVarArgChild(hash);
3047             addToGraph(Node::VarArg, MapSet, OpInfo(0), OpInfo(0));
3048             setResult(base);
3049             return true;
3050         }
3051
3052         case JSSetBucketHeadIntrinsic:
3053         case JSMapBucketHeadIntrinsic: {
3054             ASSERT(argumentCountIncludingThis == 2);
3055
3056             insertChecks();
3057             Node* map = get(virtualRegisterForArgument(1, registerOffset));
3058             UseKind useKind = intrinsic == JSSetBucketHeadIntrinsic ? SetObjectUse : MapObjectUse;
3059             Node* resultNode = addToGraph(GetMapBucketHead, Edge(map, useKind));
3060             setResult(resultNode);
3061             return true;
3062         }
3063
3064         case JSSetBucketNextIntrinsic:
3065         case JSMapBucketNextIntrinsic: {
3066             ASSERT(argumentCountIncludingThis == 2);
3067
3068             insertChecks();
3069             Node* bucket = get(virtualRegisterForArgument(1, registerOffset));
3070             BucketOwnerType type = intrinsic == JSSetBucketNextIntrinsic ? BucketOwnerType::Set : BucketOwnerType::Map;
3071             Node* resultNode = addToGraph(GetMapBucketNext, OpInfo(type), bucket);
3072             setResult(resultNode);
3073             return true;
3074         }
3075
3076         case JSSetBucketKeyIntrinsic:
3077         case JSMapBucketKeyIntrinsic: {
3078             ASSERT(argumentCountIncludingThis == 2);
3079
3080             insertChecks();
3081             Node* bucket = get(virtualRegisterForArgument(1, registerOffset));
3082             BucketOwnerType type = intrinsic == JSSetBucketKeyIntrinsic ? BucketOwnerType::Set : BucketOwnerType::Map;
3083             Node* resultNode = addToGraph(LoadKeyFromMapBucket, OpInfo(type), OpInfo(prediction), bucket);
3084             setResult(resultNode);
3085             return true;
3086         }
3087
3088         case JSMapBucketValueIntrinsic: {
3089             ASSERT(argumentCountIncludingThis == 2);
3090
3091             insertChecks();
3092             Node* bucket = get(virtualRegisterForArgument(1, registerOffset));
3093             Node* resultNode = addToGraph(LoadValueFromMapBucket, OpInfo(BucketOwnerType::Map), Op