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