]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGJITCodeGenerator.cpp
781edbb3d08ad70daf74d6f688d32afb43f6b1be
[apple/javascriptcore.git] / dfg / DFGJITCodeGenerator.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 "DFGJITCodeGenerator.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "DFGNonSpeculativeJIT.h"
32 #include "DFGSpeculativeJIT.h"
33 #include "LinkBuffer.h"
34
35 namespace JSC { namespace DFG {
36
37 GPRReg JITCodeGenerator::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat)
38 {
39 Node& node = m_jit.graph()[nodeIndex];
40 VirtualRegister virtualRegister = node.virtualRegister();
41 GenerationInfo& info = m_generationInfo[virtualRegister];
42
43 if (info.registerFormat() == DataFormatNone) {
44 GPRReg gpr = allocate();
45
46 if (node.isConstant()) {
47 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
48 if (isInt32Constant(nodeIndex)) {
49 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
50 info.fillInteger(gpr);
51 returnFormat = DataFormatInteger;
52 return gpr;
53 }
54 if (isDoubleConstant(nodeIndex)) {
55 JSValue jsValue = jsNumber(valueOfDoubleConstant(nodeIndex));
56 m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
57 } else {
58 ASSERT(isJSConstant(nodeIndex));
59 JSValue jsValue = valueOfJSConstant(nodeIndex);
60 m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
61 }
62 } else {
63 ASSERT(info.spillFormat() == DataFormatJS || info.spillFormat() == DataFormatJSInteger);
64 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
65 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
66 }
67
68 // Since we statically know that we're filling an integer, and values
69 // in the RegisterFile are boxed, this must be DataFormatJSInteger.
70 // We will check this with a jitAssert below.
71 info.fillJSValue(gpr, DataFormatJSInteger);
72 unlock(gpr);
73 }
74
75 switch (info.registerFormat()) {
76 case DataFormatNone:
77 // Should have filled, above.
78 case DataFormatJSDouble:
79 case DataFormatDouble:
80 case DataFormatJS:
81 case DataFormatCell:
82 case DataFormatJSCell:
83 // Should only be calling this function if we know this operand to be integer.
84 ASSERT_NOT_REACHED();
85
86 case DataFormatJSInteger: {
87 GPRReg gpr = info.gpr();
88 m_gprs.lock(gpr);
89 m_jit.jitAssertIsJSInt32(gpr);
90 returnFormat = DataFormatJSInteger;
91 return gpr;
92 }
93
94 case DataFormatInteger: {
95 GPRReg gpr = info.gpr();
96 m_gprs.lock(gpr);
97 m_jit.jitAssertIsInt32(gpr);
98 returnFormat = DataFormatInteger;
99 return gpr;
100 }
101 }
102
103 ASSERT_NOT_REACHED();
104 return InvalidGPRReg;
105 }
106
107 FPRReg JITCodeGenerator::fillDouble(NodeIndex nodeIndex)
108 {
109 Node& node = m_jit.graph()[nodeIndex];
110 VirtualRegister virtualRegister = node.virtualRegister();
111 GenerationInfo& info = m_generationInfo[virtualRegister];
112
113 if (info.registerFormat() == DataFormatNone) {
114 GPRReg gpr = allocate();
115
116 if (node.isConstant()) {
117 if (isInt32Constant(nodeIndex)) {
118 // FIXME: should not be reachable?
119 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
120 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
121 info.fillInteger(gpr);
122 unlock(gpr);
123 } else if (isDoubleConstant(nodeIndex)) {
124 FPRReg fpr = fprAllocate();
125 m_jit.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfDoubleConstant(nodeIndex)))), gpr);
126 m_jit.movePtrToDouble(gpr, fpr);
127 unlock(gpr);
128
129 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
130 info.fillDouble(fpr);
131 return fpr;
132 } else {
133 // FIXME: should not be reachable?
134 ASSERT(isJSConstant(nodeIndex));
135 JSValue jsValue = valueOfJSConstant(nodeIndex);
136 m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
137 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
138 info.fillJSValue(gpr, DataFormatJS);
139 unlock(gpr);
140 }
141 } else {
142 DataFormat spillFormat = info.spillFormat();
143 ASSERT(spillFormat & DataFormatJS);
144 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
145 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
146 info.fillJSValue(gpr, m_isSpeculative ? spillFormat : DataFormatJS);
147 unlock(gpr);
148 }
149 }
150
151 switch (info.registerFormat()) {
152 case DataFormatNone:
153 // Should have filled, above.
154 case DataFormatCell:
155 case DataFormatJSCell:
156 // Should only be calling this function if we know this operand to be numeric.
157 ASSERT_NOT_REACHED();
158
159 case DataFormatJS: {
160 GPRReg jsValueGpr = info.gpr();
161 m_gprs.lock(jsValueGpr);
162 FPRReg fpr = fprAllocate();
163 GPRReg tempGpr = allocate(); // FIXME: can we skip this allocation on the last use of the virtual register?
164
165 JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister);
166
167 m_jit.jitAssertIsJSDouble(jsValueGpr);
168
169 // First, if we get here we have a double encoded as a JSValue
170 m_jit.move(jsValueGpr, tempGpr);
171 m_jit.addPtr(GPRInfo::tagTypeNumberRegister, tempGpr);
172 m_jit.movePtrToDouble(tempGpr, fpr);
173 JITCompiler::Jump hasUnboxedDouble = m_jit.jump();
174
175 // Finally, handle integers.
176 isInteger.link(&m_jit);
177 m_jit.convertInt32ToDouble(jsValueGpr, fpr);
178 hasUnboxedDouble.link(&m_jit);
179
180 m_gprs.release(jsValueGpr);
181 m_gprs.unlock(jsValueGpr);
182 m_gprs.unlock(tempGpr);
183 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
184 info.fillDouble(fpr);
185 return fpr;
186 }
187
188 case DataFormatJSInteger:
189 case DataFormatInteger: {
190 FPRReg fpr = fprAllocate();
191 GPRReg gpr = info.gpr();
192 m_gprs.lock(gpr);
193
194 m_jit.convertInt32ToDouble(gpr, fpr);
195
196 m_gprs.release(gpr);
197 m_gprs.unlock(gpr);
198 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
199 info.fillDouble(fpr);
200 return fpr;
201 }
202
203 // Unbox the double
204 case DataFormatJSDouble: {
205 GPRReg gpr = info.gpr();
206 FPRReg fpr = unboxDouble(gpr);
207
208 m_gprs.release(gpr);
209 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
210
211 info.fillDouble(fpr);
212 return fpr;
213 }
214
215 case DataFormatDouble: {
216 FPRReg fpr = info.fpr();
217 m_fprs.lock(fpr);
218 return fpr;
219 }
220 }
221
222 ASSERT_NOT_REACHED();
223 return InvalidFPRReg;
224 }
225
226 GPRReg JITCodeGenerator::fillJSValue(NodeIndex nodeIndex)
227 {
228 Node& node = m_jit.graph()[nodeIndex];
229 VirtualRegister virtualRegister = node.virtualRegister();
230 GenerationInfo& info = m_generationInfo[virtualRegister];
231
232 switch (info.registerFormat()) {
233 case DataFormatNone: {
234 GPRReg gpr = allocate();
235
236 if (node.isConstant()) {
237 if (isInt32Constant(nodeIndex)) {
238 info.fillJSValue(gpr, DataFormatJSInteger);
239 JSValue jsValue = jsNumber(valueOfInt32Constant(nodeIndex));
240 m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
241 } else if (isDoubleConstant(nodeIndex)) {
242 info.fillJSValue(gpr, DataFormatJSDouble);
243 JSValue jsValue(JSValue::EncodeAsDouble, valueOfDoubleConstant(nodeIndex));
244 m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
245 } else {
246 ASSERT(isJSConstant(nodeIndex));
247 JSValue jsValue = valueOfJSConstant(nodeIndex);
248 m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
249 info.fillJSValue(gpr, DataFormatJS);
250 }
251
252 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
253 } else {
254 DataFormat spillFormat = info.spillFormat();
255 ASSERT(spillFormat & DataFormatJS);
256 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
257 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
258 info.fillJSValue(gpr, m_isSpeculative ? spillFormat : DataFormatJS);
259 }
260 return gpr;
261 }
262
263 case DataFormatInteger: {
264 GPRReg gpr = info.gpr();
265 // If the register has already been locked we need to take a copy.
266 // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInteger, not DataFormatJSInteger.
267 if (m_gprs.isLocked(gpr)) {
268 GPRReg result = allocate();
269 m_jit.orPtr(GPRInfo::tagTypeNumberRegister, gpr, result);
270 return result;
271 }
272 m_gprs.lock(gpr);
273 m_jit.orPtr(GPRInfo::tagTypeNumberRegister, gpr);
274 info.fillJSValue(gpr, DataFormatJSInteger);
275 return gpr;
276 }
277
278 case DataFormatDouble: {
279 FPRReg fpr = info.fpr();
280 GPRReg gpr = boxDouble(fpr);
281
282 // Update all info
283 info.fillJSValue(gpr, DataFormatJSDouble);
284 m_fprs.release(fpr);
285 m_gprs.retain(gpr, virtualRegister, SpillOrderJS);
286
287 return gpr;
288 }
289
290 case DataFormatCell:
291 // No retag required on JSVALUE64!
292 case DataFormatJS:
293 case DataFormatJSInteger:
294 case DataFormatJSDouble:
295 case DataFormatJSCell: {
296 GPRReg gpr = info.gpr();
297 m_gprs.lock(gpr);
298 return gpr;
299 }
300 }
301
302 ASSERT_NOT_REACHED();
303 return InvalidGPRReg;
304 }
305
306 void JITCodeGenerator::useChildren(Node& node)
307 {
308 NodeIndex child1 = node.child1;
309 if (child1 == NoNode) {
310 ASSERT(node.child2 == NoNode && node.child3 == NoNode);
311 return;
312 }
313 use(child1);
314
315 NodeIndex child2 = node.child2;
316 if (child2 == NoNode) {
317 ASSERT(node.child3 == NoNode);
318 return;
319 }
320 use(child2);
321
322 NodeIndex child3 = node.child3;
323 if (child3 == NoNode)
324 return;
325 use(child3);
326 }
327
328 #ifndef NDEBUG
329 static const char* dataFormatString(DataFormat format)
330 {
331 // These values correspond to the DataFormat enum.
332 const char* strings[] = {
333 "[ ]",
334 "[ i]",
335 "[ d]",
336 "[ c]",
337 "Err!",
338 "Err!",
339 "Err!",
340 "Err!",
341 "[J ]",
342 "[Ji]",
343 "[Jd]",
344 "[Jc]",
345 "Err!",
346 "Err!",
347 "Err!",
348 "Err!",
349 };
350 return strings[format];
351 }
352
353 void JITCodeGenerator::dump(const char* label)
354 {
355 if (label)
356 fprintf(stderr, "<%s>\n", label);
357
358 fprintf(stderr, " gprs:\n");
359 m_gprs.dump();
360 fprintf(stderr, " fprs:\n");
361 m_fprs.dump();
362 fprintf(stderr, " VirtualRegisters:\n");
363 for (unsigned i = 0; i < m_generationInfo.size(); ++i) {
364 GenerationInfo& info = m_generationInfo[i];
365 if (info.alive())
366 fprintf(stderr, " % 3d:%s%s", i, dataFormatString(info.registerFormat()), dataFormatString(info.spillFormat()));
367 else
368 fprintf(stderr, " % 3d:[__][__]", i);
369 if (info.registerFormat() == DataFormatDouble)
370 fprintf(stderr, ":fpr%d\n", info.fpr());
371 else if (info.registerFormat() != DataFormatNone) {
372 ASSERT(info.gpr() != InvalidGPRReg);
373 fprintf(stderr, ":%s\n", GPRInfo::debugName(info.gpr()));
374 } else
375 fprintf(stderr, "\n");
376 }
377 if (label)
378 fprintf(stderr, "</%s>\n", label);
379 }
380 #endif
381
382
383 #if DFG_CONSISTENCY_CHECK
384 void JITCodeGenerator::checkConsistency()
385 {
386 bool failed = false;
387
388 for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
389 if (iter.isLocked()) {
390 fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: gpr %s is locked.\n", iter.debugName());
391 failed = true;
392 }
393 }
394 for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
395 if (iter.isLocked()) {
396 fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: fpr %s is locked.\n", iter.debugName());
397 failed = true;
398 }
399 }
400
401 for (unsigned i = 0; i < m_generationInfo.size(); ++i) {
402 VirtualRegister virtualRegister = (VirtualRegister)i;
403 GenerationInfo& info = m_generationInfo[virtualRegister];
404 if (!info.alive())
405 continue;
406 switch (info.registerFormat()) {
407 case DataFormatNone:
408 break;
409 case DataFormatInteger:
410 case DataFormatCell:
411 case DataFormatJS:
412 case DataFormatJSInteger:
413 case DataFormatJSDouble:
414 case DataFormatJSCell: {
415 GPRReg gpr = info.gpr();
416 ASSERT(gpr != InvalidGPRReg);
417 if (m_gprs.name(gpr) != virtualRegister) {
418 fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (gpr %s).\n", virtualRegister, GPRInfo::debugName(gpr));
419 failed = true;
420 }
421 break;
422 }
423 case DataFormatDouble: {
424 FPRReg fpr = info.fpr();
425 ASSERT(fpr != InvalidFPRReg);
426 if (m_fprs.name(fpr) != virtualRegister) {
427 fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (fpr %s).\n", virtualRegister, FPRInfo::debugName(fpr));
428 failed = true;
429 }
430 break;
431 }
432 }
433 }
434
435 for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
436 VirtualRegister virtualRegister = iter.name();
437 if (virtualRegister == InvalidVirtualRegister)
438 continue;
439
440 GenerationInfo& info = m_generationInfo[virtualRegister];
441 if (iter.regID() != info.gpr()) {
442 fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
443 failed = true;
444 }
445 }
446
447 for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
448 VirtualRegister virtualRegister = iter.name();
449 if (virtualRegister == InvalidVirtualRegister)
450 continue;
451
452 GenerationInfo& info = m_generationInfo[virtualRegister];
453 if (iter.regID() != info.fpr()) {
454 fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for fpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
455 failed = true;
456 }
457 }
458
459 if (failed) {
460 dump();
461 CRASH();
462 }
463 }
464 #endif
465
466 GPRTemporary::GPRTemporary(JITCodeGenerator* jit)
467 : m_jit(jit)
468 , m_gpr(InvalidGPRReg)
469 {
470 m_gpr = m_jit->allocate();
471 }
472
473 GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateIntegerOperand& op1)
474 : m_jit(jit)
475 , m_gpr(InvalidGPRReg)
476 {
477 if (m_jit->canReuse(op1.index()))
478 m_gpr = m_jit->reuse(op1.gpr());
479 else
480 m_gpr = m_jit->allocate();
481 }
482
483 GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateIntegerOperand& op1, SpeculateIntegerOperand& op2)
484 : m_jit(jit)
485 , m_gpr(InvalidGPRReg)
486 {
487 if (m_jit->canReuse(op1.index()))
488 m_gpr = m_jit->reuse(op1.gpr());
489 else if (m_jit->canReuse(op2.index()))
490 m_gpr = m_jit->reuse(op2.gpr());
491 else
492 m_gpr = m_jit->allocate();
493 }
494
495 GPRTemporary::GPRTemporary(JITCodeGenerator* jit, IntegerOperand& op1)
496 : m_jit(jit)
497 , m_gpr(InvalidGPRReg)
498 {
499 if (m_jit->canReuse(op1.index()))
500 m_gpr = m_jit->reuse(op1.gpr());
501 else
502 m_gpr = m_jit->allocate();
503 }
504
505 GPRTemporary::GPRTemporary(JITCodeGenerator* jit, IntegerOperand& op1, IntegerOperand& op2)
506 : m_jit(jit)
507 , m_gpr(InvalidGPRReg)
508 {
509 if (m_jit->canReuse(op1.index()))
510 m_gpr = m_jit->reuse(op1.gpr());
511 else if (m_jit->canReuse(op2.index()))
512 m_gpr = m_jit->reuse(op2.gpr());
513 else
514 m_gpr = m_jit->allocate();
515 }
516
517 GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateCellOperand& op1)
518 : m_jit(jit)
519 , m_gpr(InvalidGPRReg)
520 {
521 if (m_jit->canReuse(op1.index()))
522 m_gpr = m_jit->reuse(op1.gpr());
523 else
524 m_gpr = m_jit->allocate();
525 }
526
527 GPRTemporary::GPRTemporary(JITCodeGenerator* jit, JSValueOperand& op1)
528 : m_jit(jit)
529 , m_gpr(InvalidGPRReg)
530 {
531 if (m_jit->canReuse(op1.index()))
532 m_gpr = m_jit->reuse(op1.gpr());
533 else
534 m_gpr = m_jit->allocate();
535 }
536
537 FPRTemporary::FPRTemporary(JITCodeGenerator* jit)
538 : m_jit(jit)
539 , m_fpr(InvalidFPRReg)
540 {
541 m_fpr = m_jit->fprAllocate();
542 }
543
544 FPRTemporary::FPRTemporary(JITCodeGenerator* jit, DoubleOperand& op1)
545 : m_jit(jit)
546 , m_fpr(InvalidFPRReg)
547 {
548 if (m_jit->canReuse(op1.index()))
549 m_fpr = m_jit->reuse(op1.fpr());
550 else
551 m_fpr = m_jit->fprAllocate();
552 }
553
554 FPRTemporary::FPRTemporary(JITCodeGenerator* jit, DoubleOperand& op1, DoubleOperand& op2)
555 : m_jit(jit)
556 , m_fpr(InvalidFPRReg)
557 {
558 if (m_jit->canReuse(op1.index()))
559 m_fpr = m_jit->reuse(op1.fpr());
560 else if (m_jit->canReuse(op2.index()))
561 m_fpr = m_jit->reuse(op2.fpr());
562 else
563 m_fpr = m_jit->fprAllocate();
564 }
565
566 } } // namespace JSC::DFG
567
568 #endif