]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGByteCodeParser.cpp
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / 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 #if ENABLE(DFG_JIT_RESTRICTIONS)
38 // FIXME: Temporarily disable arithmetic, until we fix associated performance regressions.
39 #define ARITHMETIC_OP() m_parseFailed = true
40 #else
41 #define ARITHMETIC_OP() ((void)0)
42 #endif
43
44 // === ByteCodeParser ===
45 //
46 // This class is used to compile the dataflow graph from a CodeBlock.
47 class ByteCodeParser {
48 public:
49 ByteCodeParser(JSGlobalData* globalData, CodeBlock* codeBlock, Graph& graph)
50 : m_globalData(globalData)
51 , m_codeBlock(codeBlock)
52 , m_graph(graph)
53 , m_currentIndex(0)
54 , m_parseFailed(false)
55 , m_constantUndefined(UINT_MAX)
56 , m_constantNull(UINT_MAX)
57 , m_constant1(UINT_MAX)
58 , m_constants(codeBlock->numberOfConstantRegisters())
59 , m_numArguments(codeBlock->m_numParameters)
60 , m_numLocals(codeBlock->m_numCalleeRegisters)
61 , m_preservedVars(codeBlock->m_numVars)
62 {
63 }
64
65 // Parse a full CodeBlock of bytecode.
66 bool parse();
67
68 private:
69 // Parse a single basic block of bytecode instructions.
70 bool parseBlock(unsigned limit);
71 // Setup predecessor links in the graph's BasicBlocks.
72 void setupPredecessors();
73 // Link GetLocal & SetLocal nodes, to ensure live values are generated.
74 enum PhiStackType {
75 LocalPhiStack,
76 ArgumentPhiStack
77 };
78 template<PhiStackType stackType>
79 void processPhiStack();
80 // Add spill locations to nodes.
81 void allocateVirtualRegisters();
82
83 // Get/Set the operands/result of a bytecode instruction.
84 NodeIndex get(int operand)
85 {
86 // Is this a constant?
87 if (operand >= FirstConstantRegisterIndex) {
88 unsigned constant = operand - FirstConstantRegisterIndex;
89 ASSERT(constant < m_constants.size());
90 return getJSConstant(constant);
91 }
92
93 // Is this an argument?
94 if (operandIsArgument(operand))
95 return getArgument(operand);
96
97 // Must be a local.
98 return getLocal((unsigned)operand);
99 }
100 void set(int operand, NodeIndex value, PredictedType prediction = PredictNone)
101 {
102 m_graph.predict(operand, prediction);
103
104 // Is this an argument?
105 if (operandIsArgument(operand)) {
106 setArgument(operand, value);
107 return;
108 }
109
110 // Must be a local.
111 setLocal((unsigned)operand, value);
112 }
113
114 // Used in implementing get/set, above, where the operand is a local variable.
115 NodeIndex getLocal(unsigned operand)
116 {
117 NodeIndex nodeIndex = m_currentBlock->m_locals[operand].value;
118
119 if (nodeIndex != NoNode) {
120 Node& node = m_graph[nodeIndex];
121 if (node.op == GetLocal)
122 return nodeIndex;
123 ASSERT(node.op == SetLocal);
124 return node.child1;
125 }
126
127 // Check for reads of temporaries from prior blocks,
128 // expand m_preservedVars to cover these.
129 m_preservedVars = std::max(m_preservedVars, operand + 1);
130
131 NodeIndex phi = addToGraph(Phi);
132 m_localPhiStack.append(PhiStackEntry(m_currentBlock, phi, operand));
133 nodeIndex = addToGraph(GetLocal, OpInfo(operand), phi);
134 m_currentBlock->m_locals[operand].value = nodeIndex;
135 return nodeIndex;
136 }
137 void setLocal(unsigned operand, NodeIndex value)
138 {
139 m_currentBlock->m_locals[operand].value = addToGraph(SetLocal, OpInfo(operand), value);
140 }
141
142 // Used in implementing get/set, above, where the operand is an argument.
143 NodeIndex getArgument(unsigned operand)
144 {
145 unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize;
146 ASSERT(argument < m_numArguments);
147
148 NodeIndex nodeIndex = m_currentBlock->m_arguments[argument].value;
149
150 if (nodeIndex != NoNode) {
151 Node& node = m_graph[nodeIndex];
152 if (node.op == GetLocal)
153 return nodeIndex;
154 ASSERT(node.op == SetLocal);
155 return node.child1;
156 }
157
158 NodeIndex phi = addToGraph(Phi);
159 m_argumentPhiStack.append(PhiStackEntry(m_currentBlock, phi, argument));
160 nodeIndex = addToGraph(GetLocal, OpInfo(operand), phi);
161 m_currentBlock->m_arguments[argument].value = nodeIndex;
162 return nodeIndex;
163 }
164 void setArgument(int operand, NodeIndex value)
165 {
166 unsigned argument = operand + m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize;
167 ASSERT(argument < m_numArguments);
168
169 m_currentBlock->m_arguments[argument].value = addToGraph(SetLocal, OpInfo(operand), value);
170 }
171
172 // Get an operand, and perform a ToInt32/ToNumber conversion on it.
173 NodeIndex getToInt32(int operand)
174 {
175 // Avoid wastefully adding a JSConstant node to the graph, only to
176 // replace it with a Int32Constant (which is what would happen if
177 // we called 'toInt32(get(operand))' in this case).
178 if (operand >= FirstConstantRegisterIndex) {
179 JSValue v = m_codeBlock->getConstant(operand);
180 if (v.isInt32())
181 return getInt32Constant(v.asInt32(), operand - FirstConstantRegisterIndex);
182 }
183 return toInt32(get(operand));
184 }
185 NodeIndex getToNumber(int operand)
186 {
187 // Avoid wastefully adding a JSConstant node to the graph, only to
188 // replace it with a DoubleConstant (which is what would happen if
189 // we called 'toNumber(get(operand))' in this case).
190 if (operand >= FirstConstantRegisterIndex) {
191 JSValue v = m_codeBlock->getConstant(operand);
192 if (v.isNumber())
193 return getDoubleConstant(v.uncheckedGetNumber(), operand - FirstConstantRegisterIndex);
194 }
195 return toNumber(get(operand));
196 }
197
198 // Perform an ES5 ToInt32 operation - returns a node of type NodeResultInt32.
199 NodeIndex toInt32(NodeIndex index)
200 {
201 Node& node = m_graph[index];
202
203 if (node.hasInt32Result())
204 return index;
205
206 if (node.hasDoubleResult()) {
207 if (node.op == DoubleConstant)
208 return getInt32Constant(JSC::toInt32(valueOfDoubleConstant(index)), node.constantNumber());
209 // 'NumberToInt32(Int32ToNumber(X))' == X, and 'NumberToInt32(UInt32ToNumber(X)) == X'
210 if (node.op == Int32ToNumber || node.op == UInt32ToNumber)
211 return node.child1;
212
213 // We unique NumberToInt32 nodes in a map to prevent duplicate conversions.
214 pair<UnaryOpMap::iterator, bool> result = m_numberToInt32Nodes.add(index, NoNode);
215 // Either we added a new value, or the existing value in the map is non-zero.
216 ASSERT(result.second == (result.first->second == NoNode));
217 if (result.second)
218 result.first->second = addToGraph(NumberToInt32, index);
219 return result.first->second;
220 }
221
222 // Check for numeric constants boxed as JSValues.
223 if (node.op == JSConstant) {
224 JSValue v = valueOfJSConstant(index);
225 if (v.isInt32())
226 return getInt32Constant(v.asInt32(), node.constantNumber());
227 if (v.isNumber())
228 return getInt32Constant(JSC::toInt32(v.uncheckedGetNumber()), node.constantNumber());
229 }
230
231 return addToGraph(ValueToInt32, index);
232 }
233
234 // Perform an ES5 ToNumber operation - returns a node of type NodeResultDouble.
235 NodeIndex toNumber(NodeIndex index)
236 {
237 Node& node = m_graph[index];
238
239 if (node.hasDoubleResult())
240 return index;
241
242 if (node.hasInt32Result()) {
243 if (node.op == Int32Constant)
244 return getDoubleConstant(valueOfInt32Constant(index), node.constantNumber());
245
246 // We unique Int32ToNumber nodes in a map to prevent duplicate conversions.
247 pair<UnaryOpMap::iterator, bool> result = m_int32ToNumberNodes.add(index, NoNode);
248 // Either we added a new value, or the existing value in the map is non-zero.
249 ASSERT(result.second == (result.first->second == NoNode));
250 if (result.second)
251 result.first->second = addToGraph(Int32ToNumber, index);
252 return result.first->second;
253 }
254
255 if (node.op == JSConstant) {
256 JSValue v = valueOfJSConstant(index);
257 if (v.isNumber())
258 return getDoubleConstant(v.uncheckedGetNumber(), node.constantNumber());
259 }
260
261 return addToGraph(ValueToNumber, index);
262 }
263
264
265 // Used in implementing get, above, where the operand is a constant.
266 NodeIndex getInt32Constant(int32_t value, unsigned constant)
267 {
268 NodeIndex index = m_constants[constant].asInt32;
269 if (index != NoNode)
270 return index;
271 NodeIndex resultIndex = addToGraph(Int32Constant, OpInfo(constant));
272 m_graph[resultIndex].setInt32Constant(value);
273 m_constants[constant].asInt32 = resultIndex;
274 return resultIndex;
275 }
276 NodeIndex getDoubleConstant(double value, unsigned constant)
277 {
278 NodeIndex index = m_constants[constant].asNumeric;
279 if (index != NoNode)
280 return index;
281 NodeIndex resultIndex = addToGraph(DoubleConstant, OpInfo(constant));
282 m_graph[resultIndex].setDoubleConstant(value);
283 m_constants[constant].asNumeric = resultIndex;
284 return resultIndex;
285 }
286 NodeIndex getJSConstant(unsigned constant)
287 {
288 NodeIndex index = m_constants[constant].asJSValue;
289 if (index != NoNode)
290 return index;
291
292 NodeIndex resultIndex = addToGraph(JSConstant, OpInfo(constant));
293 m_constants[constant].asJSValue = resultIndex;
294 return resultIndex;
295 }
296
297 // Helper functions to get/set the this value.
298 NodeIndex getThis()
299 {
300 return getArgument(m_codeBlock->thisRegister());
301 }
302 void setThis(NodeIndex value)
303 {
304 setArgument(m_codeBlock->thisRegister(), value);
305 }
306
307 // Convenience methods for checking nodes for constants.
308 bool isInt32Constant(NodeIndex index)
309 {
310 return m_graph[index].op == Int32Constant;
311 }
312 bool isDoubleConstant(NodeIndex index)
313 {
314 return m_graph[index].op == DoubleConstant;
315 }
316 bool isJSConstant(NodeIndex index)
317 {
318 return m_graph[index].op == JSConstant;
319 }
320
321 // Convenience methods for getting constant values.
322 int32_t valueOfInt32Constant(NodeIndex index)
323 {
324 ASSERT(isInt32Constant(index));
325 return m_graph[index].int32Constant();
326 }
327 double valueOfDoubleConstant(NodeIndex index)
328 {
329 ASSERT(isDoubleConstant(index));
330 return m_graph[index].numericConstant();
331 }
332 JSValue valueOfJSConstant(NodeIndex index)
333 {
334 ASSERT(isJSConstant(index));
335 return m_codeBlock->getConstant(FirstConstantRegisterIndex + m_graph[index].constantNumber());
336 }
337
338 // This method returns a JSConstant with the value 'undefined'.
339 NodeIndex constantUndefined()
340 {
341 // Has m_constantUndefined been set up yet?
342 if (m_constantUndefined == UINT_MAX) {
343 // Search the constant pool for undefined, if we find it, we can just reuse this!
344 unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
345 for (m_constantUndefined = 0; m_constantUndefined < numberOfConstants; ++m_constantUndefined) {
346 JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined);
347 if (testMe.isUndefined())
348 return getJSConstant(m_constantUndefined);
349 }
350
351 // Add undefined to the CodeBlock's constants, and add a corresponding slot in m_constants.
352 ASSERT(m_constants.size() == numberOfConstants);
353 m_codeBlock->addConstant(jsUndefined());
354 m_constants.append(ConstantRecord());
355 ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
356 }
357
358 // m_constantUndefined must refer to an entry in the CodeBlock's constant pool that has the value 'undefined'.
359 ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined).isUndefined());
360 return getJSConstant(m_constantUndefined);
361 }
362
363 // This method returns a JSConstant with the value 'null'.
364 NodeIndex constantNull()
365 {
366 // Has m_constantNull been set up yet?
367 if (m_constantNull == UINT_MAX) {
368 // Search the constant pool for null, if we find it, we can just reuse this!
369 unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
370 for (m_constantNull = 0; m_constantNull < numberOfConstants; ++m_constantNull) {
371 JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull);
372 if (testMe.isNull())
373 return getJSConstant(m_constantNull);
374 }
375
376 // Add null to the CodeBlock's constants, and add a corresponding slot in m_constants.
377 ASSERT(m_constants.size() == numberOfConstants);
378 m_codeBlock->addConstant(jsNull());
379 m_constants.append(ConstantRecord());
380 ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
381 }
382
383 // m_constantNull must refer to an entry in the CodeBlock's constant pool that has the value 'null'.
384 ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull).isNull());
385 return getJSConstant(m_constantNull);
386 }
387
388 // This method returns a DoubleConstant with the value 1.
389 NodeIndex one()
390 {
391 // Has m_constant1 been set up yet?
392 if (m_constant1 == UINT_MAX) {
393 // Search the constant pool for the value 1, if we find it, we can just reuse this!
394 unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
395 for (m_constant1 = 0; m_constant1 < numberOfConstants; ++m_constant1) {
396 JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1);
397 if (testMe.isInt32() && testMe.asInt32() == 1)
398 return getDoubleConstant(1, m_constant1);
399 }
400
401 // Add the value 1 to the CodeBlock's constants, and add a corresponding slot in m_constants.
402 ASSERT(m_constants.size() == numberOfConstants);
403 m_codeBlock->addConstant(jsNumber(1));
404 m_constants.append(ConstantRecord());
405 ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
406 }
407
408 // m_constant1 must refer to an entry in the CodeBlock's constant pool that has the integer value 1.
409 ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).isInt32());
410 ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).asInt32() == 1);
411 return getDoubleConstant(1, m_constant1);
412 }
413
414
415 // These methods create a node and add it to the graph. If nodes of this type are
416 // 'mustGenerate' then the node will implicitly be ref'ed to ensure generation.
417 NodeIndex addToGraph(NodeType op, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
418 {
419 NodeIndex resultIndex = (NodeIndex)m_graph.size();
420 m_graph.append(Node(op, m_currentIndex, child1, child2, child3));
421
422 if (op & NodeMustGenerate)
423 m_graph.ref(resultIndex);
424 return resultIndex;
425 }
426 NodeIndex addToGraph(NodeType op, OpInfo info, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
427 {
428 NodeIndex resultIndex = (NodeIndex)m_graph.size();
429 m_graph.append(Node(op, m_currentIndex, info, child1, child2, child3));
430
431 if (op & NodeMustGenerate)
432 m_graph.ref(resultIndex);
433 return resultIndex;
434 }
435 NodeIndex addToGraph(NodeType op, OpInfo info1, OpInfo info2, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
436 {
437 NodeIndex resultIndex = (NodeIndex)m_graph.size();
438 m_graph.append(Node(op, m_currentIndex, info1, info2, child1, child2, child3));
439
440 if (op & NodeMustGenerate)
441 m_graph.ref(resultIndex);
442 return resultIndex;
443 }
444
445 void predictArray(NodeIndex nodeIndex)
446 {
447 Node* nodePtr = &m_graph[nodeIndex];
448
449 if (nodePtr->op == GetLocal)
450 m_graph.predict(nodePtr->local(), PredictArray);
451 }
452
453 void predictInt32(NodeIndex nodeIndex)
454 {
455 Node* nodePtr = &m_graph[nodeIndex];
456
457 if (nodePtr->op == ValueToNumber)
458 nodePtr = &m_graph[nodePtr->child1];
459
460 if (nodePtr->op == ValueToInt32)
461 nodePtr = &m_graph[nodePtr->child1];
462
463 if (nodePtr->op == NumberToInt32)
464 nodePtr = &m_graph[nodePtr->child1];
465
466 if (nodePtr->op == GetLocal)
467 m_graph.predict(nodePtr->local(), PredictInt32);
468 }
469
470 JSGlobalData* m_globalData;
471 CodeBlock* m_codeBlock;
472 Graph& m_graph;
473
474 // The current block being generated.
475 BasicBlock* m_currentBlock;
476 // The bytecode index of the current instruction being generated.
477 unsigned m_currentIndex;
478
479 // Record failures due to unimplemented functionality or regressions.
480 bool m_parseFailed;
481
482 // We use these values during code generation, and to avoid the need for
483 // special handling we make sure they are available as constants in the
484 // CodeBlock's constant pool. These variables are initialized to
485 // UINT_MAX, and lazily updated to hold an index into the CodeBlock's
486 // constant pool, as necessary.
487 unsigned m_constantUndefined;
488 unsigned m_constantNull;
489 unsigned m_constant1;
490
491 // A constant in the constant pool may be represented by more than one
492 // node in the graph, depending on the context in which it is being used.
493 struct ConstantRecord {
494 ConstantRecord()
495 : asInt32(NoNode)
496 , asNumeric(NoNode)
497 , asJSValue(NoNode)
498 {
499 }
500
501 NodeIndex asInt32;
502 NodeIndex asNumeric;
503 NodeIndex asJSValue;
504 };
505
506 // Track the index of the node whose result is the current value for every
507 // register value in the bytecode - argument, local, and temporary.
508 Vector<ConstantRecord, 16> m_constants;
509
510 // The number of arguments passed to the function.
511 unsigned m_numArguments;
512 // The number of locals (vars + temporaries) used in the function.
513 unsigned m_numLocals;
514 // The number of registers we need to preserve across BasicBlock boundaries;
515 // typically equal to the number vars, but we expand this to cover all
516 // temporaries that persist across blocks (dues to ?:, &&, ||, etc).
517 unsigned m_preservedVars;
518
519 struct PhiStackEntry {
520 PhiStackEntry(BasicBlock* block, NodeIndex phi, unsigned varNo)
521 : m_block(block)
522 , m_phi(phi)
523 , m_varNo(varNo)
524 {
525 }
526
527 BasicBlock* m_block;
528 NodeIndex m_phi;
529 unsigned m_varNo;
530 };
531 Vector<PhiStackEntry, 16> m_argumentPhiStack;
532 Vector<PhiStackEntry, 16> m_localPhiStack;
533
534 // These maps are used to unique ToNumber and ToInt32 operations.
535 typedef HashMap<NodeIndex, NodeIndex> UnaryOpMap;
536 UnaryOpMap m_int32ToNumberNodes;
537 UnaryOpMap m_numberToInt32Nodes;
538 };
539
540 #define NEXT_OPCODE(name) \
541 m_currentIndex += OPCODE_LENGTH(name); \
542 continue
543
544 #define LAST_OPCODE(name) \
545 m_currentIndex += OPCODE_LENGTH(name); \
546 return !m_parseFailed
547
548 bool ByteCodeParser::parseBlock(unsigned limit)
549 {
550 // No need to reset state initially, since it has been set by the constructor.
551 if (m_currentIndex) {
552 for (unsigned i = 0; i < m_constants.size(); ++i)
553 m_constants[i] = ConstantRecord();
554 }
555
556 AliasTracker aliases(m_graph);
557
558 Interpreter* interpreter = m_globalData->interpreter;
559 Instruction* instructionsBegin = m_codeBlock->instructions().begin();
560 while (true) {
561 // Don't extend over jump destinations.
562 if (m_currentIndex == limit) {
563 addToGraph(Jump, OpInfo(m_currentIndex));
564 return !m_parseFailed;
565 }
566
567 // Switch on the current bytecode opcode.
568 Instruction* currentInstruction = instructionsBegin + m_currentIndex;
569 switch (interpreter->getOpcodeID(currentInstruction->u.opcode)) {
570
571 // === Function entry opcodes ===
572
573 case op_enter:
574 // Initialize all locals to undefined.
575 for (int i = 0; i < m_codeBlock->m_numVars; ++i)
576 set(i, constantUndefined());
577 NEXT_OPCODE(op_enter);
578
579 case op_convert_this: {
580 NodeIndex op1 = getThis();
581 setThis(addToGraph(ConvertThis, op1));
582 NEXT_OPCODE(op_convert_this);
583 }
584
585 // === Bitwise operations ===
586
587 case op_bitand: {
588 NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
589 NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
590 predictInt32(op1);
591 predictInt32(op2);
592 set(currentInstruction[1].u.operand, addToGraph(BitAnd, op1, op2), PredictInt32);
593 NEXT_OPCODE(op_bitand);
594 }
595
596 case op_bitor: {
597 NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
598 NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
599 predictInt32(op1);
600 predictInt32(op2);
601 set(currentInstruction[1].u.operand, addToGraph(BitOr, op1, op2), PredictInt32);
602 NEXT_OPCODE(op_bitor);
603 }
604
605 case op_bitxor: {
606 NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
607 NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
608 predictInt32(op1);
609 predictInt32(op2);
610 set(currentInstruction[1].u.operand, addToGraph(BitXor, op1, op2), PredictInt32);
611 NEXT_OPCODE(op_bitxor);
612 }
613
614 case op_rshift: {
615 NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
616 NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
617 predictInt32(op1);
618 predictInt32(op2);
619 NodeIndex result;
620 // Optimize out shifts by zero.
621 if (isInt32Constant(op2) && !(valueOfInt32Constant(op2) & 0x1f))
622 result = op1;
623 else
624 result = addToGraph(BitRShift, op1, op2);
625 set(currentInstruction[1].u.operand, result, PredictInt32);
626 NEXT_OPCODE(op_rshift);
627 }
628
629 case op_lshift: {
630 NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
631 NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
632 predictInt32(op1);
633 predictInt32(op2);
634 NodeIndex result;
635 // Optimize out shifts by zero.
636 if (isInt32Constant(op2) && !(valueOfInt32Constant(op2) & 0x1f))
637 result = op1;
638 else
639 result = addToGraph(BitLShift, op1, op2);
640 set(currentInstruction[1].u.operand, result, PredictInt32);
641 NEXT_OPCODE(op_lshift);
642 }
643
644 case op_urshift: {
645 NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
646 NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
647 predictInt32(op1);
648 predictInt32(op2);
649 NodeIndex result;
650 // The result of a zero-extending right shift is treated as an unsigned value.
651 // This means that if the top bit is set, the result is not in the int32 range,
652 // and as such must be stored as a double. If the shift amount is a constant,
653 // we may be able to optimize.
654 if (isInt32Constant(op2)) {
655 // If we know we are shifting by a non-zero amount, then since the operation
656 // zero fills we know the top bit of the result must be zero, and as such the
657 // result must be within the int32 range. Conversely, if this is a shift by
658 // zero, then the result may be changed by the conversion to unsigned, but it
659 // is not necessary to perform the shift!
660 if (valueOfInt32Constant(op2) & 0x1f)
661 result = addToGraph(BitURShift, op1, op2);
662 else
663 result = addToGraph(UInt32ToNumber, op1);
664 } else {
665 // Cannot optimize at this stage; shift & potentially rebox as a double.
666 result = addToGraph(BitURShift, op1, op2);
667 result = addToGraph(UInt32ToNumber, result);
668 }
669 set(currentInstruction[1].u.operand, result, PredictInt32);
670 NEXT_OPCODE(op_urshift);
671 }
672
673 // === Increment/Decrement opcodes ===
674
675 case op_pre_inc: {
676 unsigned srcDst = currentInstruction[1].u.operand;
677 NodeIndex op = getToNumber(srcDst);
678 predictInt32(op);
679 set(srcDst, addToGraph(ArithAdd, op, one()));
680 NEXT_OPCODE(op_pre_inc);
681 }
682
683 case op_post_inc: {
684 unsigned result = currentInstruction[1].u.operand;
685 unsigned srcDst = currentInstruction[2].u.operand;
686 NodeIndex op = getToNumber(srcDst);
687 predictInt32(op);
688 set(result, op);
689 set(srcDst, addToGraph(ArithAdd, op, one()));
690 NEXT_OPCODE(op_post_inc);
691 }
692
693 case op_pre_dec: {
694 unsigned srcDst = currentInstruction[1].u.operand;
695 NodeIndex op = getToNumber(srcDst);
696 predictInt32(op);
697 set(srcDst, addToGraph(ArithSub, op, one()));
698 NEXT_OPCODE(op_pre_dec);
699 }
700
701 case op_post_dec: {
702 unsigned result = currentInstruction[1].u.operand;
703 unsigned srcDst = currentInstruction[2].u.operand;
704 NodeIndex op = getToNumber(srcDst);
705 predictInt32(op);
706 set(result, op);
707 set(srcDst, addToGraph(ArithSub, op, one()));
708 NEXT_OPCODE(op_post_dec);
709 }
710
711 // === Arithmetic operations ===
712
713 case op_add: {
714 ARITHMETIC_OP();
715 NodeIndex op1 = get(currentInstruction[2].u.operand);
716 NodeIndex op2 = get(currentInstruction[3].u.operand);
717 // If both operands can statically be determined to the numbers, then this is an arithmetic add.
718 // Otherwise, we must assume this may be performing a concatenation to a string.
719 if (m_graph[op1].hasNumericResult() && m_graph[op2].hasNumericResult())
720 set(currentInstruction[1].u.operand, addToGraph(ArithAdd, toNumber(op1), toNumber(op2)));
721 else
722 set(currentInstruction[1].u.operand, addToGraph(ValueAdd, op1, op2));
723 NEXT_OPCODE(op_add);
724 }
725
726 case op_sub: {
727 ARITHMETIC_OP();
728 NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
729 NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
730 set(currentInstruction[1].u.operand, addToGraph(ArithSub, op1, op2));
731 NEXT_OPCODE(op_sub);
732 }
733
734 case op_mul: {
735 ARITHMETIC_OP();
736 NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
737 NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
738 set(currentInstruction[1].u.operand, addToGraph(ArithMul, op1, op2));
739 NEXT_OPCODE(op_mul);
740 }
741
742 case op_mod: {
743 ARITHMETIC_OP();
744 NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
745 NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
746 set(currentInstruction[1].u.operand, addToGraph(ArithMod, op1, op2));
747 NEXT_OPCODE(op_mod);
748 }
749
750 case op_div: {
751 ARITHMETIC_OP();
752 NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
753 NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
754 set(currentInstruction[1].u.operand, addToGraph(ArithDiv, op1, op2));
755 NEXT_OPCODE(op_div);
756 }
757
758 // === Misc operations ===
759
760 case op_mov: {
761 NodeIndex op = get(currentInstruction[2].u.operand);
762 set(currentInstruction[1].u.operand, op);
763 NEXT_OPCODE(op_mov);
764 }
765
766 case op_not: {
767 ARITHMETIC_OP();
768 NodeIndex value = get(currentInstruction[2].u.operand);
769 set(currentInstruction[1].u.operand, addToGraph(LogicalNot, value));
770 NEXT_OPCODE(op_not);
771 }
772
773 case op_less: {
774 ARITHMETIC_OP();
775 NodeIndex op1 = get(currentInstruction[2].u.operand);
776 NodeIndex op2 = get(currentInstruction[3].u.operand);
777 set(currentInstruction[1].u.operand, addToGraph(CompareLess, op1, op2));
778 NEXT_OPCODE(op_less);
779 }
780
781 case op_lesseq: {
782 ARITHMETIC_OP();
783 NodeIndex op1 = get(currentInstruction[2].u.operand);
784 NodeIndex op2 = get(currentInstruction[3].u.operand);
785 set(currentInstruction[1].u.operand, addToGraph(CompareLessEq, op1, op2));
786 NEXT_OPCODE(op_lesseq);
787 }
788
789 case op_eq: {
790 ARITHMETIC_OP();
791 NodeIndex op1 = get(currentInstruction[2].u.operand);
792 NodeIndex op2 = get(currentInstruction[3].u.operand);
793 set(currentInstruction[1].u.operand, addToGraph(CompareEq, op1, op2));
794 NEXT_OPCODE(op_eq);
795 }
796
797 case op_eq_null: {
798 ARITHMETIC_OP();
799 NodeIndex value = get(currentInstruction[2].u.operand);
800 set(currentInstruction[1].u.operand, addToGraph(CompareEq, value, constantNull()));
801 NEXT_OPCODE(op_eq_null);
802 }
803
804 case op_stricteq: {
805 ARITHMETIC_OP();
806 NodeIndex op1 = get(currentInstruction[2].u.operand);
807 NodeIndex op2 = get(currentInstruction[3].u.operand);
808 set(currentInstruction[1].u.operand, addToGraph(CompareStrictEq, op1, op2));
809 NEXT_OPCODE(op_stricteq);
810 }
811
812 case op_neq: {
813 ARITHMETIC_OP();
814 NodeIndex op1 = get(currentInstruction[2].u.operand);
815 NodeIndex op2 = get(currentInstruction[3].u.operand);
816 set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareEq, op1, op2)));
817 NEXT_OPCODE(op_neq);
818 }
819
820 case op_neq_null: {
821 ARITHMETIC_OP();
822 NodeIndex value = get(currentInstruction[2].u.operand);
823 set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareEq, value, constantNull())));
824 NEXT_OPCODE(op_neq_null);
825 }
826
827 case op_nstricteq: {
828 ARITHMETIC_OP();
829 NodeIndex op1 = get(currentInstruction[2].u.operand);
830 NodeIndex op2 = get(currentInstruction[3].u.operand);
831 set(currentInstruction[1].u.operand, addToGraph(LogicalNot, addToGraph(CompareStrictEq, op1, op2)));
832 NEXT_OPCODE(op_nstricteq);
833 }
834
835 // === Property access operations ===
836
837 case op_get_by_val: {
838 NodeIndex base = get(currentInstruction[2].u.operand);
839 NodeIndex property = get(currentInstruction[3].u.operand);
840 predictArray(base);
841 predictInt32(property);
842
843 NodeIndex getByVal = addToGraph(GetByVal, base, property, aliases.lookupGetByVal(base, property));
844 set(currentInstruction[1].u.operand, getByVal);
845 aliases.recordGetByVal(getByVal);
846
847 NEXT_OPCODE(op_get_by_val);
848 }
849
850 case op_put_by_val: {
851 NodeIndex base = get(currentInstruction[1].u.operand);
852 NodeIndex property = get(currentInstruction[2].u.operand);
853 NodeIndex value = get(currentInstruction[3].u.operand);
854 predictArray(base);
855 predictInt32(property);
856
857 NodeIndex aliasedGet = aliases.lookupGetByVal(base, property);
858 NodeIndex putByVal = addToGraph(aliasedGet != NoNode ? PutByValAlias : PutByVal, base, property, value);
859 aliases.recordPutByVal(putByVal);
860
861 NEXT_OPCODE(op_put_by_val);
862 }
863
864 case op_get_by_id: {
865 NodeIndex base = get(currentInstruction[2].u.operand);
866 unsigned identifier = currentInstruction[3].u.operand;
867
868 NodeIndex getById = addToGraph(GetById, OpInfo(identifier), base);
869 set(currentInstruction[1].u.operand, getById);
870 aliases.recordGetById(getById);
871
872 NEXT_OPCODE(op_get_by_id);
873 }
874
875 case op_put_by_id: {
876 NodeIndex value = get(currentInstruction[3].u.operand);
877 NodeIndex base = get(currentInstruction[1].u.operand);
878 unsigned identifier = currentInstruction[2].u.operand;
879 bool direct = currentInstruction[8].u.operand;
880
881 if (direct) {
882 NodeIndex putByIdDirect = addToGraph(PutByIdDirect, OpInfo(identifier), base, value);
883 aliases.recordPutByIdDirect(putByIdDirect);
884 } else {
885 NodeIndex putById = addToGraph(PutById, OpInfo(identifier), base, value);
886 aliases.recordPutById(putById);
887 }
888
889 NEXT_OPCODE(op_put_by_id);
890 }
891
892 case op_get_global_var: {
893 NodeIndex getGlobalVar = addToGraph(GetGlobalVar, OpInfo(currentInstruction[2].u.operand));
894 set(currentInstruction[1].u.operand, getGlobalVar);
895 NEXT_OPCODE(op_get_global_var);
896 }
897
898 case op_put_global_var: {
899 NodeIndex value = get(currentInstruction[2].u.operand);
900 addToGraph(PutGlobalVar, OpInfo(currentInstruction[1].u.operand), value);
901 NEXT_OPCODE(op_put_global_var);
902 }
903
904 // === Block terminators. ===
905
906 case op_jmp: {
907 unsigned relativeOffset = currentInstruction[1].u.operand;
908 addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
909 LAST_OPCODE(op_jmp);
910 }
911
912 case op_loop: {
913 unsigned relativeOffset = currentInstruction[1].u.operand;
914 addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
915 LAST_OPCODE(op_loop);
916 }
917
918 case op_jtrue: {
919 unsigned relativeOffset = currentInstruction[2].u.operand;
920 NodeIndex condition = get(currentInstruction[1].u.operand);
921 addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jtrue)), condition);
922 LAST_OPCODE(op_jtrue);
923 }
924
925 case op_jfalse: {
926 unsigned relativeOffset = currentInstruction[2].u.operand;
927 NodeIndex condition = get(currentInstruction[1].u.operand);
928 addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jfalse)), OpInfo(m_currentIndex + relativeOffset), condition);
929 LAST_OPCODE(op_jfalse);
930 }
931
932 case op_loop_if_true: {
933 unsigned relativeOffset = currentInstruction[2].u.operand;
934 NodeIndex condition = get(currentInstruction[1].u.operand);
935 addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_true)), condition);
936 LAST_OPCODE(op_loop_if_true);
937 }
938
939 case op_loop_if_false: {
940 unsigned relativeOffset = currentInstruction[2].u.operand;
941 NodeIndex condition = get(currentInstruction[1].u.operand);
942 addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_false)), OpInfo(m_currentIndex + relativeOffset), condition);
943 LAST_OPCODE(op_loop_if_false);
944 }
945
946 case op_jeq_null: {
947 unsigned relativeOffset = currentInstruction[2].u.operand;
948 NodeIndex value = get(currentInstruction[1].u.operand);
949 NodeIndex condition = addToGraph(CompareEq, value, constantNull());
950 addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jeq_null)), condition);
951 LAST_OPCODE(op_jeq_null);
952 }
953
954 case op_jneq_null: {
955 unsigned relativeOffset = currentInstruction[2].u.operand;
956 NodeIndex value = get(currentInstruction[1].u.operand);
957 NodeIndex condition = addToGraph(CompareEq, value, constantNull());
958 addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jneq_null)), OpInfo(m_currentIndex + relativeOffset), condition);
959 LAST_OPCODE(op_jneq_null);
960 }
961
962 case op_jnless: {
963 unsigned relativeOffset = currentInstruction[3].u.operand;
964 NodeIndex op1 = get(currentInstruction[1].u.operand);
965 NodeIndex op2 = get(currentInstruction[2].u.operand);
966 NodeIndex condition = addToGraph(CompareLess, op1, op2);
967 addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jnless)), OpInfo(m_currentIndex + relativeOffset), condition);
968 LAST_OPCODE(op_jnless);
969 }
970
971 case op_jnlesseq: {
972 unsigned relativeOffset = currentInstruction[3].u.operand;
973 NodeIndex op1 = get(currentInstruction[1].u.operand);
974 NodeIndex op2 = get(currentInstruction[2].u.operand);
975 NodeIndex condition = addToGraph(CompareLessEq, op1, op2);
976 addToGraph(Branch, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jnlesseq)), OpInfo(m_currentIndex + relativeOffset), condition);
977 LAST_OPCODE(op_jnlesseq);
978 }
979
980 case op_jless: {
981 unsigned relativeOffset = currentInstruction[3].u.operand;
982 NodeIndex op1 = get(currentInstruction[1].u.operand);
983 NodeIndex op2 = get(currentInstruction[2].u.operand);
984 NodeIndex condition = addToGraph(CompareLess, op1, op2);
985 addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jless)), condition);
986 LAST_OPCODE(op_jless);
987 }
988
989 case op_jlesseq: {
990 unsigned relativeOffset = currentInstruction[3].u.operand;
991 NodeIndex op1 = get(currentInstruction[1].u.operand);
992 NodeIndex op2 = get(currentInstruction[2].u.operand);
993 NodeIndex condition = addToGraph(CompareLessEq, op1, op2);
994 addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_jlesseq)), condition);
995 LAST_OPCODE(op_jlesseq);
996 }
997
998 case op_loop_if_less: {
999 unsigned relativeOffset = currentInstruction[3].u.operand;
1000 NodeIndex op1 = get(currentInstruction[1].u.operand);
1001 NodeIndex op2 = get(currentInstruction[2].u.operand);
1002 NodeIndex condition = addToGraph(CompareLess, op1, op2);
1003 addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_less)), condition);
1004 LAST_OPCODE(op_loop_if_less);
1005 }
1006
1007 case op_loop_if_lesseq: {
1008 unsigned relativeOffset = currentInstruction[3].u.operand;
1009 NodeIndex op1 = get(currentInstruction[1].u.operand);
1010 NodeIndex op2 = get(currentInstruction[2].u.operand);
1011 NodeIndex condition = addToGraph(CompareLessEq, op1, op2);
1012 addToGraph(Branch, OpInfo(m_currentIndex + relativeOffset), OpInfo(m_currentIndex + OPCODE_LENGTH(op_loop_if_lesseq)), condition);
1013 LAST_OPCODE(op_loop_if_lesseq);
1014 }
1015
1016 case op_ret: {
1017 addToGraph(Return, get(currentInstruction[1].u.operand));
1018 LAST_OPCODE(op_ret);
1019 }
1020
1021 default:
1022 // Parse failed!
1023 return false;
1024 }
1025 }
1026 }
1027
1028 template<ByteCodeParser::PhiStackType stackType>
1029 void ByteCodeParser::processPhiStack()
1030 {
1031 Vector<PhiStackEntry, 16>& phiStack = (stackType == ArgumentPhiStack) ? m_argumentPhiStack : m_localPhiStack;
1032
1033 while (!phiStack.isEmpty()) {
1034 PhiStackEntry entry = phiStack.last();
1035 phiStack.removeLast();
1036
1037 Node& phiNode = m_graph[entry.m_phi];
1038 PredecessorList& predecessors = entry.m_block->m_predecessors;
1039 unsigned varNo = entry.m_varNo;
1040
1041 for (size_t i = 0; i < predecessors.size(); ++i) {
1042 BasicBlock* predecessorBlock = m_graph.m_blocks[predecessors[i]].get();
1043
1044 VariableRecord& var = (stackType == ArgumentPhiStack) ? predecessorBlock->m_arguments[varNo] : predecessorBlock->m_locals[varNo];
1045
1046 NodeIndex valueInPredecessor = var.value;
1047 if (valueInPredecessor == NoNode) {
1048 valueInPredecessor = addToGraph(Phi);
1049 var.value = valueInPredecessor;
1050 phiStack.append(PhiStackEntry(predecessorBlock, valueInPredecessor, varNo));
1051 } else if (m_graph[valueInPredecessor].op == GetLocal)
1052 valueInPredecessor = m_graph[valueInPredecessor].child1;
1053 ASSERT(m_graph[valueInPredecessor].op == SetLocal || m_graph[valueInPredecessor].op == Phi);
1054
1055 if (phiNode.refCount())
1056 m_graph.ref(valueInPredecessor);
1057
1058 if (phiNode.child1 == NoNode) {
1059 phiNode.child1 = valueInPredecessor;
1060 continue;
1061 }
1062 if (phiNode.child2 == NoNode) {
1063 phiNode.child2 = valueInPredecessor;
1064 continue;
1065 }
1066 if (phiNode.child3 == NoNode) {
1067 phiNode.child3 = valueInPredecessor;
1068 continue;
1069 }
1070
1071 NodeIndex newPhi = addToGraph(Phi);
1072 Node& newPhiNode = m_graph[newPhi];
1073 if (phiNode.refCount())
1074 m_graph.ref(newPhi);
1075
1076 newPhiNode.child1 = phiNode.child1;
1077 newPhiNode.child2 = phiNode.child2;
1078 newPhiNode.child3 = phiNode.child3;
1079
1080 phiNode.child1 = newPhi;
1081 phiNode.child1 = valueInPredecessor;
1082 phiNode.child3 = NoNode;
1083 }
1084 }
1085 }
1086
1087 void ByteCodeParser::setupPredecessors()
1088 {
1089 for (BlockIndex index = 0; index < m_graph.m_blocks.size(); ++index) {
1090 BasicBlock* block = m_graph.m_blocks[index].get();
1091 ASSERT(block->end != NoNode);
1092 Node& node = m_graph[block->end - 1];
1093 ASSERT(node.isTerminal());
1094
1095 if (node.isJump())
1096 m_graph.blockForBytecodeOffset(node.takenBytecodeOffset()).m_predecessors.append(index);
1097 else if (node.isBranch()) {
1098 m_graph.blockForBytecodeOffset(node.takenBytecodeOffset()).m_predecessors.append(index);
1099 m_graph.blockForBytecodeOffset(node.notTakenBytecodeOffset()).m_predecessors.append(index);
1100 }
1101 }
1102 }
1103
1104 void ByteCodeParser::allocateVirtualRegisters()
1105 {
1106 ScoreBoard scoreBoard(m_graph, m_preservedVars);
1107 unsigned sizeExcludingPhiNodes = m_graph.m_blocks.last()->end;
1108 for (size_t i = 0; i < sizeExcludingPhiNodes; ++i) {
1109 Node& node = m_graph[i];
1110 if (!node.shouldGenerate())
1111 continue;
1112
1113 // GetLocal nodes are effectively phi nodes in the graph, referencing
1114 // results from prior blocks.
1115 if (node.op != GetLocal) {
1116 // First, call use on all of the current node's children, then
1117 // allocate a VirtualRegister for this node. We do so in this
1118 // order so that if a child is on its last use, and a
1119 // VirtualRegister is freed, then it may be reused for node.
1120 scoreBoard.use(node.child1);
1121 scoreBoard.use(node.child2);
1122 scoreBoard.use(node.child3);
1123 }
1124
1125 if (!node.hasResult())
1126 continue;
1127
1128 node.setVirtualRegister(scoreBoard.allocate());
1129 // 'mustGenerate' nodes have their useCount artificially elevated,
1130 // call use now to account for this.
1131 if (node.mustGenerate())
1132 scoreBoard.use(i);
1133 }
1134
1135 // 'm_numCalleeRegisters' is the number of locals and temporaries allocated
1136 // for the function (and checked for on entry). Since we perform a new and
1137 // different allocation of temporaries, more registers may now be required.
1138 unsigned calleeRegisters = scoreBoard.allocatedCount() + m_preservedVars;
1139 if ((unsigned)m_codeBlock->m_numCalleeRegisters < calleeRegisters)
1140 m_codeBlock->m_numCalleeRegisters = calleeRegisters;
1141 }
1142
1143 bool ByteCodeParser::parse()
1144 {
1145 // Set during construction.
1146 ASSERT(!m_currentIndex);
1147
1148 for (unsigned jumpTargetIndex = 0; jumpTargetIndex <= m_codeBlock->numberOfJumpTargets(); ++jumpTargetIndex) {
1149 // The maximum bytecode offset to go into the current basicblock is either the next jump target, or the end of the instructions.
1150 unsigned limit = jumpTargetIndex < m_codeBlock->numberOfJumpTargets() ? m_codeBlock->jumpTarget(jumpTargetIndex) : m_codeBlock->instructions().size();
1151 ASSERT(m_currentIndex < limit);
1152
1153 // Loop until we reach the current limit (i.e. next jump target).
1154 do {
1155 OwnPtr<BasicBlock> block = adoptPtr(new BasicBlock(m_currentIndex, m_graph.size(), m_numArguments, m_numLocals));
1156 m_currentBlock = block.get();
1157 m_graph.m_blocks.append(block.release());
1158
1159 if (!parseBlock(limit))
1160 return false;
1161 // We should not have gone beyond the limit.
1162 ASSERT(m_currentIndex <= limit);
1163
1164 m_currentBlock->end = m_graph.size();
1165 } while (m_currentIndex < limit);
1166 }
1167
1168 // Should have reached the end of the instructions.
1169 ASSERT(m_currentIndex == m_codeBlock->instructions().size());
1170
1171 setupPredecessors();
1172 processPhiStack<LocalPhiStack>();
1173 processPhiStack<ArgumentPhiStack>();
1174
1175 allocateVirtualRegisters();
1176
1177 #if DFG_DEBUG_VERBOSE
1178 m_graph.dump(m_codeBlock);
1179 #endif
1180
1181 return true;
1182 }
1183
1184 bool parse(Graph& graph, JSGlobalData* globalData, CodeBlock* codeBlock)
1185 {
1186 #if DFG_DEBUG_LOCAL_DISBALE
1187 UNUSED_PARAM(graph);
1188 UNUSED_PARAM(globalData);
1189 UNUSED_PARAM(codeBlock);
1190 return false;
1191 #else
1192 return ByteCodeParser(globalData, codeBlock, graph).parse();
1193 #endif
1194 }
1195
1196 } } // namespace JSC::DFG
1197
1198 #endif