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