2011-03-30 Zoltan Herczeg <zherczeg@inf.u-szeged.hu>
[WebKit.git] / Source / JavaScriptCore / dfg / DFGByteCodeParser.cpp
1 /*
2  * Copyright (C) 2011 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 "DFGAliasTracker.h"
32 #include "DFGScoreBoard.h"
33 #include "CodeBlock.h"
34
35 namespace JSC { namespace DFG {
36
37 // === ByteCodeParser ===
38 //
39 // This class is used to compile the dataflow graph from a CodeBlock.
40 class ByteCodeParser {
41 public:
42     ByteCodeParser(JSGlobalData* globalData, CodeBlock* codeBlock, Graph& graph)
43         : m_globalData(globalData)
44         , m_codeBlock(codeBlock)
45         , m_graph(graph)
46         , m_currentIndex(0)
47         , m_noArithmetic(true)
48         , m_constantUndefined(UINT_MAX)
49         , m_constant1(UINT_MAX)
50     {
51         unsigned numberOfConstants = codeBlock->numberOfConstantRegisters();
52         m_constantRecords.grow(numberOfConstants);
53
54         unsigned numberOfParameters = codeBlock->m_numParameters;
55         m_arguments.grow(numberOfParameters);
56         for (unsigned i = 0; i < numberOfParameters; ++i)
57             m_arguments[i] = NoNode;
58
59         unsigned numberOfRegisters = codeBlock->m_numCalleeRegisters;
60         m_calleeRegisters.grow(numberOfRegisters);
61         for (unsigned i = 0; i < numberOfRegisters; ++i)
62             m_calleeRegisters[i] = NoNode;
63     }
64
65     bool parse();
66
67 private:
68     // Get/Set the operands/result of a bytecode instruction.
69     NodeIndex get(int operand)
70     {
71         // Is this a constant?
72         if (operand >= FirstConstantRegisterIndex) {
73             unsigned constant = operand - FirstConstantRegisterIndex;
74             ASSERT(constant < m_constantRecords.size());
75             return getJSConstant(constant);
76         }
77
78         // Is this an argument?
79         if (operand < 0) {
80             unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize;
81             ASSERT(argument < m_arguments.size());
82             return getArgument(argument);
83         }
84
85         // Must be a local or temporary.
86         ASSERT((unsigned)operand < m_calleeRegisters.size());
87         return getRegister((unsigned)operand);
88     }
89     void set(int operand, NodeIndex value)
90     {
91         // Is this an argument?
92         if (operand < 0) {
93             unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize;
94             ASSERT(argument < m_arguments.size());
95             return setArgument(argument, value);
96         }
97
98         // Must be a local or temporary.
99         ASSERT((unsigned)operand < m_calleeRegisters.size());
100         return setRegister((unsigned)operand, value);
101     }
102
103     // Used in implementing get/set, above, where the operand is a local or temporary.
104     NodeIndex getRegister(unsigned operand)
105     {
106         NodeIndex index = m_calleeRegisters[operand];
107         if (index != NoNode)
108             return index;
109         // We have not yet seen a definition for this value in this block.
110         // For now, since we are only generating single block functions,
111         // this value must be undefined.
112         // For example:
113         //     function f() { var x; return x; }
114         return constantUndefined();
115     }
116     void setRegister(int operand, NodeIndex value)
117     {
118         m_calleeRegisters[operand] = value;
119     }
120
121     // Used in implementing get/set, above, where the operand is an argument.
122     NodeIndex getArgument(unsigned argument)
123     {
124         NodeIndex index = m_arguments[argument];
125         if (index != NoNode)
126             return index;
127         NodeIndex resultIndex = (NodeIndex)m_graph.size();
128         m_graph.append(Node(Argument, m_currentIndex, OpInfo(argument)));
129         return m_arguments[argument] = resultIndex;
130     }
131     void setArgument(int operand, NodeIndex value)
132     {
133         m_arguments[operand] = value;
134     }
135
136     // Get an operand, and perform a ToInt32/ToNumber conversion on it.
137     NodeIndex getToInt32(int operand)
138     {
139         // Avoid wastefully adding a JSConstant node to the graph, only to
140         // replace it with a Int32Constant (which is what would happen if
141         // we called 'toInt32(get(operand))' in this case).
142         if (operand >= FirstConstantRegisterIndex) {
143             JSValue v = m_codeBlock->getConstant(operand);
144             if (v.isInt32())
145                 return getInt32Constant(v.asInt32(), operand - FirstConstantRegisterIndex);
146         }
147         return toInt32(get(operand));
148     }
149     NodeIndex getToNumber(int operand)
150     {
151         // Avoid wastefully adding a JSConstant node to the graph, only to
152         // replace it with a DoubleConstant (which is what would happen if
153         // we called 'toNumber(get(operand))' in this case).
154         if (operand >= FirstConstantRegisterIndex) {
155             JSValue v = m_codeBlock->getConstant(operand);
156             if (v.isNumber())
157                 return getDoubleConstant(v.uncheckedGetNumber(), operand - FirstConstantRegisterIndex);
158         }
159         return toNumber(get(operand));
160     }
161
162     // Perform an ES5 ToInt32 operation - returns a node of type NodeResultInt32.
163     NodeIndex toInt32(NodeIndex index)
164     {
165         Node& node = m_graph[index];
166
167         if (node.hasInt32Result())
168             return index;
169
170         if (node.hasDoubleResult()) {
171             if (node.op == DoubleConstant)
172                 return getInt32Constant(JSC::toInt32(valueOfDoubleConstant(index)), node.constantNumber());
173             // 'NumberToInt32(Int32ToNumber(X))' == X, and 'NumberToInt32(UInt32ToNumber(X)) == X'
174             if (node.op == Int32ToNumber || node.op == UInt32ToNumber)
175                 return node.child1;
176
177             // We unique NumberToInt32 nodes in a map to prevent duplicate conversions.
178             pair<UnaryOpMap::iterator, bool> result = m_numberToInt32Nodes.add(index, NoNode);
179             // Either we added a new value, or the existing value in the map is non-zero.
180             ASSERT(result.second == (result.first->second == NoNode));
181             if (result.second)
182                 result.first->second = addToGraph(NumberToInt32, index);
183             return result.first->second;
184         }
185
186         // Check for numeric constants boxed as JSValues.
187         if (node.op == JSConstant) {
188             JSValue v = valueOfJSConstant(index);
189             if (v.isInt32())
190                 return getInt32Constant(v.asInt32(), node.constantNumber());
191             if (v.isNumber())
192                 return getInt32Constant(JSC::toInt32(v.uncheckedGetNumber()), node.constantNumber());
193         }
194
195         return addToGraph(ValueToInt32, index);
196     }
197
198     // Perform an ES5 ToNumber operation - returns a node of type NodeResultDouble.
199     NodeIndex toNumber(NodeIndex index)
200     {
201         Node& node = m_graph[index];
202
203         if (node.hasDoubleResult())
204             return index;
205
206         if (node.hasInt32Result()) {
207             if (node.op == Int32Constant)
208                 return getDoubleConstant(valueOfInt32Constant(index), node.constantNumber());
209
210             // We unique Int32ToNumber nodes in a map to prevent duplicate conversions.
211             pair<UnaryOpMap::iterator, bool> result = m_int32ToNumberNodes.add(index, NoNode);
212             // Either we added a new value, or the existing value in the map is non-zero.
213             ASSERT(result.second == (result.first->second == NoNode));
214             if (result.second)
215                 result.first->second = addToGraph(Int32ToNumber, index);
216             return result.first->second;
217         }
218
219         if (node.op == JSConstant) {
220             JSValue v = valueOfJSConstant(index);
221             if (v.isNumber())
222                 return getDoubleConstant(v.uncheckedGetNumber(), node.constantNumber());
223         }
224
225         return addToGraph(ValueToNumber, index);
226     }
227
228
229     // Used in implementing get, above, where the operand is a constant.
230     NodeIndex getInt32Constant(int32_t value, unsigned constant)
231     {
232         NodeIndex index = m_constantRecords[constant].asInt32;
233         if (index != NoNode)
234             return index;
235         NodeIndex resultIndex = (NodeIndex)m_graph.size();
236         m_graph.append(Node(Int32Constant, m_currentIndex, OpInfo(constant)));
237         m_graph[resultIndex].setInt32Constant(value);
238         m_constantRecords[constant].asInt32 = resultIndex;
239         return resultIndex;
240     }
241     NodeIndex getDoubleConstant(double value, unsigned constant)
242     {
243         NodeIndex index = m_constantRecords[constant].asNumeric;
244         if (index != NoNode)
245             return index;
246         NodeIndex resultIndex = (NodeIndex)m_graph.size();
247         m_graph.append(Node(DoubleConstant, m_currentIndex, OpInfo(constant)));
248         m_graph[resultIndex].setDoubleConstant(value);
249         m_constantRecords[constant].asNumeric = resultIndex;
250         return resultIndex;
251     }
252     NodeIndex getJSConstant(unsigned constant)
253     {
254         NodeIndex index = m_constantRecords[constant].asJSValue;
255         if (index != NoNode)
256             return index;
257
258         NodeIndex resultIndex = (NodeIndex)m_graph.size();
259         m_graph.append(Node(JSConstant, m_currentIndex, OpInfo(constant)));
260         m_constantRecords[constant].asJSValue = resultIndex;
261         return resultIndex;
262     }
263
264     // Helper functions to get/set the this value.
265     NodeIndex getThis()
266     {
267         return getArgument(0);
268     }
269     void setThis(NodeIndex value)
270     {
271         setArgument(0, value);
272     }
273
274     // Convenience methods for checking nodes for constants.
275     bool isInt32Constant(NodeIndex index)
276     {
277         return m_graph[index].op == Int32Constant;
278     }
279     bool isDoubleConstant(NodeIndex index)
280     {
281         return m_graph[index].op == DoubleConstant;
282     }
283     bool isJSConstant(NodeIndex index)
284     {
285         return m_graph[index].op == JSConstant;
286     }
287
288     // Convenience methods for getting constant values.
289     int32_t valueOfInt32Constant(NodeIndex index)
290     {
291         ASSERT(isInt32Constant(index));
292         return m_graph[index].int32Constant();
293     }
294     double valueOfDoubleConstant(NodeIndex index)
295     {
296         ASSERT(isDoubleConstant(index));
297         return m_graph[index].numericConstant();
298     }
299     JSValue valueOfJSConstant(NodeIndex index)
300     {
301         ASSERT(isJSConstant(index));
302         return m_codeBlock->getConstant(FirstConstantRegisterIndex + m_graph[index].constantNumber());
303     }
304
305     // This method returns a JSConstant with the value 'undefined'.
306     NodeIndex constantUndefined()
307     {
308         // Has m_constantUndefined been set up yet?
309         if (m_constantUndefined == UINT_MAX) {
310             // Search the constant pool for undefined, if we find it, we can just reuse this!
311             unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
312             for (m_constantUndefined = 0; m_constantUndefined < numberOfConstants; ++m_constantUndefined) {
313                 JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined);
314                 if (testMe.isUndefined())
315                     return getJSConstant(m_constantUndefined);
316             }
317
318             // Add undefined to the CodeBlock's constants, and add a corresponding slot in m_constantRecords.
319             ASSERT(m_constantRecords.size() == numberOfConstants);
320             m_codeBlock->addConstant(jsUndefined());
321             m_constantRecords.append(ConstantRecord());
322             ASSERT(m_constantRecords.size() == m_codeBlock->numberOfConstantRegisters());
323         }
324
325         // m_constantUndefined must refer to an entry in the CodeBlock's constant pool that has the value 'undefined'.
326         ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined).isUndefined());
327         return getJSConstant(m_constantUndefined);
328     }
329
330     // This method returns a DoubleConstant with the value 1.
331     NodeIndex one()
332     {
333         // Has m_constant1 been set up yet?
334         if (m_constant1 == UINT_MAX) {
335             // Search the constant pool for the value 1, if we find it, we can just reuse this!
336             unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
337             for (m_constant1 = 0; m_constant1 < numberOfConstants; ++m_constant1) {
338                 JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1);
339                 if (testMe.isInt32() && testMe.asInt32() == 1)
340                     return getDoubleConstant(1, m_constant1);
341             }
342
343             // Add the value 1 to the CodeBlock's constants, and add a corresponding slot in m_constantRecords.
344             ASSERT(m_constantRecords.size() == numberOfConstants);
345             m_codeBlock->addConstant(jsNumber(1));
346             m_constantRecords.append(ConstantRecord());
347             ASSERT(m_constantRecords.size() == m_codeBlock->numberOfConstantRegisters());
348         }
349
350         // m_constant1 must refer to an entry in the CodeBlock's constant pool that has the integer value 1.
351         ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).isInt32());
352         ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).asInt32() == 1);
353         return getDoubleConstant(1, m_constant1);
354     }
355
356
357     // These methods create a node and add it to the graph. If nodes of this type are
358     // 'mustGenerate' then the node  will implicitly be ref'ed to ensure generation.
359     NodeIndex addToGraph(NodeType op, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
360     {
361         NodeIndex resultIndex = (NodeIndex)m_graph.size();
362         m_graph.append(Node(op, m_currentIndex, child1, child2, child3));
363
364         if (op & NodeMustGenerate)
365             m_graph.ref(resultIndex);
366         return resultIndex;
367     }
368     NodeIndex addToGraph(NodeType op, OpInfo info, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
369     {
370         NodeIndex resultIndex = (NodeIndex)m_graph.size();
371         m_graph.append(Node(op, m_currentIndex, info, child1, child2, child3));
372
373         if (op & NodeMustGenerate)
374             m_graph.ref(resultIndex);
375         return resultIndex;
376     }
377
378     JSGlobalData* m_globalData;
379     CodeBlock* m_codeBlock;
380     Graph& m_graph;
381
382     // The bytecode index of the current instruction being generated.
383     unsigned m_currentIndex;
384
385     // FIXME: used to temporarily disable arithmetic, until we fix associated performance regressions.
386     bool m_noArithmetic;
387
388     // We use these values during code generation, and to avoid the need for
389     // special handling we make sure they are available as constants in the
390     // CodeBlock's constant pool. These variables are initialized to
391     // UINT_MAX, and lazily updated to hold an index into the CodeBlock's
392     // constant pool, as necessary.
393     unsigned m_constantUndefined;
394     unsigned m_constant1;
395
396     // A constant in the constant pool may be represented by more than one
397     // node in the graph, depending on the context in which it is being used.
398     struct ConstantRecord {
399         ConstantRecord()
400             : asInt32(NoNode)
401             , asNumeric(NoNode)
402             , asJSValue(NoNode)
403         {
404         }
405
406         NodeIndex asInt32;
407         NodeIndex asNumeric;
408         NodeIndex asJSValue;
409     };
410     Vector <ConstantRecord, 32> m_constantRecords;
411
412     // Track the index of the node whose result is the current value for every
413     // register value in the bytecode - argument, local, and temporary.
414     Vector <NodeIndex, 32> m_arguments;
415     Vector <NodeIndex, 32> m_calleeRegisters;
416
417     // These maps are used to unique ToNumber and ToInt32 operations.
418     typedef HashMap<NodeIndex, NodeIndex> UnaryOpMap;
419     UnaryOpMap m_int32ToNumberNodes;
420     UnaryOpMap m_numberToInt32Nodes;
421 };
422
423 #define NEXT_OPCODE(name) \
424     m_currentIndex += OPCODE_LENGTH(name); \
425     continue;
426
427 bool ByteCodeParser::parse()
428 {
429     AliasTracker aliases(m_graph);
430
431     Interpreter* interpreter = m_globalData->interpreter;
432     Instruction* instructionsBegin = m_codeBlock->instructions().begin();
433     while (true) {
434         // Switch on the current bytecode opcode.
435         Instruction* currentInstruction = instructionsBegin + m_currentIndex;
436         switch (interpreter->getOpcodeID(currentInstruction->u.opcode)) {
437
438         // === Function entry opcodes ===
439
440         case op_enter:
441             // This is a no-op for now - may need to initialize locals, if
442             // DCE analysis cannot determine that the values are never read.
443             NEXT_OPCODE(op_enter);
444
445         case op_convert_this: {
446             NodeIndex op1 = getThis();
447             setThis(addToGraph(ConvertThis, op1));
448             NEXT_OPCODE(op_convert_this);
449         }
450
451         // === Bitwise operations ===
452
453         case op_bitand: {
454             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
455             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
456             set(currentInstruction[1].u.operand, addToGraph(BitAnd, op1, op2));
457             NEXT_OPCODE(op_bitand);
458         }
459
460         case op_bitor: {
461             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
462             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
463             set(currentInstruction[1].u.operand, addToGraph(BitOr, op1, op2));
464             NEXT_OPCODE(op_bitor);
465         }
466
467         case op_bitxor: {
468             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
469             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
470             set(currentInstruction[1].u.operand, addToGraph(BitXor, op1, op2));
471             NEXT_OPCODE(op_bitxor);
472         }
473
474         case op_rshift: {
475             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
476             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
477             NodeIndex result;
478             // Optimize out shifts by zero.
479             if (isInt32Constant(op2) && !(valueOfInt32Constant(op2) & 0x1f))
480                 result = op1;
481             else
482                 result = addToGraph(BitRShift, op1, op2);
483             set(currentInstruction[1].u.operand, result);
484             NEXT_OPCODE(op_rshift);
485         }
486
487         case op_lshift: {
488             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
489             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
490             NodeIndex result;
491             // Optimize out shifts by zero.
492             if (isInt32Constant(op2) && !(valueOfInt32Constant(op2) & 0x1f))
493                 result = op1;
494             else
495                 result = addToGraph(BitLShift, op1, op2);
496             set(currentInstruction[1].u.operand, result);
497             NEXT_OPCODE(op_lshift);
498         }
499
500         case op_urshift: {
501             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
502             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
503             NodeIndex result;
504             // The result of a zero-extending right shift is treated as an unsigned value.
505             // This means that if the top bit is set, the result is not in the int32 range,
506             // and as such must be stored as a double. If the shift amount is a constant,
507             // we may be able to optimize.
508             if (isInt32Constant(op2)) {
509                 // If we know we are shifting by a non-zero amount, then since the operation
510                 // zero fills we know the top bit of the result must be zero, and as such the
511                 // result must be within the int32 range. Conversely, if this is a shift by
512                 // zero, then the result may be changed by the conversion to unsigned, but it
513                 // is not necessary to perform the shift!
514                 if (valueOfInt32Constant(op2) & 0x1f)
515                     result = addToGraph(BitURShift, op1, op2);
516                 else
517                     result = addToGraph(UInt32ToNumber, op1);
518             }  else {
519                 // Cannot optimize at this stage; shift & potentially rebox as a double.
520                 result = addToGraph(BitURShift, op1, op2);
521                 result = addToGraph(UInt32ToNumber, result);
522             }
523             set(currentInstruction[1].u.operand, result);
524             NEXT_OPCODE(op_urshift);
525         }
526
527         // === Increment/Decrement opcodes ===
528
529         case op_pre_inc: {
530             unsigned srcDst = currentInstruction[1].u.operand;
531             NodeIndex op = getToNumber(srcDst);
532             set(srcDst, addToGraph(ArithAdd, op, one()));
533             NEXT_OPCODE(op_pre_inc);
534         }
535
536         case op_post_inc: {
537             unsigned result = currentInstruction[1].u.operand;
538             unsigned srcDst = currentInstruction[2].u.operand;
539             NodeIndex op = getToNumber(srcDst);
540             set(result, op);
541             set(srcDst, addToGraph(ArithAdd, op, one()));
542             NEXT_OPCODE(op_post_inc);
543         }
544
545         case op_pre_dec: {
546             unsigned srcDst = currentInstruction[1].u.operand;
547             NodeIndex op = getToNumber(srcDst);
548             set(srcDst, addToGraph(ArithSub, op, one()));
549             NEXT_OPCODE(op_pre_dec);
550         }
551
552         case op_post_dec: {
553             unsigned result = currentInstruction[1].u.operand;
554             unsigned srcDst = currentInstruction[2].u.operand;
555             NodeIndex op = getToNumber(srcDst);
556             set(result, op);
557             set(srcDst, addToGraph(ArithSub, op, one()));
558             NEXT_OPCODE(op_post_dec);
559         }
560
561         // === Arithmetic operations ===
562
563         case op_add: {
564             m_noArithmetic = false;
565             NodeIndex op1 = get(currentInstruction[2].u.operand);
566             NodeIndex op2 = get(currentInstruction[3].u.operand);
567             // If both operands can statically be determined to the numbers, then this is an arithmetic add.
568             // Otherwise, we must assume this may be performing a concatenation to a string.
569             if (m_graph[op1].hasNumericResult() && m_graph[op2].hasNumericResult())
570                 set(currentInstruction[1].u.operand, addToGraph(ArithAdd, toNumber(op1), toNumber(op2)));
571             else
572                 set(currentInstruction[1].u.operand, addToGraph(ValueAdd, op1, op2));
573             NEXT_OPCODE(op_add);
574         }
575
576         case op_sub: {
577             m_noArithmetic = false;
578             NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
579             NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
580             set(currentInstruction[1].u.operand, addToGraph(ArithSub, op1, op2));
581             NEXT_OPCODE(op_sub);
582         }
583
584         case op_mul: {
585             m_noArithmetic = false;
586             NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
587             NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
588             set(currentInstruction[1].u.operand, addToGraph(ArithMul, op1, op2));
589             NEXT_OPCODE(op_mul);
590         }
591
592         case op_mod: {
593             m_noArithmetic = false;
594             NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
595             NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
596             set(currentInstruction[1].u.operand, addToGraph(ArithMod, op1, op2));
597             NEXT_OPCODE(op_mod);
598         }
599
600         case op_div: {
601             m_noArithmetic = false;
602             NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
603             NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
604             set(currentInstruction[1].u.operand, addToGraph(ArithDiv, op1, op2));
605             NEXT_OPCODE(op_div);
606         }
607
608         // === Misc operations ===
609
610         case op_mov: {
611             NodeIndex op = get(currentInstruction[2].u.operand);
612             set(currentInstruction[1].u.operand, op);
613             NEXT_OPCODE(op_mov);
614         }
615
616         // === Property access operations ===
617
618         case op_get_by_val: {
619             NodeIndex base = get(currentInstruction[2].u.operand);
620             NodeIndex property = get(currentInstruction[3].u.operand);
621
622             NodeIndex getByVal = addToGraph(GetByVal, base, property, aliases.lookupGetByVal(base, property));
623             set(currentInstruction[1].u.operand, getByVal);
624             aliases.recordGetByVal(getByVal);
625
626             NEXT_OPCODE(op_get_by_val);
627         };
628
629         case op_put_by_val: {
630             NodeIndex base = get(currentInstruction[1].u.operand);
631             NodeIndex property = get(currentInstruction[2].u.operand);
632             NodeIndex value = get(currentInstruction[3].u.operand);
633
634             NodeIndex aliasedGet = aliases.lookupGetByVal(base, property);
635             NodeIndex putByVal = addToGraph(aliasedGet != NoNode ? PutByValAlias : PutByVal, base, property, value);
636             aliases.recordPutByVal(putByVal);
637
638             NEXT_OPCODE(op_put_by_val);
639         };
640
641         case op_get_by_id: {
642             NodeIndex base = get(currentInstruction[2].u.operand);
643             unsigned identifier = currentInstruction[3].u.operand;
644
645             NodeIndex getById = addToGraph(GetById, OpInfo(identifier), base);
646             set(currentInstruction[1].u.operand, getById);
647             aliases.recordGetById(getById);
648
649             NEXT_OPCODE(op_get_by_id);
650         }
651
652         case op_put_by_id: {
653             NodeIndex value = get(currentInstruction[3].u.operand);
654             NodeIndex base = get(currentInstruction[1].u.operand);
655             unsigned identifier = currentInstruction[2].u.operand;
656             bool direct = currentInstruction[8].u.operand;
657
658             if (direct) {
659                 NodeIndex putByIdDirect = addToGraph(PutByIdDirect, OpInfo(identifier), base, value);
660                 aliases.recordPutByIdDirect(putByIdDirect);
661             } else {
662                 NodeIndex putById = addToGraph(PutById, OpInfo(identifier), base, value);
663                 aliases.recordPutById(putById);
664             }
665
666             NEXT_OPCODE(op_put_by_id);
667         }
668
669         case op_get_global_var: {
670             NodeIndex getGlobalVar = addToGraph(GetGlobalVar, OpInfo(currentInstruction[2].u.operand));
671             set(currentInstruction[1].u.operand, getGlobalVar);
672             NEXT_OPCODE(op_get_global_var);
673         }
674
675         case op_put_global_var: {
676             NodeIndex value = get(currentInstruction[2].u.operand);
677             addToGraph(PutGlobalVar, OpInfo(currentInstruction[1].u.operand), value);
678             NEXT_OPCODE(op_put_global_var);
679         }
680
681         // === Block terminators. ===
682
683         case op_ret: {
684             addToGraph(Return, get(currentInstruction[1].u.operand));
685             m_currentIndex += OPCODE_LENGTH(op_ret);
686 #if ENABLE(DFG_JIT_RESTRICTIONS)
687             // FIXME: temporarily disabling the DFG JIT for functions containing arithmetic.
688             return m_noArithmetic;
689 #else
690             return true;
691 #endif
692         }
693
694         default:
695             // parse failed!
696             return false;
697         }
698     }
699 }
700
701 bool parse(Graph& graph, JSGlobalData* globalData, CodeBlock* codeBlock)
702 {
703     // Call ByteCodeParser::parse to build the dataflow for the basic block at 'startIndex'.
704     ByteCodeParser state(globalData, codeBlock, graph);
705     if (!state.parse())
706         return false;
707
708     // Assign VirtualRegisters.
709     ScoreBoard scoreBoard(graph);
710     Node* nodes = graph.begin();
711     size_t size = graph.size();
712     for (size_t i = 0; i < size; ++i) {
713         Node& node = nodes[i];
714         if (node.refCount) {
715             // First, call use on all of the current node's children, then
716             // allocate a VirtualRegister for this node. We do so in this
717             // order so that if a child is on its last use, and a
718             // VirtualRegister is freed, then it may be reused for node.
719             scoreBoard.use(node.child1);
720             scoreBoard.use(node.child2);
721             scoreBoard.use(node.child3);
722             node.virtualRegister = scoreBoard.allocate();
723             // 'mustGenerate' nodes have their useCount artificially elevated,
724             // call use now to account for this.
725             if (node.mustGenerate())
726                 scoreBoard.use(i);
727         }
728     }
729
730     // 'm_numCalleeRegisters' is the number of locals and temporaries allocated
731     // for the function (and checked for on entry). Since we perform a new and
732     // different allocation of temporaries, more registers may now be required.
733     if ((unsigned)codeBlock->m_numCalleeRegisters < scoreBoard.allocatedCount())
734         codeBlock->m_numCalleeRegisters = scoreBoard.allocatedCount();
735
736 #if DFG_DEBUG_VERBOSE
737     graph.dump(codeBlock);
738 #endif
739     return true;
740 }
741
742 } } // namespace JSC::DFG
743
744 #endif