]> git.saurik.com Git - apple/javascriptcore.git/blame - dfg/DFGSpeculativeJIT32_64.cpp
JavaScriptCore-1097.3.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGSpeculativeJIT32_64.cpp
CommitLineData
6fe7ccc8
A
1/*
2 * Copyright (C) 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2011 Intel Corporation. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "DFGSpeculativeJIT.h"
29
30#if ENABLE(DFG_JIT)
31
32namespace JSC { namespace DFG {
33
34#if USE(JSVALUE32_64)
35
36GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat)
37{
38 Node& node = at(nodeIndex);
39 VirtualRegister virtualRegister = node.virtualRegister();
40 GenerationInfo& info = m_generationInfo[virtualRegister];
41
42 if (info.registerFormat() == DataFormatNone) {
43 GPRReg gpr = allocate();
44
45 if (node.hasConstant()) {
46 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
47 if (isInt32Constant(nodeIndex))
48 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
49 else if (isNumberConstant(nodeIndex))
50 ASSERT_NOT_REACHED();
51 else {
52 ASSERT(isJSConstant(nodeIndex));
53 JSValue jsValue = valueOfJSConstant(nodeIndex);
54 m_jit.move(MacroAssembler::Imm32(jsValue.payload()), gpr);
55 }
56 } else {
57 ASSERT(info.spillFormat() == DataFormatJS || info.spillFormat() == DataFormatJSInteger || info.spillFormat() == DataFormatInteger);
58 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
59 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
60 }
61
62 info.fillInteger(gpr);
63 returnFormat = DataFormatInteger;
64 return gpr;
65 }
66
67 switch (info.registerFormat()) {
68 case DataFormatNone:
69 // Should have filled, above.
70 case DataFormatJSDouble:
71 case DataFormatDouble:
72 case DataFormatJS:
73 case DataFormatCell:
74 case DataFormatJSCell:
75 case DataFormatBoolean:
76 case DataFormatJSBoolean:
77 case DataFormatStorage:
78 // Should only be calling this function if we know this operand to be integer.
79 ASSERT_NOT_REACHED();
80
81 case DataFormatJSInteger: {
82 GPRReg tagGPR = info.tagGPR();
83 GPRReg payloadGPR = info.payloadGPR();
84 m_gprs.lock(tagGPR);
85 m_jit.jitAssertIsJSInt32(tagGPR);
86 m_gprs.unlock(tagGPR);
87 m_gprs.lock(payloadGPR);
88 m_gprs.release(tagGPR);
89 m_gprs.release(payloadGPR);
90 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderInteger);
91 info.fillInteger(payloadGPR);
92 returnFormat = DataFormatInteger;
93 return payloadGPR;
94 }
95
96 case DataFormatInteger: {
97 GPRReg gpr = info.gpr();
98 m_gprs.lock(gpr);
99 m_jit.jitAssertIsInt32(gpr);
100 returnFormat = DataFormatInteger;
101 return gpr;
102 }
103 }
104
105 ASSERT_NOT_REACHED();
106 return InvalidGPRReg;
107}
108
109FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
110{
111 Node& node = at(nodeIndex);
112 VirtualRegister virtualRegister = node.virtualRegister();
113 GenerationInfo& info = m_generationInfo[virtualRegister];
114
115 if (info.registerFormat() == DataFormatNone) {
116
117 if (node.hasConstant()) {
118 if (isInt32Constant(nodeIndex)) {
119 // FIXME: should not be reachable?
120 GPRReg gpr = allocate();
121 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
122 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
123 info.fillInteger(gpr);
124 unlock(gpr);
125 } else if (isNumberConstant(nodeIndex)) {
126 FPRReg fpr = fprAllocate();
127 m_jit.loadDouble(addressOfDoubleConstant(nodeIndex), fpr);
128 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
129 info.fillDouble(fpr);
130 return fpr;
131 } else {
132 // FIXME: should not be reachable?
133 ASSERT_NOT_REACHED();
134 }
135 } else {
136 DataFormat spillFormat = info.spillFormat();
137 ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatInteger);
138 if (spillFormat == DataFormatJSDouble) {
139 FPRReg fpr = fprAllocate();
140 m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
141 m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
142 info.fillDouble(fpr);
143 return fpr;
144 }
145
146 FPRReg fpr = fprAllocate();
147 JITCompiler::Jump hasUnboxedDouble;
148
149 if (spillFormat != DataFormatJSInteger && spillFormat != DataFormatInteger) {
150 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag));
151 m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
152 hasUnboxedDouble = m_jit.jump();
153 isInteger.link(&m_jit);
154 }
155
156 m_jit.convertInt32ToDouble(JITCompiler::payloadFor(virtualRegister), fpr);
157
158 if (hasUnboxedDouble.isSet())
159 hasUnboxedDouble.link(&m_jit);
160
161 m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
162 info.fillDouble(fpr);
163 return fpr;
164 }
165 }
166
167 switch (info.registerFormat()) {
168 case DataFormatNone:
169 // Should have filled, above.
170 case DataFormatCell:
171 case DataFormatJSCell:
172 case DataFormatBoolean:
173 case DataFormatJSBoolean:
174 case DataFormatStorage:
175 // Should only be calling this function if we know this operand to be numeric.
176 ASSERT_NOT_REACHED();
177
178 case DataFormatJSInteger:
179 case DataFormatJS: {
180 GPRReg tagGPR = info.tagGPR();
181 GPRReg payloadGPR = info.payloadGPR();
182 FPRReg fpr = fprAllocate();
183 m_gprs.lock(tagGPR);
184 m_gprs.lock(payloadGPR);
185
186 JITCompiler::Jump hasUnboxedDouble;
187
188 if (info.registerFormat() != DataFormatJSInteger) {
189 FPRTemporary scratch(this);
190 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag));
191 m_jit.jitAssertIsJSDouble(tagGPR);
192 unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr());
193 hasUnboxedDouble = m_jit.jump();
194 isInteger.link(&m_jit);
195 }
196
197 m_jit.convertInt32ToDouble(payloadGPR, fpr);
198
199 if (hasUnboxedDouble.isSet())
200 hasUnboxedDouble.link(&m_jit);
201
202 m_gprs.release(tagGPR);
203 m_gprs.release(payloadGPR);
204 m_gprs.unlock(tagGPR);
205 m_gprs.unlock(payloadGPR);
206 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
207 info.fillDouble(fpr);
208 info.killSpilled();
209 return fpr;
210 }
211
212 case DataFormatInteger: {
213 FPRReg fpr = fprAllocate();
214 GPRReg gpr = info.gpr();
215 m_gprs.lock(gpr);
216 m_jit.convertInt32ToDouble(gpr, fpr);
217 m_gprs.unlock(gpr);
218 return fpr;
219 }
220
221 case DataFormatJSDouble:
222 case DataFormatDouble: {
223 FPRReg fpr = info.fpr();
224 m_fprs.lock(fpr);
225 return fpr;
226 }
227 }
228
229 ASSERT_NOT_REACHED();
230 return InvalidFPRReg;
231}
232
233bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& payloadGPR, FPRReg& fpr)
234{
235 // FIXME: For double we could fill with a FPR.
236 UNUSED_PARAM(fpr);
237
238 Node& node = at(nodeIndex);
239 VirtualRegister virtualRegister = node.virtualRegister();
240 GenerationInfo& info = m_generationInfo[virtualRegister];
241
242 switch (info.registerFormat()) {
243 case DataFormatNone: {
244
245 if (node.hasConstant()) {
246 tagGPR = allocate();
247 payloadGPR = allocate();
248 m_jit.move(Imm32(valueOfJSConstant(nodeIndex).tag()), tagGPR);
249 m_jit.move(Imm32(valueOfJSConstant(nodeIndex).payload()), payloadGPR);
250 m_gprs.retain(tagGPR, virtualRegister, SpillOrderConstant);
251 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderConstant);
252 info.fillJSValue(tagGPR, payloadGPR, isInt32Constant(nodeIndex) ? DataFormatJSInteger : DataFormatJS);
253 } else {
254 DataFormat spillFormat = info.spillFormat();
255 ASSERT(spillFormat != DataFormatNone && spillFormat != DataFormatStorage);
256 tagGPR = allocate();
257 payloadGPR = allocate();
258 switch (spillFormat) {
259 case DataFormatInteger:
260 m_jit.move(TrustedImm32(JSValue::Int32Tag), tagGPR);
261 spillFormat = DataFormatJSInteger; // This will be used as the new register format.
262 break;
263 case DataFormatCell:
264 m_jit.move(TrustedImm32(JSValue::CellTag), tagGPR);
265 spillFormat = DataFormatJSCell; // This will be used as the new register format.
266 break;
267 case DataFormatBoolean:
268 m_jit.move(TrustedImm32(JSValue::BooleanTag), tagGPR);
269 spillFormat = DataFormatJSBoolean; // This will be used as the new register format.
270 break;
271 default:
272 m_jit.load32(JITCompiler::tagFor(virtualRegister), tagGPR);
273 break;
274 }
275 m_jit.load32(JITCompiler::payloadFor(virtualRegister), payloadGPR);
276 m_gprs.retain(tagGPR, virtualRegister, SpillOrderSpilled);
277 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderSpilled);
278 info.fillJSValue(tagGPR, payloadGPR, spillFormat == DataFormatJSDouble ? DataFormatJS : spillFormat);
279 }
280
281 return true;
282 }
283
284 case DataFormatInteger:
285 case DataFormatCell:
286 case DataFormatBoolean: {
287 GPRReg gpr = info.gpr();
288 // If the register has already been locked we need to take a copy.
289 if (m_gprs.isLocked(gpr)) {
290 payloadGPR = allocate();
291 m_jit.move(gpr, payloadGPR);
292 } else {
293 payloadGPR = gpr;
294 m_gprs.lock(gpr);
295 }
296 tagGPR = allocate();
297 uint32_t tag = JSValue::EmptyValueTag;
298 DataFormat fillFormat = DataFormatJS;
299 switch (info.registerFormat()) {
300 case DataFormatInteger:
301 tag = JSValue::Int32Tag;
302 fillFormat = DataFormatJSInteger;
303 break;
304 case DataFormatCell:
305 tag = JSValue::CellTag;
306 fillFormat = DataFormatJSCell;
307 break;
308 case DataFormatBoolean:
309 tag = JSValue::BooleanTag;
310 fillFormat = DataFormatJSBoolean;
311 break;
312 default:
313 ASSERT_NOT_REACHED();
314 break;
315 }
316 m_jit.move(TrustedImm32(tag), tagGPR);
317 m_gprs.release(gpr);
318 m_gprs.retain(tagGPR, virtualRegister, SpillOrderJS);
319 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderJS);
320 info.fillJSValue(tagGPR, payloadGPR, fillFormat);
321 return true;
322 }
323
324 case DataFormatJSDouble:
325 case DataFormatDouble: {
326 FPRReg oldFPR = info.fpr();
327 m_fprs.lock(oldFPR);
328 tagGPR = allocate();
329 payloadGPR = allocate();
330 boxDouble(oldFPR, tagGPR, payloadGPR);
331 m_fprs.unlock(oldFPR);
332 m_fprs.release(oldFPR);
333 m_gprs.retain(tagGPR, virtualRegister, SpillOrderJS);
334 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderJS);
335 info.fillJSValue(tagGPR, payloadGPR, DataFormatJS);
336 return true;
337 }
338
339 case DataFormatJS:
340 case DataFormatJSInteger:
341 case DataFormatJSCell:
342 case DataFormatJSBoolean: {
343 tagGPR = info.tagGPR();
344 payloadGPR = info.payloadGPR();
345 m_gprs.lock(tagGPR);
346 m_gprs.lock(payloadGPR);
347 return true;
348 }
349
350 case DataFormatStorage:
351 // this type currently never occurs
352 ASSERT_NOT_REACHED();
353 }
354
355 ASSERT_NOT_REACHED();
356 return true;
357}
358
359void SpeculativeJIT::nonSpeculativeValueToNumber(Node& node)
360{
361 if (isKnownNumeric(node.child1().index())) {
362 JSValueOperand op1(this, node.child1());
363 op1.fill();
364 if (op1.isDouble()) {
365 FPRTemporary result(this, op1);
366 m_jit.moveDouble(op1.fpr(), result.fpr());
367 doubleResult(result.fpr(), m_compileIndex);
368 } else {
369 GPRTemporary resultTag(this, op1);
370 GPRTemporary resultPayload(this, op1, false);
371 m_jit.move(op1.tagGPR(), resultTag.gpr());
372 m_jit.move(op1.payloadGPR(), resultPayload.gpr());
373 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
374 }
375 return;
376 }
377
378 JSValueOperand op1(this, node.child1());
379 GPRTemporary resultTag(this, op1);
380 GPRTemporary resultPayload(this, op1, false);
381
382 ASSERT(!isInt32Constant(node.child1().index()));
383 ASSERT(!isNumberConstant(node.child1().index()));
384
385 GPRReg tagGPR = op1.tagGPR();
386 GPRReg payloadGPR = op1.payloadGPR();
387 GPRReg resultTagGPR = resultTag.gpr();
388 GPRReg resultPayloadGPR = resultPayload.gpr();
389 op1.use();
390
391 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag));
392 JITCompiler::Jump nonNumeric = m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag));
393
394 // First, if we get here we have a double encoded as a JSValue
395 JITCompiler::Jump hasUnboxedDouble = m_jit.jump();
396
397 // Next handle cells (& other JS immediates)
398 nonNumeric.link(&m_jit);
399 silentSpillAllRegisters(resultTagGPR, resultPayloadGPR);
400 callOperation(dfgConvertJSValueToNumber, FPRInfo::returnValueFPR, tagGPR, payloadGPR);
401 boxDouble(FPRInfo::returnValueFPR, resultTagGPR, resultPayloadGPR);
402 silentFillAllRegisters(resultTagGPR, resultPayloadGPR);
403 JITCompiler::Jump hasCalledToNumber = m_jit.jump();
404
405 // Finally, handle integers.
406 isInteger.link(&m_jit);
407 hasUnboxedDouble.link(&m_jit);
408 m_jit.move(tagGPR, resultTagGPR);
409 m_jit.move(payloadGPR, resultPayloadGPR);
410 hasCalledToNumber.link(&m_jit);
411 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
412}
413
414void SpeculativeJIT::nonSpeculativeValueToInt32(Node& node)
415{
416 ASSERT(!isInt32Constant(node.child1().index()));
417
418 if (isKnownInteger(node.child1().index())) {
419 IntegerOperand op1(this, node.child1());
420 GPRTemporary result(this, op1);
421 m_jit.move(op1.gpr(), result.gpr());
422 integerResult(result.gpr(), m_compileIndex);
423 return;
424 }
425
426 GenerationInfo& childInfo = m_generationInfo[at(node.child1()).virtualRegister()];
427 if (childInfo.isJSDouble()) {
428 DoubleOperand op1(this, node.child1());
429 GPRTemporary result(this);
430 FPRReg fpr = op1.fpr();
431 GPRReg gpr = result.gpr();
432 op1.use();
433 JITCompiler::Jump truncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateSuccessful);
434
435 silentSpillAllRegisters(gpr);
436 callOperation(toInt32, gpr, fpr);
437 silentFillAllRegisters(gpr);
438
439 truncatedToInteger.link(&m_jit);
440 integerResult(gpr, m_compileIndex, UseChildrenCalledExplicitly);
441 return;
442 }
443
444 JSValueOperand op1(this, node.child1());
445 GPRTemporary result(this);
446 GPRReg tagGPR = op1.tagGPR();
447 GPRReg payloadGPR = op1.payloadGPR();
448 GPRReg resultGPR = result.gpr();
449 op1.use();
450
451 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag));
452
453 // First handle non-integers
454 silentSpillAllRegisters(resultGPR);
455 callOperation(dfgConvertJSValueToInt32, GPRInfo::returnValueGPR, tagGPR, payloadGPR);
456 m_jit.move(GPRInfo::returnValueGPR, resultGPR);
457 silentFillAllRegisters(resultGPR);
458 JITCompiler::Jump hasCalledToInt32 = m_jit.jump();
459
460 // Then handle integers.
461 isInteger.link(&m_jit);
462 m_jit.move(payloadGPR, resultGPR);
463 hasCalledToInt32.link(&m_jit);
464 integerResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
465}
466
467void SpeculativeJIT::nonSpeculativeUInt32ToNumber(Node& node)
468{
469 IntegerOperand op1(this, node.child1());
470 FPRTemporary boxer(this);
471 GPRTemporary resultTag(this, op1);
472 GPRTemporary resultPayload(this);
473
474 JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, op1.gpr(), TrustedImm32(0));
475
476 m_jit.convertInt32ToDouble(op1.gpr(), boxer.fpr());
477 m_jit.move(JITCompiler::TrustedImmPtr(&AssemblyHelpers::twoToThe32), resultPayload.gpr()); // reuse resultPayload register here.
478 m_jit.addDouble(JITCompiler::Address(resultPayload.gpr(), 0), boxer.fpr());
479
480 boxDouble(boxer.fpr(), resultTag.gpr(), resultPayload.gpr());
481
482 JITCompiler::Jump done = m_jit.jump();
483
484 positive.link(&m_jit);
485
486 m_jit.move(TrustedImm32(JSValue::Int32Tag), resultTag.gpr());
487 m_jit.move(op1.gpr(), resultPayload.gpr());
488
489 done.link(&m_jit);
490
491 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
492}
493
494JITCompiler::Call SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
495{
496 JITCompiler::DataLabelPtr structureToCompare;
497 JITCompiler::PatchableJump structureCheck = m_jit.patchableBranchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(basePayloadGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
498
499 m_jit.loadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfPropertyStorage()), resultPayloadGPR);
500 JITCompiler::DataLabelCompact tagLoadWithPatch = m_jit.load32WithCompactAddressOffsetPatch(JITCompiler::Address(resultPayloadGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
501 JITCompiler::DataLabelCompact payloadLoadWithPatch = m_jit.load32WithCompactAddressOffsetPatch(JITCompiler::Address(resultPayloadGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
502
503 JITCompiler::Jump done = m_jit.jump();
504
505 structureCheck.m_jump.link(&m_jit);
506
507 if (slowPathTarget.isSet())
508 slowPathTarget.link(&m_jit);
509
510 JITCompiler::Label slowCase = m_jit.label();
511
512 if (spillMode == NeedToSpill)
513 silentSpillAllRegisters(resultTagGPR, resultPayloadGPR);
514 JITCompiler::Call functionCall;
515 if (baseTagGPROrNone == InvalidGPRReg)
516 functionCall = callOperation(operationGetByIdOptimize, resultTagGPR, resultPayloadGPR, JSValue::CellTag, basePayloadGPR, identifier(identifierNumber));
517 else
518 functionCall = callOperation(operationGetByIdOptimize, resultTagGPR, resultPayloadGPR, baseTagGPROrNone, basePayloadGPR, identifier(identifierNumber));
519 if (spillMode == NeedToSpill)
520 silentFillAllRegisters(resultTagGPR, resultPayloadGPR);
521
522 done.link(&m_jit);
523
524 JITCompiler::Label doneLabel = m_jit.label();
525
526 m_jit.addPropertyAccess(PropertyAccessRecord(codeOrigin, structureToCompare, functionCall, structureCheck, tagLoadWithPatch, payloadLoadWithPatch, slowCase, doneLabel, safeCast<int8_t>(basePayloadGPR), safeCast<int8_t>(resultTagGPR), safeCast<int8_t>(resultPayloadGPR), safeCast<int8_t>(scratchGPR), spillMode == NeedToSpill ? PropertyAccessRecord::RegistersInUse : PropertyAccessRecord::RegistersFlushed));
527
528 return functionCall;
529}
530
531void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, Edge valueUse, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget)
532{
533 JITCompiler::DataLabelPtr structureToCompare;
534 JITCompiler::PatchableJump structureCheck = m_jit.patchableBranchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(basePayloadGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
535
536 writeBarrier(basePayloadGPR, valueTagGPR, valueUse, WriteBarrierForPropertyAccess, scratchGPR);
537
538 m_jit.loadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
539 JITCompiler::DataLabel32 tagStoreWithPatch = m_jit.store32WithAddressOffsetPatch(valueTagGPR, JITCompiler::Address(scratchGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
540 JITCompiler::DataLabel32 payloadStoreWithPatch = m_jit.store32WithAddressOffsetPatch(valuePayloadGPR, JITCompiler::Address(scratchGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
541
542 JITCompiler::Jump done = m_jit.jump();
543
544 structureCheck.m_jump.link(&m_jit);
545
546 if (slowPathTarget.isSet())
547 slowPathTarget.link(&m_jit);
548
549 JITCompiler::Label slowCase = m_jit.label();
550
551 silentSpillAllRegisters(InvalidGPRReg);
552 V_DFGOperation_EJCI optimizedCall;
553 if (m_jit.strictModeFor(at(m_compileIndex).codeOrigin)) {
554 if (putKind == Direct)
555 optimizedCall = operationPutByIdDirectStrictOptimize;
556 else
557 optimizedCall = operationPutByIdStrictOptimize;
558 } else {
559 if (putKind == Direct)
560 optimizedCall = operationPutByIdDirectNonStrictOptimize;
561 else
562 optimizedCall = operationPutByIdNonStrictOptimize;
563 }
564 JITCompiler::Call functionCall = callOperation(optimizedCall, valueTagGPR, valuePayloadGPR, basePayloadGPR, identifier(identifierNumber));
565 silentFillAllRegisters(InvalidGPRReg);
566
567 done.link(&m_jit);
568 JITCompiler::Label doneLabel = m_jit.label();
569
570 m_jit.addPropertyAccess(PropertyAccessRecord(codeOrigin, structureToCompare, functionCall, structureCheck, JITCompiler::DataLabelCompact(tagStoreWithPatch.label()), JITCompiler::DataLabelCompact(payloadStoreWithPatch.label()), slowCase, doneLabel, safeCast<int8_t>(basePayloadGPR), safeCast<int8_t>(valueTagGPR), safeCast<int8_t>(valuePayloadGPR), safeCast<int8_t>(scratchGPR)));
571}
572
573void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool invert)
574{
575 JSValueOperand arg(this, operand);
576 GPRReg argTagGPR = arg.tagGPR();
577 GPRReg argPayloadGPR = arg.payloadGPR();
578
579 GPRTemporary resultPayload(this, arg, false);
580 GPRReg resultPayloadGPR = resultPayload.gpr();
581
582 JITCompiler::Jump notCell;
583 if (!isKnownCell(operand.index()))
584 notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
585
586 m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureOffset()), resultPayloadGPR);
587 m_jit.test8(invert ? JITCompiler::Zero : JITCompiler::NonZero, JITCompiler::Address(resultPayloadGPR, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined), resultPayloadGPR);
588
589 if (!isKnownCell(operand.index())) {
590 JITCompiler::Jump done = m_jit.jump();
591
592 notCell.link(&m_jit);
593 // null or undefined?
594 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
595 m_jit.move(argTagGPR, resultPayloadGPR);
596 m_jit.or32(TrustedImm32(1), resultPayloadGPR);
597 m_jit.compare32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultPayloadGPR, TrustedImm32(JSValue::NullTag), resultPayloadGPR);
598
599 done.link(&m_jit);
600 }
601
602 booleanResult(resultPayloadGPR, m_compileIndex);
603}
604
605void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, NodeIndex branchNodeIndex, bool invert)
606{
607 Node& branchNode = at(branchNodeIndex);
608 BlockIndex taken = branchNode.takenBlockIndex();
609 BlockIndex notTaken = branchNode.notTakenBlockIndex();
610
611 if (taken == (m_block + 1)) {
612 invert = !invert;
613 BlockIndex tmp = taken;
614 taken = notTaken;
615 notTaken = tmp;
616 }
617
618 JSValueOperand arg(this, operand);
619 GPRReg argTagGPR = arg.tagGPR();
620 GPRReg argPayloadGPR = arg.payloadGPR();
621
622 GPRTemporary result(this, arg);
623 GPRReg resultGPR = result.gpr();
624
625 JITCompiler::Jump notCell;
626
627 if (!isKnownCell(operand.index()))
628 notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
629
630 m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureOffset()), resultGPR);
631 branchTest8(invert ? JITCompiler::Zero : JITCompiler::NonZero, JITCompiler::Address(resultGPR, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined), taken);
632
633 if (!isKnownCell(operand.index())) {
634 jump(notTaken, ForceJump);
635
636 notCell.link(&m_jit);
637 // null or undefined?
638 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
639 m_jit.move(argTagGPR, resultGPR);
640 m_jit.or32(TrustedImm32(1), resultGPR);
641 branch32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultGPR, JITCompiler::TrustedImm32(JSValue::NullTag), taken);
642 }
643
644 jump(notTaken);
645}
646
647bool SpeculativeJIT::nonSpeculativeCompareNull(Node& node, Edge operand, bool invert)
648{
649 unsigned branchIndexInBlock = detectPeepHoleBranch();
650 if (branchIndexInBlock != UINT_MAX) {
651 NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
652
653 ASSERT(node.adjustedRefCount() == 1);
654
655 nonSpeculativePeepholeBranchNull(operand, branchNodeIndex, invert);
656
657 use(node.child1());
658 use(node.child2());
659 m_indexInBlock = branchIndexInBlock;
660 m_compileIndex = branchNodeIndex;
661
662 return true;
663 }
664
665 nonSpeculativeNonPeepholeCompareNull(operand, invert);
666
667 return false;
668}
669
670void SpeculativeJIT::nonSpeculativePeepholeBranch(Node& node, NodeIndex branchNodeIndex, MacroAssembler::RelationalCondition cond, S_DFGOperation_EJJ helperFunction)
671{
672 Node& branchNode = at(branchNodeIndex);
673 BlockIndex taken = branchNode.takenBlockIndex();
674 BlockIndex notTaken = branchNode.notTakenBlockIndex();
675
676 JITCompiler::ResultCondition callResultCondition = JITCompiler::NonZero;
677
678 // The branch instruction will branch to the taken block.
679 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
680 if (taken == (m_block + 1)) {
681 cond = JITCompiler::invert(cond);
682 callResultCondition = JITCompiler::Zero;
683 BlockIndex tmp = taken;
684 taken = notTaken;
685 notTaken = tmp;
686 }
687
688 JSValueOperand arg1(this, node.child1());
689 JSValueOperand arg2(this, node.child2());
690 GPRReg arg1TagGPR = arg1.tagGPR();
691 GPRReg arg1PayloadGPR = arg1.payloadGPR();
692 GPRReg arg2TagGPR = arg2.tagGPR();
693 GPRReg arg2PayloadGPR = arg2.payloadGPR();
694
695 JITCompiler::JumpList slowPath;
696
697 if (isKnownNotInteger(node.child1().index()) || isKnownNotInteger(node.child2().index())) {
698 GPRResult result(this);
699 GPRReg resultGPR = result.gpr();
700
701 arg1.use();
702 arg2.use();
703
704 flushRegisters();
705 callOperation(helperFunction, resultGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
706
707 branchTest32(callResultCondition, resultGPR, taken);
708 } else {
709 GPRTemporary result(this);
710 GPRReg resultGPR = result.gpr();
711
712 arg1.use();
713 arg2.use();
714
715 if (!isKnownInteger(node.child1().index()))
716 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg1TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
717 if (!isKnownInteger(node.child2().index()))
718 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg2TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
719
720 branch32(cond, arg1PayloadGPR, arg2PayloadGPR, taken);
721
722 if (!isKnownInteger(node.child1().index()) || !isKnownInteger(node.child2().index())) {
723 jump(notTaken, ForceJump);
724
725 slowPath.link(&m_jit);
726
727 silentSpillAllRegisters(resultGPR);
728 callOperation(helperFunction, resultGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
729 silentFillAllRegisters(resultGPR);
730
731 branchTest32(callResultCondition, resultGPR, taken);
732 }
733 }
734
735 jump(notTaken);
736
737 m_indexInBlock = m_jit.graph().m_blocks[m_block]->size() - 1;
738 m_compileIndex = branchNodeIndex;
739}
740
741void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node& node, MacroAssembler::RelationalCondition cond, S_DFGOperation_EJJ helperFunction)
742{
743 JSValueOperand arg1(this, node.child1());
744 JSValueOperand arg2(this, node.child2());
745 GPRReg arg1TagGPR = arg1.tagGPR();
746 GPRReg arg1PayloadGPR = arg1.payloadGPR();
747 GPRReg arg2TagGPR = arg2.tagGPR();
748 GPRReg arg2PayloadGPR = arg2.payloadGPR();
749
750 JITCompiler::JumpList slowPath;
751
752 if (isKnownNotInteger(node.child1().index()) || isKnownNotInteger(node.child2().index())) {
753 GPRResult result(this);
754 GPRReg resultPayloadGPR = result.gpr();
755
756 arg1.use();
757 arg2.use();
758
759 flushRegisters();
760 callOperation(helperFunction, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
761
762 booleanResult(resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
763 } else {
764 GPRTemporary resultPayload(this, arg1, false);
765 GPRReg resultPayloadGPR = resultPayload.gpr();
766
767 arg1.use();
768 arg2.use();
769
770 if (!isKnownInteger(node.child1().index()))
771 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg1TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
772 if (!isKnownInteger(node.child2().index()))
773 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg2TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
774
775 m_jit.compare32(cond, arg1PayloadGPR, arg2PayloadGPR, resultPayloadGPR);
776
777 if (!isKnownInteger(node.child1().index()) || !isKnownInteger(node.child2().index())) {
778 JITCompiler::Jump haveResult = m_jit.jump();
779
780 slowPath.link(&m_jit);
781
782 silentSpillAllRegisters(resultPayloadGPR);
783 callOperation(helperFunction, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
784 silentFillAllRegisters(resultPayloadGPR);
785
786 m_jit.andPtr(TrustedImm32(1), resultPayloadGPR);
787
788 haveResult.link(&m_jit);
789 }
790
791 booleanResult(resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
792 }
793}
794
795void SpeculativeJIT::nonSpeculativePeepholeStrictEq(Node& node, NodeIndex branchNodeIndex, bool invert)
796{
797 Node& branchNode = at(branchNodeIndex);
798 BlockIndex taken = branchNode.takenBlockIndex();
799 BlockIndex notTaken = branchNode.notTakenBlockIndex();
800
801 // The branch instruction will branch to the taken block.
802 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
803 if (taken == (m_block + 1)) {
804 invert = !invert;
805 BlockIndex tmp = taken;
806 taken = notTaken;
807 notTaken = tmp;
808 }
809
810 JSValueOperand arg1(this, node.child1());
811 JSValueOperand arg2(this, node.child2());
812 GPRReg arg1TagGPR = arg1.tagGPR();
813 GPRReg arg1PayloadGPR = arg1.payloadGPR();
814 GPRReg arg2TagGPR = arg2.tagGPR();
815 GPRReg arg2PayloadGPR = arg2.payloadGPR();
816
817 GPRTemporary resultPayload(this, arg1, false);
818 GPRReg resultPayloadGPR = resultPayload.gpr();
819
820 arg1.use();
821 arg2.use();
822
823 if (isKnownCell(node.child1().index()) && isKnownCell(node.child2().index())) {
824 // see if we get lucky: if the arguments are cells and they reference the same
825 // cell, then they must be strictly equal.
826 branchPtr(JITCompiler::Equal, arg1PayloadGPR, arg2PayloadGPR, invert ? notTaken : taken);
827
828 silentSpillAllRegisters(resultPayloadGPR);
829 callOperation(operationCompareStrictEqCell, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
830 silentFillAllRegisters(resultPayloadGPR);
831
832 branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, resultPayloadGPR, taken);
833 } else {
834 // FIXME: Add fast paths for twoCells, number etc.
835
836 silentSpillAllRegisters(resultPayloadGPR);
837 callOperation(operationCompareStrictEq, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
838 silentFillAllRegisters(resultPayloadGPR);
839
840 branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, resultPayloadGPR, taken);
841 }
842
843 jump(notTaken);
844}
845
846void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node& node, bool invert)
847{
848 JSValueOperand arg1(this, node.child1());
849 JSValueOperand arg2(this, node.child2());
850 GPRReg arg1TagGPR = arg1.tagGPR();
851 GPRReg arg1PayloadGPR = arg1.payloadGPR();
852 GPRReg arg2TagGPR = arg2.tagGPR();
853 GPRReg arg2PayloadGPR = arg2.payloadGPR();
854
855 GPRTemporary resultPayload(this, arg1, false);
856 GPRReg resultPayloadGPR = resultPayload.gpr();
857
858 arg1.use();
859 arg2.use();
860
861 if (isKnownCell(node.child1().index()) && isKnownCell(node.child2().index())) {
862 // see if we get lucky: if the arguments are cells and they reference the same
863 // cell, then they must be strictly equal.
864 JITCompiler::Jump notEqualCase = m_jit.branchPtr(JITCompiler::NotEqual, arg1PayloadGPR, arg2PayloadGPR);
865
866 m_jit.move(JITCompiler::TrustedImm32(!invert), resultPayloadGPR);
867 JITCompiler::Jump done = m_jit.jump();
868
869 notEqualCase.link(&m_jit);
870
871 silentSpillAllRegisters(resultPayloadGPR);
872 callOperation(operationCompareStrictEqCell, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
873 silentFillAllRegisters(resultPayloadGPR);
874
875 m_jit.andPtr(JITCompiler::TrustedImm32(1), resultPayloadGPR);
876
877 done.link(&m_jit);
878 } else {
879 // FIXME: Add fast paths.
880
881 silentSpillAllRegisters(resultPayloadGPR);
882 callOperation(operationCompareStrictEq, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
883 silentFillAllRegisters(resultPayloadGPR);
884
885 m_jit.andPtr(JITCompiler::TrustedImm32(1), resultPayloadGPR);
886 }
887
888 booleanResult(resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
889}
890
891void SpeculativeJIT::emitCall(Node& node)
892{
893 P_DFGOperation_E slowCallFunction;
894
895 if (node.op() == Call)
896 slowCallFunction = operationLinkCall;
897 else {
898 ASSERT(node.op() == Construct);
899 slowCallFunction = operationLinkConstruct;
900 }
901
902 // For constructors, the this argument is not passed but we have to make space
903 // for it.
904 int dummyThisArgument = node.op() == Call ? 0 : 1;
905
906 CallLinkInfo::CallType callType = node.op() == Call ? CallLinkInfo::Call : CallLinkInfo::Construct;
907
908 Edge calleeEdge = m_jit.graph().m_varArgChildren[node.firstChild()];
909 JSValueOperand callee(this, calleeEdge);
910 GPRReg calleeTagGPR = callee.tagGPR();
911 GPRReg calleePayloadGPR = callee.payloadGPR();
912 use(calleeEdge);
913
914 // The call instruction's first child is either the function (normal call) or the
915 // receiver (method call). subsequent children are the arguments.
916 int numPassedArgs = node.numChildren() - 1;
917
918 m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs + dummyThisArgument), callFramePayloadSlot(RegisterFile::ArgumentCount));
919 m_jit.storePtr(GPRInfo::callFrameRegister, callFramePayloadSlot(RegisterFile::CallerFrame));
920 m_jit.store32(calleePayloadGPR, callFramePayloadSlot(RegisterFile::Callee));
921 m_jit.store32(calleeTagGPR, callFrameTagSlot(RegisterFile::Callee));
922
923 for (int i = 0; i < numPassedArgs; i++) {
924 Edge argEdge = m_jit.graph().m_varArgChildren[node.firstChild() + 1 + i];
925 JSValueOperand arg(this, argEdge);
926 GPRReg argTagGPR = arg.tagGPR();
927 GPRReg argPayloadGPR = arg.payloadGPR();
928 use(argEdge);
929
930 m_jit.store32(argTagGPR, argumentTagSlot(i + dummyThisArgument));
931 m_jit.store32(argPayloadGPR, argumentPayloadSlot(i + dummyThisArgument));
932 }
933
934 flushRegisters();
935
936 GPRResult resultPayload(this);
937 GPRResult2 resultTag(this);
938 GPRReg resultPayloadGPR = resultPayload.gpr();
939 GPRReg resultTagGPR = resultTag.gpr();
940
941 JITCompiler::DataLabelPtr targetToCheck;
942 JITCompiler::JumpList slowPath;
943
944 slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
945 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, calleeTagGPR, TrustedImm32(JSValue::CellTag)));
946 m_jit.loadPtr(MacroAssembler::Address(calleePayloadGPR, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), resultPayloadGPR);
947 m_jit.storePtr(resultPayloadGPR, callFramePayloadSlot(RegisterFile::ScopeChain));
948 m_jit.store32(MacroAssembler::TrustedImm32(JSValue::CellTag), callFrameTagSlot(RegisterFile::ScopeChain));
949
950 m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
951
952 CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin;
953 CallBeginToken token = m_jit.beginCall();
954 JITCompiler::Call fastCall = m_jit.nearCall();
955 m_jit.notifyCall(fastCall, codeOrigin, token);
956
957 JITCompiler::Jump done = m_jit.jump();
958
959 slowPath.link(&m_jit);
960
961 m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
962 m_jit.poke(GPRInfo::argumentGPR0);
963 token = m_jit.beginCall();
964 JITCompiler::Call slowCall = m_jit.appendCall(slowCallFunction);
965 m_jit.addFastExceptionCheck(slowCall, codeOrigin, token);
966 m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
967 token = m_jit.beginCall();
968 JITCompiler::Call theCall = m_jit.call(GPRInfo::returnValueGPR);
969 m_jit.notifyCall(theCall, codeOrigin, token);
970
971 done.link(&m_jit);
972
973 m_jit.setupResults(resultPayloadGPR, resultTagGPR);
974
975 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, DataFormatJS, UseChildrenCalledExplicitly);
976
977 m_jit.addJSCall(fastCall, slowCall, targetToCheck, callType, at(m_compileIndex).codeOrigin);
978}
979
980template<bool strict>
981GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& returnFormat)
982{
983#if DFG_ENABLE(DEBUG_VERBOSE)
984 dataLog("SpecInt@%d ", nodeIndex);
985#endif
986 if (isKnownNotInteger(nodeIndex)) {
987 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
988 returnFormat = DataFormatInteger;
989 return allocate();
990 }
991
992 Node& node = at(nodeIndex);
993 VirtualRegister virtualRegister = node.virtualRegister();
994 GenerationInfo& info = m_generationInfo[virtualRegister];
995
996 switch (info.registerFormat()) {
997 case DataFormatNone: {
998
999 if (node.hasConstant()) {
1000 ASSERT(isInt32Constant(nodeIndex));
1001 GPRReg gpr = allocate();
1002 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
1003 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1004 info.fillInteger(gpr);
1005 returnFormat = DataFormatInteger;
1006 return gpr;
1007 }
1008
1009 DataFormat spillFormat = info.spillFormat();
1010 ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatInteger);
1011
1012 // If we know this was spilled as an integer we can fill without checking.
1013 if (spillFormat != DataFormatJSInteger && spillFormat != DataFormatInteger)
1014 speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)));
1015
1016 GPRReg gpr = allocate();
1017 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
1018 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
1019 info.fillInteger(gpr);
1020 returnFormat = DataFormatInteger;
1021 return gpr;
1022 }
1023
1024 case DataFormatJSInteger:
1025 case DataFormatJS: {
1026 // Check the value is an integer.
1027 GPRReg tagGPR = info.tagGPR();
1028 GPRReg payloadGPR = info.payloadGPR();
1029 m_gprs.lock(tagGPR);
1030 m_gprs.lock(payloadGPR);
1031 if (info.registerFormat() != DataFormatJSInteger)
1032 speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::Int32Tag)));
1033 m_gprs.unlock(tagGPR);
1034 m_gprs.release(tagGPR);
1035 m_gprs.release(payloadGPR);
1036 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderInteger);
1037 info.fillInteger(payloadGPR);
1038 // If !strict we're done, return.
1039 returnFormat = DataFormatInteger;
1040 return payloadGPR;
1041 }
1042
1043 case DataFormatInteger: {
1044 GPRReg gpr = info.gpr();
1045 m_gprs.lock(gpr);
1046 returnFormat = DataFormatInteger;
1047 return gpr;
1048 }
1049
1050 case DataFormatDouble:
1051 case DataFormatCell:
1052 case DataFormatBoolean:
1053 case DataFormatJSDouble:
1054 case DataFormatJSCell:
1055 case DataFormatJSBoolean:
1056 case DataFormatStorage:
1057 ASSERT_NOT_REACHED();
1058 }
1059
1060 ASSERT_NOT_REACHED();
1061 return InvalidGPRReg;
1062}
1063
1064GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat)
1065{
1066 return fillSpeculateIntInternal<false>(nodeIndex, returnFormat);
1067}
1068
1069GPRReg SpeculativeJIT::fillSpeculateIntStrict(NodeIndex nodeIndex)
1070{
1071 DataFormat mustBeDataFormatInteger;
1072 GPRReg result = fillSpeculateIntInternal<true>(nodeIndex, mustBeDataFormatInteger);
1073 ASSERT(mustBeDataFormatInteger == DataFormatInteger);
1074 return result;
1075}
1076
1077FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
1078{
1079#if DFG_ENABLE(DEBUG_VERBOSE)
1080 dataLog("SpecDouble@%d ", nodeIndex);
1081#endif
1082 if (isKnownNotNumber(nodeIndex)) {
1083 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
1084 return fprAllocate();
1085 }
1086
1087 Node& node = at(nodeIndex);
1088 VirtualRegister virtualRegister = node.virtualRegister();
1089 GenerationInfo& info = m_generationInfo[virtualRegister];
1090
1091 if (info.registerFormat() == DataFormatNone) {
1092
1093 if (node.hasConstant()) {
1094 if (isInt32Constant(nodeIndex)) {
1095 GPRReg gpr = allocate();
1096 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
1097 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1098 info.fillInteger(gpr);
1099 unlock(gpr);
1100 } else if (isNumberConstant(nodeIndex)) {
1101 FPRReg fpr = fprAllocate();
1102 m_jit.loadDouble(addressOfDoubleConstant(nodeIndex), fpr);
1103 m_fprs.retain(fpr, virtualRegister, SpillOrderConstant);
1104 info.fillDouble(fpr);
1105 return fpr;
1106 } else
1107 ASSERT_NOT_REACHED();
1108 } else {
1109 DataFormat spillFormat = info.spillFormat();
1110 ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatInteger);
1111 if (spillFormat == DataFormatJSDouble || spillFormat == DataFormatDouble) {
1112 FPRReg fpr = fprAllocate();
1113 m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
1114 m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
1115 info.fillDouble(fpr);
1116 return fpr;
1117 }
1118
1119 FPRReg fpr = fprAllocate();
1120 JITCompiler::Jump hasUnboxedDouble;
1121
1122 if (spillFormat != DataFormatJSInteger && spillFormat != DataFormatInteger) {
1123 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag));
1124 speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::AboveOrEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::LowestTag)));
1125 m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
1126 hasUnboxedDouble = m_jit.jump();
1127
1128 isInteger.link(&m_jit);
1129 }
1130
1131 m_jit.convertInt32ToDouble(JITCompiler::payloadFor(virtualRegister), fpr);
1132
1133 if (hasUnboxedDouble.isSet())
1134 hasUnboxedDouble.link(&m_jit);
1135
1136 m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
1137 info.fillDouble(fpr);
1138 info.killSpilled();
1139 return fpr;
1140 }
1141 }
1142
1143 switch (info.registerFormat()) {
1144 case DataFormatJS:
1145 case DataFormatJSInteger: {
1146 GPRReg tagGPR = info.tagGPR();
1147 GPRReg payloadGPR = info.payloadGPR();
1148 FPRReg fpr = fprAllocate();
1149
1150 m_gprs.lock(tagGPR);
1151 m_gprs.lock(payloadGPR);
1152
1153 JITCompiler::Jump hasUnboxedDouble;
1154
1155 if (info.registerFormat() != DataFormatJSInteger) {
1156 FPRTemporary scratch(this);
1157 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag));
1158 speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag)));
1159 unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr());
1160 hasUnboxedDouble = m_jit.jump();
1161 isInteger.link(&m_jit);
1162 }
1163
1164 m_jit.convertInt32ToDouble(payloadGPR, fpr);
1165
1166 if (hasUnboxedDouble.isSet())
1167 hasUnboxedDouble.link(&m_jit);
1168
1169 m_gprs.release(tagGPR);
1170 m_gprs.release(payloadGPR);
1171 m_gprs.unlock(tagGPR);
1172 m_gprs.unlock(payloadGPR);
1173 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
1174 info.fillDouble(fpr);
1175 info.killSpilled();
1176 return fpr;
1177 }
1178
1179 case DataFormatInteger: {
1180 FPRReg fpr = fprAllocate();
1181 GPRReg gpr = info.gpr();
1182 m_gprs.lock(gpr);
1183 m_jit.convertInt32ToDouble(gpr, fpr);
1184 m_gprs.unlock(gpr);
1185 return fpr;
1186 }
1187
1188 case DataFormatJSDouble:
1189 case DataFormatDouble: {
1190 FPRReg fpr = info.fpr();
1191 m_fprs.lock(fpr);
1192 return fpr;
1193 }
1194
1195 case DataFormatNone:
1196 case DataFormatStorage:
1197 case DataFormatCell:
1198 case DataFormatJSCell:
1199 case DataFormatBoolean:
1200 case DataFormatJSBoolean:
1201 ASSERT_NOT_REACHED();
1202 }
1203
1204 ASSERT_NOT_REACHED();
1205 return InvalidFPRReg;
1206}
1207
1208GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
1209{
1210#if DFG_ENABLE(DEBUG_VERBOSE)
1211 dataLog("SpecCell@%d ", nodeIndex);
1212#endif
1213 if (isKnownNotCell(nodeIndex)) {
1214 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
1215 return allocate();
1216 }
1217
1218 Node& node = at(nodeIndex);
1219 VirtualRegister virtualRegister = node.virtualRegister();
1220 GenerationInfo& info = m_generationInfo[virtualRegister];
1221
1222 switch (info.registerFormat()) {
1223 case DataFormatNone: {
1224
1225 if (node.hasConstant()) {
1226 JSValue jsValue = valueOfJSConstant(nodeIndex);
1227 ASSERT(jsValue.isCell());
1228 GPRReg gpr = allocate();
1229 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1230 m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr);
1231 info.fillCell(gpr);
1232 return gpr;
1233 }
1234
1235 ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatCell);
1236 if (info.spillFormat() != DataFormatJSCell && info.spillFormat() != DataFormatCell)
1237 speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag)));
1238 GPRReg gpr = allocate();
1239 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
1240 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
1241 info.fillCell(gpr);
1242 return gpr;
1243 }
1244
1245 case DataFormatCell: {
1246 GPRReg gpr = info.gpr();
1247 m_gprs.lock(gpr);
1248 return gpr;
1249 }
1250
1251 case DataFormatJSCell:
1252 case DataFormatJS: {
1253 GPRReg tagGPR = info.tagGPR();
1254 GPRReg payloadGPR = info.payloadGPR();
1255 m_gprs.lock(tagGPR);
1256 m_gprs.lock(payloadGPR);
1257 if (info.spillFormat() != DataFormatJSCell)
1258 speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::CellTag)));
1259 m_gprs.unlock(tagGPR);
1260 m_gprs.release(tagGPR);
1261 m_gprs.release(payloadGPR);
1262 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderCell);
1263 info.fillCell(payloadGPR);
1264 return payloadGPR;
1265 }
1266
1267 case DataFormatJSInteger:
1268 case DataFormatInteger:
1269 case DataFormatJSDouble:
1270 case DataFormatDouble:
1271 case DataFormatJSBoolean:
1272 case DataFormatBoolean:
1273 case DataFormatStorage:
1274 ASSERT_NOT_REACHED();
1275 }
1276
1277 ASSERT_NOT_REACHED();
1278 return InvalidGPRReg;
1279}
1280
1281GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
1282{
1283#if DFG_ENABLE(DEBUG_VERBOSE)
1284 dataLog("SpecBool@%d ", nodeIndex);
1285#endif
1286 Node& node = m_jit.graph()[nodeIndex];
1287 VirtualRegister virtualRegister = node.virtualRegister();
1288 GenerationInfo& info = m_generationInfo[virtualRegister];
1289 if ((node.hasConstant() && !valueOfJSConstant(nodeIndex).isBoolean())
1290 || !(info.isJSBoolean() || info.isUnknownJS())) {
1291 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
1292 return allocate();
1293 }
1294
1295 switch (info.registerFormat()) {
1296 case DataFormatNone: {
1297
1298 if (node.hasConstant()) {
1299 JSValue jsValue = valueOfJSConstant(nodeIndex);
1300 ASSERT(jsValue.isBoolean());
1301 GPRReg gpr = allocate();
1302 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1303 m_jit.move(MacroAssembler::TrustedImm32(jsValue.asBoolean()), gpr);
1304 info.fillBoolean(gpr);
1305 return gpr;
1306 }
1307
1308 ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatBoolean);
1309
1310 if (info.spillFormat() != DataFormatJSBoolean && info.spillFormat() != DataFormatBoolean)
1311 speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)));
1312
1313 GPRReg gpr = allocate();
1314 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
1315 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
1316 info.fillBoolean(gpr);
1317 return gpr;
1318 }
1319
1320 case DataFormatBoolean: {
1321 GPRReg gpr = info.gpr();
1322 m_gprs.lock(gpr);
1323 return gpr;
1324 }
1325
1326 case DataFormatJSBoolean:
1327 case DataFormatJS: {
1328 GPRReg tagGPR = info.tagGPR();
1329 GPRReg payloadGPR = info.payloadGPR();
1330 m_gprs.lock(tagGPR);
1331 m_gprs.lock(payloadGPR);
1332 if (info.registerFormat() != DataFormatJSBoolean)
1333 speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::BooleanTag)));
1334
1335 m_gprs.unlock(tagGPR);
1336 m_gprs.release(tagGPR);
1337 m_gprs.release(payloadGPR);
1338 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderBoolean);
1339 info.fillBoolean(payloadGPR);
1340 return payloadGPR;
1341 }
1342
1343 case DataFormatJSInteger:
1344 case DataFormatInteger:
1345 case DataFormatJSDouble:
1346 case DataFormatDouble:
1347 case DataFormatJSCell:
1348 case DataFormatCell:
1349 case DataFormatStorage:
1350 ASSERT_NOT_REACHED();
1351 }
1352
1353 ASSERT_NOT_REACHED();
1354 return InvalidGPRReg;
1355}
1356
1357JITCompiler::Jump SpeculativeJIT::convertToDouble(JSValueOperand& op, FPRReg result)
1358{
1359 FPRTemporary scratch(this);
1360
1361 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, op.tagGPR(), TrustedImm32(JSValue::Int32Tag));
1362 JITCompiler::Jump notNumber = m_jit.branch32(MacroAssembler::AboveOrEqual, op.payloadGPR(), TrustedImm32(JSValue::LowestTag));
1363
1364 unboxDouble(op.tagGPR(), op.payloadGPR(), result, scratch.fpr());
1365 JITCompiler::Jump done = m_jit.jump();
1366
1367 isInteger.link(&m_jit);
1368 m_jit.convertInt32ToDouble(op.payloadGPR(), result);
1369
1370 done.link(&m_jit);
1371
1372 return notNumber;
1373}
1374
1375void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInfo, PredictionChecker predictionCheck)
1376{
1377 SpeculateCellOperand op1(this, node.child1());
1378 SpeculateCellOperand op2(this, node.child2());
1379 GPRReg op1GPR = op1.gpr();
1380 GPRReg op2GPR = op2.gpr();
1381
1382 if (!predictionCheck(m_state.forNode(node.child1()).m_type))
1383 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
1384 if (!predictionCheck(m_state.forNode(node.child2()).m_type))
1385 speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
1386
1387 GPRTemporary resultPayload(this, op2);
1388 GPRReg resultPayloadGPR = resultPayload.gpr();
1389
1390 MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2GPR);
1391 m_jit.move(TrustedImm32(1), resultPayloadGPR);
1392 MacroAssembler::Jump done = m_jit.jump();
1393 falseCase.link(&m_jit);
1394 m_jit.move(TrustedImm32(0), resultPayloadGPR);
1395 done.link(&m_jit);
1396
1397 booleanResult(resultPayloadGPR, m_compileIndex);
1398}
1399
1400void SpeculativeJIT::compileObjectToObjectOrOtherEquality(
1401 Edge leftChild, Edge rightChild,
1402 const ClassInfo* classInfo, PredictionChecker predictionCheck)
1403{
1404 SpeculateCellOperand op1(this, leftChild);
1405 JSValueOperand op2(this, rightChild);
1406 GPRTemporary result(this);
1407
1408 GPRReg op1GPR = op1.gpr();
1409 GPRReg op2TagGPR = op2.tagGPR();
1410 GPRReg op2PayloadGPR = op2.payloadGPR();
1411 GPRReg resultGPR = result.gpr();
1412
1413 if (!predictionCheck(m_state.forNode(leftChild).m_type)) {
1414 speculationCheck(
1415 BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(),
1416 m_jit.branchPtr(
1417 MacroAssembler::NotEqual,
1418 MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()),
1419 MacroAssembler::TrustedImmPtr(classInfo)));
1420 }
1421
1422 // It seems that most of the time when programs do a == b where b may be either null/undefined
1423 // or an object, b is usually an object. Balance the branches to make that case fast.
1424 MacroAssembler::Jump rightNotCell =
1425 m_jit.branch32(MacroAssembler::NotEqual, op2TagGPR, TrustedImm32(JSValue::CellTag));
1426
1427 // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the
1428 // proof, when filtered on cell, demonstrates that we have an object of the desired type
1429 // (predictionCheck() will test for FinalObject or Array, currently), then we can skip the
1430 // speculation.
1431 if (!predictionCheck(m_state.forNode(rightChild).m_type & PredictCell)) {
1432 speculationCheck(
1433 BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(),
1434 m_jit.branchPtr(
1435 MacroAssembler::NotEqual,
1436 MacroAssembler::Address(op2PayloadGPR, JSCell::classInfoOffset()),
1437 MacroAssembler::TrustedImmPtr(classInfo)));
1438 }
1439
1440 // At this point we know that we can perform a straight-forward equality comparison on pointer
1441 // values because both left and right are pointers to objects that have no special equality
1442 // protocols.
1443 MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2PayloadGPR);
1444 MacroAssembler::Jump trueCase = m_jit.jump();
1445
1446 rightNotCell.link(&m_jit);
1447
1448 // We know that within this branch, rightChild must not be a cell. Check if that is enough to
1449 // prove that it is either null or undefined.
1450 if (!isOtherPrediction(m_state.forNode(rightChild).m_type & ~PredictCell)) {
1451 m_jit.move(op2TagGPR, resultGPR);
1452 m_jit.or32(TrustedImm32(1), resultGPR);
1453
1454 speculationCheck(
1455 BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(),
1456 m_jit.branch32(
1457 MacroAssembler::NotEqual, resultGPR,
1458 MacroAssembler::TrustedImm32(JSValue::NullTag)));
1459 }
1460
1461 falseCase.link(&m_jit);
1462 m_jit.move(TrustedImm32(0), resultGPR);
1463 MacroAssembler::Jump done = m_jit.jump();
1464 trueCase.link(&m_jit);
1465 m_jit.move(TrustedImm32(1), resultGPR);
1466 done.link(&m_jit);
1467
1468 booleanResult(resultGPR, m_compileIndex);
1469}
1470
1471void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(
1472 Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex,
1473 const ClassInfo* classInfo, PredictionChecker predictionCheck)
1474{
1475 Node& branchNode = at(branchNodeIndex);
1476 BlockIndex taken = branchNode.takenBlockIndex();
1477 BlockIndex notTaken = branchNode.notTakenBlockIndex();
1478
1479 SpeculateCellOperand op1(this, leftChild);
1480 JSValueOperand op2(this, rightChild);
1481 GPRTemporary result(this);
1482
1483 GPRReg op1GPR = op1.gpr();
1484 GPRReg op2TagGPR = op2.tagGPR();
1485 GPRReg op2PayloadGPR = op2.payloadGPR();
1486 GPRReg resultGPR = result.gpr();
1487
1488 if (!predictionCheck(m_state.forNode(leftChild).m_type)) {
1489 speculationCheck(
1490 BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(),
1491 m_jit.branchPtr(
1492 MacroAssembler::NotEqual,
1493 MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()),
1494 MacroAssembler::TrustedImmPtr(classInfo)));
1495 }
1496
1497 // It seems that most of the time when programs do a == b where b may be either null/undefined
1498 // or an object, b is usually an object. Balance the branches to make that case fast.
1499 MacroAssembler::Jump rightNotCell =
1500 m_jit.branch32(MacroAssembler::NotEqual, op2TagGPR, TrustedImm32(JSValue::CellTag));
1501
1502 // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the
1503 // proof, when filtered on cell, demonstrates that we have an object of the desired type
1504 // (predictionCheck() will test for FinalObject or Array, currently), then we can skip the
1505 // speculation.
1506 if (!predictionCheck(m_state.forNode(rightChild).m_type & PredictCell)) {
1507 speculationCheck(
1508 BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(),
1509 m_jit.branchPtr(
1510 MacroAssembler::NotEqual,
1511 MacroAssembler::Address(op2PayloadGPR, JSCell::classInfoOffset()),
1512 MacroAssembler::TrustedImmPtr(classInfo)));
1513 }
1514
1515 // At this point we know that we can perform a straight-forward equality comparison on pointer
1516 // values because both left and right are pointers to objects that have no special equality
1517 // protocols.
1518 branch32(MacroAssembler::Equal, op1GPR, op2PayloadGPR, taken);
1519
1520 // We know that within this branch, rightChild must not be a cell. Check if that is enough to
1521 // prove that it is either null or undefined.
1522 if (isOtherPrediction(m_state.forNode(rightChild).m_type & ~PredictCell))
1523 rightNotCell.link(&m_jit);
1524 else {
1525 jump(notTaken, ForceJump);
1526
1527 rightNotCell.link(&m_jit);
1528 m_jit.move(op2TagGPR, resultGPR);
1529 m_jit.or32(TrustedImm32(1), resultGPR);
1530
1531 speculationCheck(
1532 BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(),
1533 m_jit.branch32(
1534 MacroAssembler::NotEqual, resultGPR,
1535 MacroAssembler::TrustedImm32(JSValue::NullTag)));
1536 }
1537
1538 jump(notTaken);
1539}
1540
1541void SpeculativeJIT::compileIntegerCompare(Node& node, MacroAssembler::RelationalCondition condition)
1542{
1543 SpeculateIntegerOperand op1(this, node.child1());
1544 SpeculateIntegerOperand op2(this, node.child2());
1545 GPRTemporary resultPayload(this);
1546
1547 m_jit.compare32(condition, op1.gpr(), op2.gpr(), resultPayload.gpr());
1548
1549 // If we add a DataFormatBool, we should use it here.
1550 booleanResult(resultPayload.gpr(), m_compileIndex);
1551}
1552
1553void SpeculativeJIT::compileDoubleCompare(Node& node, MacroAssembler::DoubleCondition condition)
1554{
1555 SpeculateDoubleOperand op1(this, node.child1());
1556 SpeculateDoubleOperand op2(this, node.child2());
1557 GPRTemporary resultPayload(this);
1558
1559 m_jit.move(TrustedImm32(1), resultPayload.gpr());
1560 MacroAssembler::Jump trueCase = m_jit.branchDouble(condition, op1.fpr(), op2.fpr());
1561 m_jit.move(TrustedImm32(0), resultPayload.gpr());
1562 trueCase.link(&m_jit);
1563
1564 booleanResult(resultPayload.gpr(), m_compileIndex);
1565}
1566
1567void SpeculativeJIT::compileValueAdd(Node& node)
1568{
1569 JSValueOperand op1(this, node.child1());
1570 JSValueOperand op2(this, node.child2());
1571
1572 GPRReg op1TagGPR = op1.tagGPR();
1573 GPRReg op1PayloadGPR = op1.payloadGPR();
1574 GPRReg op2TagGPR = op2.tagGPR();
1575 GPRReg op2PayloadGPR = op2.payloadGPR();
1576
1577 flushRegisters();
1578
1579 GPRResult2 resultTag(this);
1580 GPRResult resultPayload(this);
1581 if (isKnownNotNumber(node.child1().index()) || isKnownNotNumber(node.child2().index()))
1582 callOperation(operationValueAddNotNumber, resultTag.gpr(), resultPayload.gpr(), op1TagGPR, op1PayloadGPR, op2TagGPR, op2PayloadGPR);
1583 else
1584 callOperation(operationValueAdd, resultTag.gpr(), resultPayload.gpr(), op1TagGPR, op1PayloadGPR, op2TagGPR, op2PayloadGPR);
1585
1586 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
1587}
1588
1589void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse, const ClassInfo* classInfo, bool needSpeculationCheck)
1590{
1591 JSValueOperand value(this, nodeUse);
1592 GPRTemporary resultPayload(this);
1593 GPRReg valueTagGPR = value.tagGPR();
1594 GPRReg valuePayloadGPR = value.payloadGPR();
1595 GPRReg resultPayloadGPR = resultPayload.gpr();
1596
1597 MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
1598 if (needSpeculationCheck)
1599 speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(valuePayloadGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
1600 m_jit.move(TrustedImm32(0), resultPayloadGPR);
1601 MacroAssembler::Jump done = m_jit.jump();
1602
1603 notCell.link(&m_jit);
1604
1605 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
1606 if (needSpeculationCheck) {
1607 m_jit.move(valueTagGPR, resultPayloadGPR);
1608 m_jit.or32(TrustedImm32(1), resultPayloadGPR);
1609 speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, m_jit.branch32(MacroAssembler::NotEqual, resultPayloadGPR, TrustedImm32(JSValue::NullTag)));
1610 }
1611 m_jit.move(TrustedImm32(1), resultPayloadGPR);
1612
1613 done.link(&m_jit);
1614
1615 booleanResult(resultPayloadGPR, m_compileIndex);
1616}
1617
1618void SpeculativeJIT::compileLogicalNot(Node& node)
1619{
1620 if (at(node.child1()).shouldSpeculateBoolean()) {
1621 SpeculateBooleanOperand value(this, node.child1());
1622 GPRTemporary result(this, value);
1623 m_jit.xor32(TrustedImm32(1), value.gpr(), result.gpr());
1624 booleanResult(result.gpr(), m_compileIndex);
1625 return;
1626 }
1627 if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) {
1628 compileObjectOrOtherLogicalNot(node.child1(), &JSFinalObject::s_info, !isFinalObjectOrOtherPrediction(m_state.forNode(node.child1()).m_type));
1629 return;
1630 }
1631 if (at(node.child1()).shouldSpeculateArrayOrOther()) {
1632 compileObjectOrOtherLogicalNot(node.child1(), &JSArray::s_info, !isArrayOrOtherPrediction(m_state.forNode(node.child1()).m_type));
1633 return;
1634 }
1635 if (at(node.child1()).shouldSpeculateInteger()) {
1636 SpeculateIntegerOperand value(this, node.child1());
1637 GPRTemporary resultPayload(this, value);
1638 m_jit.compare32(MacroAssembler::Equal, value.gpr(), MacroAssembler::TrustedImm32(0), resultPayload.gpr());
1639 booleanResult(resultPayload.gpr(), m_compileIndex);
1640 return;
1641 }
1642 if (at(node.child1()).shouldSpeculateNumber()) {
1643 SpeculateDoubleOperand value(this, node.child1());
1644 FPRTemporary scratch(this);
1645 GPRTemporary resultPayload(this);
1646 m_jit.move(TrustedImm32(0), resultPayload.gpr());
1647 MacroAssembler::Jump nonZero = m_jit.branchDoubleNonZero(value.fpr(), scratch.fpr());
1648 m_jit.move(TrustedImm32(1), resultPayload.gpr());
1649 nonZero.link(&m_jit);
1650 booleanResult(resultPayload.gpr(), m_compileIndex);
1651 return;
1652 }
1653
1654 JSValueOperand arg1(this, node.child1());
1655 GPRTemporary resultPayload(this, arg1, false);
1656 GPRReg arg1TagGPR = arg1.tagGPR();
1657 GPRReg arg1PayloadGPR = arg1.payloadGPR();
1658 GPRReg resultPayloadGPR = resultPayload.gpr();
1659
1660 arg1.use();
1661
1662 JITCompiler::Jump fastCase = m_jit.branch32(JITCompiler::Equal, arg1TagGPR, TrustedImm32(JSValue::BooleanTag));
1663
1664 silentSpillAllRegisters(resultPayloadGPR);
1665 callOperation(dfgConvertJSValueToBoolean, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR);
1666 silentFillAllRegisters(resultPayloadGPR);
1667 JITCompiler::Jump doNot = m_jit.jump();
1668
1669 fastCase.link(&m_jit);
1670 m_jit.move(arg1PayloadGPR, resultPayloadGPR);
1671
1672 doNot.link(&m_jit);
1673 m_jit.xor32(TrustedImm32(1), resultPayloadGPR);
1674 booleanResult(resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
1675}
1676
1677void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BlockIndex taken, BlockIndex notTaken, const ClassInfo* classInfo, bool needSpeculationCheck)
1678{
1679 JSValueOperand value(this, nodeUse);
1680 GPRTemporary scratch(this);
1681 GPRReg valueTagGPR = value.tagGPR();
1682 GPRReg valuePayloadGPR = value.payloadGPR();
1683 GPRReg scratchGPR = scratch.gpr();
1684
1685 MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
1686 if (needSpeculationCheck)
1687 speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(valuePayloadGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
1688 jump(taken, ForceJump);
1689
1690 notCell.link(&m_jit);
1691
1692 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
1693 if (needSpeculationCheck) {
1694 m_jit.move(valueTagGPR, scratchGPR);
1695 m_jit.or32(TrustedImm32(1), scratchGPR);
1696 speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, m_jit.branch32(MacroAssembler::NotEqual, scratchGPR, TrustedImm32(JSValue::NullTag)));
1697 }
1698
1699 jump(notTaken);
1700
1701 noResult(m_compileIndex);
1702}
1703
1704void SpeculativeJIT::emitBranch(Node& node)
1705{
1706 BlockIndex taken = node.takenBlockIndex();
1707 BlockIndex notTaken = node.notTakenBlockIndex();
1708
1709 if (at(node.child1()).shouldSpeculateBoolean()) {
1710 SpeculateBooleanOperand value(this, node.child1());
1711 MacroAssembler::ResultCondition condition = MacroAssembler::NonZero;
1712
1713 if (taken == (m_block + 1)) {
1714 condition = MacroAssembler::Zero;
1715 BlockIndex tmp = taken;
1716 taken = notTaken;
1717 notTaken = tmp;
1718 }
1719
1720 branchTest32(condition, value.gpr(), TrustedImm32(1), taken);
1721 jump(notTaken);
1722
1723 noResult(m_compileIndex);
1724 } else if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) {
1725 emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSFinalObject::s_info, !isFinalObjectOrOtherPrediction(m_state.forNode(node.child1()).m_type));
1726 } else if (at(node.child1()).shouldSpeculateArrayOrOther()) {
1727 emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSArray::s_info, !isArrayOrOtherPrediction(m_state.forNode(node.child1()).m_type));
1728 } else if (at(node.child1()).shouldSpeculateNumber()) {
1729 if (at(node.child1()).shouldSpeculateInteger()) {
1730 bool invert = false;
1731
1732 if (taken == (m_block + 1)) {
1733 invert = true;
1734 BlockIndex tmp = taken;
1735 taken = notTaken;
1736 notTaken = tmp;
1737 }
1738
1739 SpeculateIntegerOperand value(this, node.child1());
1740 branchTest32(invert ? MacroAssembler::Zero : MacroAssembler::NonZero, value.gpr(), taken);
1741 } else {
1742 SpeculateDoubleOperand value(this, node.child1());
1743 FPRTemporary scratch(this);
1744 branchDoubleNonZero(value.fpr(), scratch.fpr(), taken);
1745 }
1746
1747 jump(notTaken);
1748
1749 noResult(m_compileIndex);
1750 } else {
1751 JSValueOperand value(this, node.child1());
1752 value.fill();
1753 GPRReg valueTagGPR = value.tagGPR();
1754 GPRReg valuePayloadGPR = value.payloadGPR();
1755
1756 GPRTemporary result(this);
1757 GPRReg resultGPR = result.gpr();
1758
1759 use(node.child1());
1760
1761 JITCompiler::Jump fastPath = m_jit.branch32(JITCompiler::Equal, valueTagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag));
1762 JITCompiler::Jump slowPath = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, JITCompiler::TrustedImm32(JSValue::BooleanTag));
1763
1764 fastPath.link(&m_jit);
1765 branchTest32(JITCompiler::Zero, valuePayloadGPR, notTaken);
1766 jump(taken, ForceJump);
1767
1768 slowPath.link(&m_jit);
1769 silentSpillAllRegisters(resultGPR);
1770 callOperation(dfgConvertJSValueToBoolean, resultGPR, valueTagGPR, valuePayloadGPR);
1771 silentFillAllRegisters(resultGPR);
1772
1773 branchTest32(JITCompiler::NonZero, resultGPR, taken);
1774 jump(notTaken);
1775
1776 noResult(m_compileIndex, UseChildrenCalledExplicitly);
1777 }
1778}
1779
1780void SpeculativeJIT::compile(Node& node)
1781{
1782 NodeType op = node.op();
1783
1784 switch (op) {
1785 case JSConstant:
1786 initConstantInfo(m_compileIndex);
1787 break;
1788
1789 case WeakJSConstant:
1790 m_jit.addWeakReference(node.weakConstant());
1791 initConstantInfo(m_compileIndex);
1792 break;
1793
1794 case GetLocal: {
1795 PredictedType prediction = node.variableAccessData()->prediction();
1796 AbstractValue& value = block()->valuesAtHead.operand(node.local());
1797
1798 // If we have no prediction for this local, then don't attempt to compile.
1799 if (prediction == PredictNone || value.isClear()) {
1800 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
1801 break;
1802 }
1803
1804 if (!m_jit.graph().isCaptured(node.local())) {
1805 if (node.variableAccessData()->shouldUseDoubleFormat()) {
1806 FPRTemporary result(this);
1807 m_jit.loadDouble(JITCompiler::addressFor(node.local()), result.fpr());
1808 VirtualRegister virtualRegister = node.virtualRegister();
1809 m_fprs.retain(result.fpr(), virtualRegister, SpillOrderDouble);
1810 m_generationInfo[virtualRegister].initDouble(m_compileIndex, node.refCount(), result.fpr());
1811 break;
1812 }
1813
1814 if (isInt32Prediction(prediction)) {
1815 GPRTemporary result(this);
1816 m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
1817
1818 // Like integerResult, but don't useChildren - our children are phi nodes,
1819 // and don't represent values within this dataflow with virtual registers.
1820 VirtualRegister virtualRegister = node.virtualRegister();
1821 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderInteger);
1822 m_generationInfo[virtualRegister].initInteger(m_compileIndex, node.refCount(), result.gpr());
1823 break;
1824 }
1825
1826 if (isArrayPrediction(prediction)) {
1827 GPRTemporary result(this);
1828 m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
1829
1830 // Like cellResult, but don't useChildren - our children are phi nodes,
1831 // and don't represent values within this dataflow with virtual registers.
1832 VirtualRegister virtualRegister = node.virtualRegister();
1833 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderCell);
1834 m_generationInfo[virtualRegister].initCell(m_compileIndex, node.refCount(), result.gpr());
1835 break;
1836 }
1837
1838 if (isBooleanPrediction(prediction)) {
1839 GPRTemporary result(this);
1840 m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
1841
1842 // Like booleanResult, but don't useChildren - our children are phi nodes,
1843 // and don't represent values within this dataflow with virtual registers.
1844 VirtualRegister virtualRegister = node.virtualRegister();
1845 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderBoolean);
1846 m_generationInfo[virtualRegister].initBoolean(m_compileIndex, node.refCount(), result.gpr());
1847 break;
1848 }
1849 }
1850
1851 GPRTemporary result(this);
1852 GPRTemporary tag(this);
1853 m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
1854 m_jit.load32(JITCompiler::tagFor(node.local()), tag.gpr());
1855
1856 // Like jsValueResult, but don't useChildren - our children are phi nodes,
1857 // and don't represent values within this dataflow with virtual registers.
1858 VirtualRegister virtualRegister = node.virtualRegister();
1859 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
1860 m_gprs.retain(tag.gpr(), virtualRegister, SpillOrderJS);
1861
1862 DataFormat format;
1863 if (isCellPrediction(value.m_type)
1864 && !m_jit.graph().isCaptured(node.local()))
1865 format = DataFormatJSCell;
1866 else
1867 format = DataFormatJS;
1868 m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), tag.gpr(), result.gpr(), format);
1869 break;
1870 }
1871
1872 case SetLocal: {
1873 // SetLocal doubles as a hint as to where a node will be stored and
1874 // as a speculation point. So before we speculate make sure that we
1875 // know where the child of this node needs to go in the virtual
1876 // register file.
1877 compileMovHint(node);
1878
1879 // As far as OSR is concerned, we're on the bytecode index corresponding
1880 // to the *next* instruction, since we've already "executed" the
1881 // SetLocal and whatever other DFG Nodes are associated with the same
1882 // bytecode index as the SetLocal.
1883 ASSERT(m_codeOriginForOSR == node.codeOrigin);
1884 Node* nextNode = &at(block()->at(m_indexInBlock + 1));
1885
1886 // But even more oddly, we need to be super careful about the following
1887 // sequence:
1888 //
1889 // a: Foo()
1890 // b: SetLocal(@a)
1891 // c: Flush(@b)
1892 //
1893 // This next piece of crazy takes care of this.
1894 if (nextNode->op() == Flush && nextNode->child1() == m_compileIndex)
1895 nextNode = &at(block()->at(m_indexInBlock + 2));
1896
1897 // Oddly, it's possible for the bytecode index for the next node to be
1898 // equal to ours. This will happen for op_post_inc. And, even more oddly,
1899 // this is just fine. Ordinarily, this wouldn't be fine, since if the
1900 // next node failed OSR then we'd be OSR-ing with this SetLocal's local
1901 // variable already set even though from the standpoint of the old JIT,
1902 // this SetLocal should not have executed. But for op_post_inc, it's just
1903 // fine, because this SetLocal's local (i.e. the LHS in a x = y++
1904 // statement) would be dead anyway - so the fact that DFG would have
1905 // already made the assignment, and baked it into the register file during
1906 // OSR exit, would not be visible to the old JIT in any way.
1907 m_codeOriginForOSR = nextNode->codeOrigin;
1908
1909 if (!m_jit.graph().isCaptured(node.local())) {
1910 if (node.variableAccessData()->shouldUseDoubleFormat()) {
1911 SpeculateDoubleOperand value(this, node.child1());
1912 m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local()));
1913 noResult(m_compileIndex);
1914 // Indicate that it's no longer necessary to retrieve the value of
1915 // this bytecode variable from registers or other locations in the register file,
1916 // but that it is stored as a double.
1917 valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile);
1918 break;
1919 }
1920 PredictedType predictedType = node.variableAccessData()->argumentAwarePrediction();
1921 if (m_generationInfo[at(node.child1()).virtualRegister()].registerFormat() == DataFormatDouble) {
1922 DoubleOperand value(this, node.child1());
1923 m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local()));
1924 noResult(m_compileIndex);
1925 valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile);
1926 break;
1927 }
1928 if (isInt32Prediction(predictedType)) {
1929 SpeculateIntegerOperand value(this, node.child1());
1930 m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local()));
1931 noResult(m_compileIndex);
1932 valueSourceReferenceForOperand(node.local()) = ValueSource(Int32InRegisterFile);
1933 break;
1934 }
1935 if (isArrayPrediction(predictedType)) {
1936 SpeculateCellOperand cell(this, node.child1());
1937 GPRReg cellGPR = cell.gpr();
1938 if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
1939 speculationCheck(BadType, JSValueSource::unboxedCell(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
1940 m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local()));
1941 noResult(m_compileIndex);
1942 valueSourceReferenceForOperand(node.local()) = ValueSource(CellInRegisterFile);
1943 break;
1944 }
1945 if (isBooleanPrediction(predictedType)) {
1946 SpeculateBooleanOperand value(this, node.child1());
1947 m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local()));
1948 noResult(m_compileIndex);
1949 valueSourceReferenceForOperand(node.local()) = ValueSource(BooleanInRegisterFile);
1950 break;
1951 }
1952 }
1953 JSValueOperand value(this, node.child1());
1954 m_jit.store32(value.payloadGPR(), JITCompiler::payloadFor(node.local()));
1955 m_jit.store32(value.tagGPR(), JITCompiler::tagFor(node.local()));
1956 noResult(m_compileIndex);
1957 valueSourceReferenceForOperand(node.local()) = ValueSource(ValueInRegisterFile);
1958 break;
1959 }
1960
1961 case SetArgument:
1962 // This is a no-op; it just marks the fact that the argument is being used.
1963 // But it may be profitable to use this as a hook to run speculation checks
1964 // on arguments, thereby allowing us to trivially eliminate such checks if
1965 // the argument is not used.
1966 break;
1967
1968 case BitAnd:
1969 case BitOr:
1970 case BitXor:
1971 if (isInt32Constant(node.child1().index())) {
1972 SpeculateIntegerOperand op2(this, node.child2());
1973 GPRTemporary result(this, op2);
1974
1975 bitOp(op, valueOfInt32Constant(node.child1().index()), op2.gpr(), result.gpr());
1976
1977 integerResult(result.gpr(), m_compileIndex);
1978 } else if (isInt32Constant(node.child2().index())) {
1979 SpeculateIntegerOperand op1(this, node.child1());
1980 GPRTemporary result(this, op1);
1981
1982 bitOp(op, valueOfInt32Constant(node.child2().index()), op1.gpr(), result.gpr());
1983
1984 integerResult(result.gpr(), m_compileIndex);
1985 } else {
1986 SpeculateIntegerOperand op1(this, node.child1());
1987 SpeculateIntegerOperand op2(this, node.child2());
1988 GPRTemporary result(this, op1, op2);
1989
1990 GPRReg reg1 = op1.gpr();
1991 GPRReg reg2 = op2.gpr();
1992 bitOp(op, reg1, reg2, result.gpr());
1993
1994 integerResult(result.gpr(), m_compileIndex);
1995 }
1996 break;
1997
1998 case BitRShift:
1999 case BitLShift:
2000 case BitURShift:
2001 if (isInt32Constant(node.child2().index())) {
2002 SpeculateIntegerOperand op1(this, node.child1());
2003 GPRTemporary result(this, op1);
2004
2005 shiftOp(op, op1.gpr(), valueOfInt32Constant(node.child2().index()) & 0x1f, result.gpr());
2006
2007 integerResult(result.gpr(), m_compileIndex);
2008 } else {
2009 // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.
2010 SpeculateIntegerOperand op1(this, node.child1());
2011 SpeculateIntegerOperand op2(this, node.child2());
2012 GPRTemporary result(this, op1);
2013
2014 GPRReg reg1 = op1.gpr();
2015 GPRReg reg2 = op2.gpr();
2016 shiftOp(op, reg1, reg2, result.gpr());
2017
2018 integerResult(result.gpr(), m_compileIndex);
2019 }
2020 break;
2021
2022 case UInt32ToNumber: {
2023 compileUInt32ToNumber(node);
2024 break;
2025 }
2026
2027 case DoubleAsInt32: {
2028 compileDoubleAsInt32(node);
2029 break;
2030 }
2031
2032 case ValueToInt32: {
2033 compileValueToInt32(node);
2034 break;
2035 }
2036
2037 case Int32ToDouble: {
2038 compileInt32ToDouble(node);
2039 break;
2040 }
2041
2042 case CheckNumber: {
2043 if (!isNumberPrediction(m_state.forNode(node.child1()).m_type)) {
2044 JSValueOperand op1(this, node.child1());
2045 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, op1.tagGPR(), TrustedImm32(JSValue::Int32Tag));
2046 speculationCheck(
2047 BadType, JSValueRegs(op1.tagGPR(), op1.payloadGPR()), node.child1().index(),
2048 m_jit.branch32(MacroAssembler::AboveOrEqual, op1.tagGPR(), TrustedImm32(JSValue::LowestTag)));
2049 isInteger.link(&m_jit);
2050 }
2051 noResult(m_compileIndex);
2052 break;
2053 }
2054
2055 case ValueAdd:
2056 case ArithAdd:
2057 compileAdd(node);
2058 break;
2059
2060 case ArithSub:
2061 compileArithSub(node);
2062 break;
2063
2064 case ArithNegate:
2065 compileArithNegate(node);
2066 break;
2067
2068 case ArithMul:
2069 compileArithMul(node);
2070 break;
2071
2072 case ArithDiv: {
2073 if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
2074#if CPU(X86)
2075 compileIntegerArithDivForX86(node);
2076#else // CPU(X86) -> so non-X86 code follows
2077 ASSERT_NOT_REACHED(); // should have been coverted into a double divide.
2078#endif // CPU(X86)
2079 break;
2080 }
2081
2082 SpeculateDoubleOperand op1(this, node.child1());
2083 SpeculateDoubleOperand op2(this, node.child2());
2084 FPRTemporary result(this, op1);
2085
2086 FPRReg reg1 = op1.fpr();
2087 FPRReg reg2 = op2.fpr();
2088 m_jit.divDouble(reg1, reg2, result.fpr());
2089
2090 doubleResult(result.fpr(), m_compileIndex);
2091 break;
2092 }
2093
2094 case ArithMod: {
2095 compileArithMod(node);
2096 break;
2097 }
2098
2099 case ArithAbs: {
2100 if (at(node.child1()).shouldSpeculateInteger() && node.canSpeculateInteger()) {
2101 SpeculateIntegerOperand op1(this, node.child1());
2102 GPRTemporary result(this, op1);
2103 GPRTemporary scratch(this);
2104
2105 m_jit.zeroExtend32ToPtr(op1.gpr(), result.gpr());
2106 m_jit.rshift32(result.gpr(), MacroAssembler::TrustedImm32(31), scratch.gpr());
2107 m_jit.add32(scratch.gpr(), result.gpr());
2108 m_jit.xor32(scratch.gpr(), result.gpr());
2109 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, result.gpr(), MacroAssembler::TrustedImm32(1 << 31)));
2110 integerResult(result.gpr(), m_compileIndex);
2111 break;
2112 }
2113
2114 SpeculateDoubleOperand op1(this, node.child1());
2115 FPRTemporary result(this);
2116
2117 m_jit.absDouble(op1.fpr(), result.fpr());
2118 doubleResult(result.fpr(), m_compileIndex);
2119 break;
2120 }
2121
2122 case ArithMin:
2123 case ArithMax: {
2124 if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
2125 SpeculateStrictInt32Operand op1(this, node.child1());
2126 SpeculateStrictInt32Operand op2(this, node.child2());
2127 GPRTemporary result(this, op1);
2128
2129 MacroAssembler::Jump op1Less = m_jit.branch32(op == ArithMin ? MacroAssembler::LessThan : MacroAssembler::GreaterThan, op1.gpr(), op2.gpr());
2130 m_jit.move(op2.gpr(), result.gpr());
2131 if (op1.gpr() != result.gpr()) {
2132 MacroAssembler::Jump done = m_jit.jump();
2133 op1Less.link(&m_jit);
2134 m_jit.move(op1.gpr(), result.gpr());
2135 done.link(&m_jit);
2136 } else
2137 op1Less.link(&m_jit);
2138
2139 integerResult(result.gpr(), m_compileIndex);
2140 break;
2141 }
2142
2143 SpeculateDoubleOperand op1(this, node.child1());
2144 SpeculateDoubleOperand op2(this, node.child2());
2145 FPRTemporary result(this, op1);
2146
2147 MacroAssembler::JumpList done;
2148
2149 MacroAssembler::Jump op1Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleLessThan : MacroAssembler::DoubleGreaterThan, op1.fpr(), op2.fpr());
2150
2151 // op2 is eather the lesser one or one of then is NaN
2152 MacroAssembler::Jump op2Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleGreaterThanOrEqual : MacroAssembler::DoubleLessThanOrEqual, op1.fpr(), op2.fpr());
2153
2154 // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding
2155 // op1 + op2 and putting it into result.
2156 m_jit.addDouble(op1.fpr(), op2.fpr(), result.fpr());
2157 done.append(m_jit.jump());
2158
2159 op2Less.link(&m_jit);
2160 m_jit.moveDouble(op2.fpr(), result.fpr());
2161
2162 if (op1.fpr() != result.fpr()) {
2163 done.append(m_jit.jump());
2164
2165 op1Less.link(&m_jit);
2166 m_jit.moveDouble(op1.fpr(), result.fpr());
2167 } else
2168 op1Less.link(&m_jit);
2169
2170 done.link(&m_jit);
2171
2172 doubleResult(result.fpr(), m_compileIndex);
2173 break;
2174 }
2175
2176 case ArithSqrt: {
2177 SpeculateDoubleOperand op1(this, node.child1());
2178 FPRTemporary result(this, op1);
2179
2180 m_jit.sqrtDouble(op1.fpr(), result.fpr());
2181
2182 doubleResult(result.fpr(), m_compileIndex);
2183 break;
2184 }
2185
2186 case LogicalNot:
2187 compileLogicalNot(node);
2188 break;
2189
2190 case CompareLess:
2191 if (compare(node, JITCompiler::LessThan, JITCompiler::DoubleLessThan, operationCompareLess))
2192 return;
2193 break;
2194
2195 case CompareLessEq:
2196 if (compare(node, JITCompiler::LessThanOrEqual, JITCompiler::DoubleLessThanOrEqual, operationCompareLessEq))
2197 return;
2198 break;
2199
2200 case CompareGreater:
2201 if (compare(node, JITCompiler::GreaterThan, JITCompiler::DoubleGreaterThan, operationCompareGreater))
2202 return;
2203 break;
2204
2205 case CompareGreaterEq:
2206 if (compare(node, JITCompiler::GreaterThanOrEqual, JITCompiler::DoubleGreaterThanOrEqual, operationCompareGreaterEq))
2207 return;
2208 break;
2209
2210 case CompareEq:
2211 if (isNullConstant(node.child1().index())) {
2212 if (nonSpeculativeCompareNull(node, node.child2()))
2213 return;
2214 break;
2215 }
2216 if (isNullConstant(node.child2().index())) {
2217 if (nonSpeculativeCompareNull(node, node.child1()))
2218 return;
2219 break;
2220 }
2221 if (compare(node, JITCompiler::Equal, JITCompiler::DoubleEqual, operationCompareEq))
2222 return;
2223 break;
2224
2225 case CompareStrictEq:
2226 if (compileStrictEq(node))
2227 return;
2228 break;
2229
2230 case StringCharCodeAt: {
2231 compileGetCharCodeAt(node);
2232 break;
2233 }
2234
2235 case StringCharAt: {
2236 // Relies on StringCharAt node having same basic layout as GetByVal
2237 compileGetByValOnString(node);
2238 break;
2239 }
2240
2241 case GetByVal: {
2242 if (!node.prediction() || !at(node.child1()).prediction() || !at(node.child2()).prediction()) {
2243 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
2244 break;
2245 }
2246
2247 if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArrayPrediction(at(node.child1()).prediction())) {
2248 SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right.
2249 JSValueOperand property(this, node.child2());
2250 GPRReg baseGPR = base.gpr();
2251 GPRReg propertyTagGPR = property.tagGPR();
2252 GPRReg propertyPayloadGPR = property.payloadGPR();
2253
2254 flushRegisters();
2255 GPRResult2 resultTag(this);
2256 GPRResult resultPayload(this);
2257 callOperation(operationGetByValCell, resultTag.gpr(), resultPayload.gpr(), baseGPR, propertyTagGPR, propertyPayloadGPR);
2258
2259 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
2260 break;
2261 }
2262
2263 if (at(node.child1()).prediction() == PredictString) {
2264 compileGetByValOnString(node);
2265 if (!m_compileOkay)
2266 return;
2267 break;
2268 }
2269
2270 if (at(node.child1()).shouldSpeculateInt8Array()) {
2271 compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
2272 if (!m_compileOkay)
2273 return;
2274 break;
2275 }
2276
2277 if (at(node.child1()).shouldSpeculateInt16Array()) {
2278 compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
2279 if (!m_compileOkay)
2280 return;
2281 break;
2282 }
2283
2284 if (at(node.child1()).shouldSpeculateInt32Array()) {
2285 compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
2286 if (!m_compileOkay)
2287 return;
2288 break;
2289 }
2290
2291 if (at(node.child1()).shouldSpeculateUint8Array()) {
2292 compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
2293 if (!m_compileOkay)
2294 return;
2295 break;
2296 }
2297
2298 if (at(node.child1()).shouldSpeculateUint8ClampedArray()) {
2299 compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
2300 if (!m_compileOkay)
2301 return;
2302 break;
2303 }
2304
2305 if (at(node.child1()).shouldSpeculateUint16Array()) {
2306 compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
2307 if (!m_compileOkay)
2308 return;
2309 break;
2310 }
2311
2312 if (at(node.child1()).shouldSpeculateUint32Array()) {
2313 compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
2314 if (!m_compileOkay)
2315 return;
2316 break;
2317 }
2318
2319 if (at(node.child1()).shouldSpeculateFloat32Array()) {
2320 compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks);
2321 if (!m_compileOkay)
2322 return;
2323 break;
2324 }
2325
2326 if (at(node.child1()).shouldSpeculateFloat64Array()) {
2327 compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks);
2328 if (!m_compileOkay)
2329 return;
2330 break;
2331 }
2332
2333 ASSERT(at(node.child1()).shouldSpeculateArray());
2334
2335 SpeculateStrictInt32Operand property(this, node.child2());
2336 StorageOperand storage(this, node.child3());
2337 GPRReg propertyReg = property.gpr();
2338 GPRReg storageReg = storage.gpr();
2339
2340 if (!m_compileOkay)
2341 return;
2342
2343 // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
2344 // If we have predicted the base to be type array, we can skip the check.
2345 {
2346 SpeculateCellOperand base(this, node.child1());
2347 GPRReg baseReg = base.gpr();
2348 if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
2349 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
2350 speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
2351 }
2352
2353 GPRTemporary resultTag(this);
2354 GPRTemporary resultPayload(this);
2355
2356 // FIXME: In cases where there are subsequent by_val accesses to the same base it might help to cache
2357 // the storage pointer - especially if there happens to be another register free right now. If we do so,
2358 // then we'll need to allocate a new temporary for result.
2359 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr());
2360 speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag)));
2361 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
2362
2363 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
2364 break;
2365 }
2366
2367 case PutByVal: {
2368 if (!at(node.child1()).prediction() || !at(node.child2()).prediction()) {
2369 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
2370 break;
2371 }
2372
2373 if (!at(node.child2()).shouldSpeculateInteger() || !isActionableMutableArrayPrediction(at(node.child1()).prediction())) {
2374 SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right.
2375 JSValueOperand property(this, node.child2());
2376 JSValueOperand value(this, node.child3());
2377 GPRReg baseGPR = base.gpr();
2378 GPRReg propertyTagGPR = property.tagGPR();
2379 GPRReg propertyPayloadGPR = property.payloadGPR();
2380 GPRReg valueTagGPR = value.tagGPR();
2381 GPRReg valuePayloadGPR = value.payloadGPR();
2382
2383 flushRegisters();
2384 callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValCellStrict : operationPutByValCellNonStrict, baseGPR, propertyTagGPR, propertyPayloadGPR, valueTagGPR, valuePayloadGPR);
2385
2386 noResult(m_compileIndex);
2387 break;
2388 }
2389
2390 SpeculateCellOperand base(this, node.child1());
2391 SpeculateStrictInt32Operand property(this, node.child2());
2392 if (at(node.child1()).shouldSpeculateInt8Array()) {
2393 compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
2394 if (!m_compileOkay)
2395 return;
2396 break;
2397 }
2398
2399 if (at(node.child1()).shouldSpeculateInt16Array()) {
2400 compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
2401 if (!m_compileOkay)
2402 return;
2403 break;
2404 }
2405
2406 if (at(node.child1()).shouldSpeculateInt32Array()) {
2407 compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray);
2408 if (!m_compileOkay)
2409 return;
2410 break;
2411 }
2412
2413 if (at(node.child1()).shouldSpeculateUint8Array()) {
2414 compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
2415 if (!m_compileOkay)
2416 return;
2417 break;
2418 }
2419
2420 if (at(node.child1()).shouldSpeculateUint8ClampedArray()) {
2421 compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding);
2422 if (!m_compileOkay)
2423 return;
2424 break;
2425 }
2426
2427 if (at(node.child1()).shouldSpeculateUint16Array()) {
2428 compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
2429 if (!m_compileOkay)
2430 return;
2431 break;
2432 }
2433
2434 if (at(node.child1()).shouldSpeculateUint32Array()) {
2435 compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray);
2436 if (!m_compileOkay)
2437 return;
2438 break;
2439 }
2440
2441 if (at(node.child1()).shouldSpeculateFloat32Array()) {
2442 compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks);
2443 if (!m_compileOkay)
2444 return;
2445 break;
2446 }
2447
2448 if (at(node.child1()).shouldSpeculateFloat64Array()) {
2449 compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks);
2450 if (!m_compileOkay)
2451 return;
2452 break;
2453 }
2454
2455 ASSERT(at(node.child1()).shouldSpeculateArray());
2456
2457 JSValueOperand value(this, node.child3());
2458 GPRTemporary scratch(this);
2459
2460 // Map base, property & value into registers, allocate a scratch register.
2461 GPRReg baseReg = base.gpr();
2462 GPRReg propertyReg = property.gpr();
2463 GPRReg valueTagReg = value.tagGPR();
2464 GPRReg valuePayloadReg = value.payloadGPR();
2465 GPRReg scratchReg = scratch.gpr();
2466
2467 if (!m_compileOkay)
2468 return;
2469
2470 writeBarrier(baseReg, valueTagReg, node.child3(), WriteBarrierForPropertyAccess, scratchReg);
2471
2472 // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
2473 // If we have predicted the base to be type array, we can skip the check.
2474 if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
2475 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
2476
2477 base.use();
2478 property.use();
2479 value.use();
2480
2481 MacroAssembler::Jump withinArrayBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
2482
2483 // Code to handle put beyond array bounds.
2484 silentSpillAllRegisters(scratchReg);
2485 callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, baseReg, propertyReg, valueTagReg, valuePayloadReg);
2486 silentFillAllRegisters(scratchReg);
2487 JITCompiler::Jump wasBeyondArrayBounds = m_jit.jump();
2488
2489 withinArrayBounds.link(&m_jit);
2490
2491 // Get the array storage.
2492 GPRReg storageReg = scratchReg;
2493 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
2494
2495 // Check if we're writing to a hole; if so increment m_numValuesInVector.
2496 MacroAssembler::Jump notHoleValue = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
2497 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
2498
2499 // If we're writing to a hole we might be growing the array;
2500 MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
2501 m_jit.add32(TrustedImm32(1), propertyReg);
2502 m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
2503 m_jit.sub32(TrustedImm32(1), propertyReg);
2504
2505 lengthDoesNotNeedUpdate.link(&m_jit);
2506 notHoleValue.link(&m_jit);
2507
2508 // Store the value to the array.
2509 m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2510 m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2511
2512 wasBeyondArrayBounds.link(&m_jit);
2513
2514 noResult(m_compileIndex, UseChildrenCalledExplicitly);
2515 break;
2516 }
2517
2518 case PutByValAlias: {
2519 if (!at(node.child1()).prediction() || !at(node.child2()).prediction()) {
2520 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
2521 break;
2522 }
2523
2524 ASSERT(isActionableMutableArrayPrediction(at(node.child1()).prediction()));
2525 ASSERT(at(node.child2()).shouldSpeculateInteger());
2526
2527 SpeculateCellOperand base(this, node.child1());
2528 SpeculateStrictInt32Operand property(this, node.child2());
2529
2530 if (at(node.child1()).shouldSpeculateInt8Array()) {
2531 compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), NoTypedArraySpecCheck, SignedTypedArray);
2532 if (!m_compileOkay)
2533 return;
2534 break;
2535 }
2536
2537 if (at(node.child1()).shouldSpeculateInt16Array()) {
2538 compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), NoTypedArraySpecCheck, SignedTypedArray);
2539 if (!m_compileOkay)
2540 return;
2541 break;
2542 }
2543
2544 if (at(node.child1()).shouldSpeculateInt32Array()) {
2545 compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), NoTypedArraySpecCheck, SignedTypedArray);
2546 if (!m_compileOkay)
2547 return;
2548 break;
2549 }
2550
2551 if (at(node.child1()).shouldSpeculateUint8Array()) {
2552 compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray);
2553 if (!m_compileOkay)
2554 return;
2555 break;
2556 }
2557
2558 if (at(node.child1()).shouldSpeculateUint8ClampedArray()) {
2559 compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray, ClampRounding);
2560 if (!m_compileOkay)
2561 return;
2562 break;
2563 }
2564
2565 if (at(node.child1()).shouldSpeculateUint16Array()) {
2566 compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), NoTypedArraySpecCheck, UnsignedTypedArray);
2567 if (!m_compileOkay)
2568 return;
2569 break;
2570 }
2571
2572 if (at(node.child1()).shouldSpeculateUint32Array()) {
2573 compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), NoTypedArraySpecCheck, UnsignedTypedArray);
2574 if (!m_compileOkay)
2575 return;
2576 break;
2577 }
2578
2579 if (at(node.child1()).shouldSpeculateFloat32Array()) {
2580 compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), NoTypedArraySpecCheck);
2581 if (!m_compileOkay)
2582 return;
2583 break;
2584 }
2585
2586 if (at(node.child1()).shouldSpeculateFloat64Array()) {
2587 compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), NoTypedArraySpecCheck);
2588 if (!m_compileOkay)
2589 return;
2590 break;
2591 }
2592
2593 ASSERT(at(node.child1()).shouldSpeculateArray());
2594
2595 JSValueOperand value(this, node.child3());
2596 GPRTemporary scratch(this, base);
2597
2598 GPRReg baseReg = base.gpr();
2599 GPRReg scratchReg = scratch.gpr();
2600
2601 writeBarrier(baseReg, value.tagGPR(), node.child3(), WriteBarrierForPropertyAccess, scratchReg);
2602
2603 // Get the array storage.
2604 GPRReg storageReg = scratchReg;
2605 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
2606
2607 // Store the value to the array.
2608 GPRReg propertyReg = property.gpr();
2609 m_jit.store32(value.tagGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2610 m_jit.store32(value.payloadGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2611
2612 noResult(m_compileIndex);
2613 break;
2614 }
2615
2616 case RegExpExec: {
2617 if (compileRegExpExec(node))
2618 return;
2619
2620 if (!node.adjustedRefCount()) {
2621 SpeculateCellOperand base(this, node.child1());
2622 SpeculateCellOperand argument(this, node.child2());
2623 GPRReg baseGPR = base.gpr();
2624 GPRReg argumentGPR = argument.gpr();
2625
2626 flushRegisters();
2627 GPRResult result(this);
2628 callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
2629
2630 // Must use jsValueResult because otherwise we screw up register
2631 // allocation, which thinks that this node has a result.
2632 booleanResult(result.gpr(), m_compileIndex);
2633 break;
2634 }
2635
2636 SpeculateCellOperand base(this, node.child1());
2637 SpeculateCellOperand argument(this, node.child2());
2638 GPRReg baseGPR = base.gpr();
2639 GPRReg argumentGPR = argument.gpr();
2640
2641 flushRegisters();
2642 GPRResult2 resultTag(this);
2643 GPRResult resultPayload(this);
2644 callOperation(operationRegExpExec, resultTag.gpr(), resultPayload.gpr(), baseGPR, argumentGPR);
2645
2646 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
2647 break;
2648 }
2649
2650 case RegExpTest: {
2651 SpeculateCellOperand base(this, node.child1());
2652 SpeculateCellOperand argument(this, node.child2());
2653 GPRReg baseGPR = base.gpr();
2654 GPRReg argumentGPR = argument.gpr();
2655
2656 flushRegisters();
2657 GPRResult result(this);
2658 callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
2659
2660 // If we add a DataFormatBool, we should use it here.
2661 booleanResult(result.gpr(), m_compileIndex);
2662 break;
2663 }
2664
2665 case ArrayPush: {
2666 SpeculateCellOperand base(this, node.child1());
2667 JSValueOperand value(this, node.child2());
2668 GPRTemporary storage(this);
2669 GPRTemporary storageLength(this);
2670
2671 GPRReg baseGPR = base.gpr();
2672 GPRReg valueTagGPR = value.tagGPR();
2673 GPRReg valuePayloadGPR = value.payloadGPR();
2674 GPRReg storageGPR = storage.gpr();
2675 GPRReg storageLengthGPR = storageLength.gpr();
2676
2677 writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR);
2678
2679 if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
2680 speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
2681
2682 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
2683 m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
2684
2685 // Refuse to handle bizarre lengths.
2686 speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(0x7ffffffe)));
2687
2688 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
2689
2690 m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2691 m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2692
2693 m_jit.add32(TrustedImm32(1), storageLengthGPR);
2694 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
2695 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
2696 m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
2697
2698 MacroAssembler::Jump done = m_jit.jump();
2699
2700 slowPath.link(&m_jit);
2701
2702 silentSpillAllRegisters(storageGPR, storageLengthGPR);
2703 callOperation(operationArrayPush, storageGPR, storageLengthGPR, valueTagGPR, valuePayloadGPR, baseGPR);
2704 silentFillAllRegisters(storageGPR, storageLengthGPR);
2705
2706 done.link(&m_jit);
2707
2708 jsValueResult(storageGPR, storageLengthGPR, m_compileIndex);
2709 break;
2710 }
2711
2712 case ArrayPop: {
2713 SpeculateCellOperand base(this, node.child1());
2714 GPRTemporary valueTag(this);
2715 GPRTemporary valuePayload(this);
2716 GPRTemporary storage(this);
2717 GPRTemporary storageLength(this);
2718
2719 GPRReg baseGPR = base.gpr();
2720 GPRReg valueTagGPR = valueTag.gpr();
2721 GPRReg valuePayloadGPR = valuePayload.gpr();
2722 GPRReg storageGPR = storage.gpr();
2723 GPRReg storageLengthGPR = storageLength.gpr();
2724
2725 if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
2726 speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
2727
2728 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
2729 m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
2730
2731 MacroAssembler::Jump emptyArrayCase = m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR);
2732
2733 m_jit.sub32(TrustedImm32(1), storageLengthGPR);
2734
2735 MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
2736
2737 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), valueTagGPR);
2738 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), valuePayloadGPR);
2739
2740 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
2741
2742 MacroAssembler::Jump holeCase = m_jit.branch32(MacroAssembler::Equal, TrustedImm32(JSValue::EmptyValueTag), valueTagGPR);
2743
2744 m_jit.store32(TrustedImm32(JSValue::EmptyValueTag), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2745
2746 m_jit.sub32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
2747
2748 MacroAssembler::JumpList done;
2749
2750 done.append(m_jit.jump());
2751
2752 holeCase.link(&m_jit);
2753 emptyArrayCase.link(&m_jit);
2754 m_jit.move(MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR);
2755 m_jit.move(MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR);
2756 done.append(m_jit.jump());
2757
2758 slowCase.link(&m_jit);
2759
2760 silentSpillAllRegisters(valueTagGPR, valuePayloadGPR);
2761 callOperation(operationArrayPop, valueTagGPR, valuePayloadGPR, baseGPR);
2762 silentFillAllRegisters(valueTagGPR, valuePayloadGPR);
2763
2764 done.link(&m_jit);
2765
2766 jsValueResult(valueTagGPR, valuePayloadGPR, m_compileIndex);
2767 break;
2768 }
2769
2770 case DFG::Jump: {
2771 BlockIndex taken = node.takenBlockIndex();
2772 jump(taken);
2773 noResult(m_compileIndex);
2774 break;
2775 }
2776
2777 case Branch:
2778 if (isStrictInt32(node.child1().index()) || at(node.child1()).shouldSpeculateInteger()) {
2779 SpeculateIntegerOperand op(this, node.child1());
2780
2781 BlockIndex taken = node.takenBlockIndex();
2782 BlockIndex notTaken = node.notTakenBlockIndex();
2783
2784 MacroAssembler::ResultCondition condition = MacroAssembler::NonZero;
2785
2786 if (taken == (m_block + 1)) {
2787 condition = MacroAssembler::Zero;
2788 BlockIndex tmp = taken;
2789 taken = notTaken;
2790 notTaken = tmp;
2791 }
2792
2793 branchTest32(condition, op.gpr(), taken);
2794 jump(notTaken);
2795
2796 noResult(m_compileIndex);
2797 break;
2798 }
2799 emitBranch(node);
2800 break;
2801
2802 case Return: {
2803 ASSERT(GPRInfo::callFrameRegister != GPRInfo::regT2);
2804 ASSERT(GPRInfo::regT1 != GPRInfo::returnValueGPR);
2805 ASSERT(GPRInfo::returnValueGPR != GPRInfo::callFrameRegister);
2806
2807#if DFG_ENABLE(SUCCESS_STATS)
2808 static SamplingCounter counter("SpeculativeJIT");
2809 m_jit.emitCount(counter);
2810#endif
2811
2812 // Return the result in returnValueGPR.
2813 JSValueOperand op1(this, node.child1());
2814 op1.fill();
2815 if (op1.isDouble())
2816 boxDouble(op1.fpr(), GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
2817 else {
2818 if (op1.payloadGPR() == GPRInfo::returnValueGPR2 && op1.tagGPR() == GPRInfo::returnValueGPR)
2819 m_jit.swap(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2);
2820 else if (op1.payloadGPR() == GPRInfo::returnValueGPR2) {
2821 m_jit.move(op1.payloadGPR(), GPRInfo::returnValueGPR);
2822 m_jit.move(op1.tagGPR(), GPRInfo::returnValueGPR2);
2823 } else {
2824 m_jit.move(op1.tagGPR(), GPRInfo::returnValueGPR2);
2825 m_jit.move(op1.payloadGPR(), GPRInfo::returnValueGPR);
2826 }
2827 }
2828
2829 // Grab the return address.
2830 m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, GPRInfo::regT2);
2831 // Restore our caller's "r".
2832 m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, GPRInfo::callFrameRegister);
2833 // Return.
2834 m_jit.restoreReturnAddressBeforeReturn(GPRInfo::regT2);
2835 m_jit.ret();
2836
2837 noResult(m_compileIndex);
2838 break;
2839 }
2840
2841 case Throw:
2842 case ThrowReferenceError: {
2843 // We expect that throw statements are rare and are intended to exit the code block
2844 // anyway, so we just OSR back to the old JIT for now.
2845 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
2846 break;
2847 }
2848
2849 case ToPrimitive: {
2850 if (at(node.child1()).shouldSpeculateInteger()) {
2851 // It's really profitable to speculate integer, since it's really cheap,
2852 // it means we don't have to do any real work, and we emit a lot less code.
2853
2854 SpeculateIntegerOperand op1(this, node.child1());
2855 GPRTemporary result(this, op1);
2856
2857 ASSERT(op1.format() == DataFormatInteger);
2858 m_jit.move(op1.gpr(), result.gpr());
2859
2860 integerResult(result.gpr(), m_compileIndex);
2861 break;
2862 }
2863
2864 // FIXME: Add string speculation here.
2865
2866 JSValueOperand op1(this, node.child1());
2867 GPRTemporary resultTag(this, op1);
2868 GPRTemporary resultPayload(this, op1, false);
2869
2870 GPRReg op1TagGPR = op1.tagGPR();
2871 GPRReg op1PayloadGPR = op1.payloadGPR();
2872 GPRReg resultTagGPR = resultTag.gpr();
2873 GPRReg resultPayloadGPR = resultPayload.gpr();
2874
2875 op1.use();
2876
2877 if (!(m_state.forNode(node.child1()).m_type & ~(PredictNumber | PredictBoolean))) {
2878 m_jit.move(op1TagGPR, resultTagGPR);
2879 m_jit.move(op1PayloadGPR, resultPayloadGPR);
2880 } else {
2881 MacroAssembler::JumpList alreadyPrimitive;
2882
2883 alreadyPrimitive.append(m_jit.branch32(MacroAssembler::NotEqual, op1TagGPR, TrustedImm32(JSValue::CellTag)));
2884 alreadyPrimitive.append(m_jit.branchPtr(MacroAssembler::Equal, MacroAssembler::Address(op1PayloadGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSString::s_info)));
2885
2886 silentSpillAllRegisters(resultTagGPR, resultPayloadGPR);
2887 callOperation(operationToPrimitive, resultTagGPR, resultPayloadGPR, op1TagGPR, op1PayloadGPR);
2888 silentFillAllRegisters(resultTagGPR, resultPayloadGPR);
2889
2890 MacroAssembler::Jump done = m_jit.jump();
2891
2892 alreadyPrimitive.link(&m_jit);
2893 m_jit.move(op1TagGPR, resultTagGPR);
2894 m_jit.move(op1PayloadGPR, resultPayloadGPR);
2895
2896 done.link(&m_jit);
2897 }
2898
2899 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
2900 break;
2901 }
2902
2903 case StrCat:
2904 case NewArray: {
2905 // We really don't want to grow the register file just to do a StrCat or NewArray.
2906 // Say we have 50 functions on the stack that all have a StrCat in them that has
2907 // upwards of 10 operands. In the DFG this would mean that each one gets
2908 // some random virtual register, and then to do the StrCat we'd need a second
2909 // span of 10 operands just to have somewhere to copy the 10 operands to, where
2910 // they'd be contiguous and we could easily tell the C code how to find them.
2911 // Ugly! So instead we use the scratchBuffer infrastructure in JSGlobalData. That
2912 // way, those 50 functions will share the same scratchBuffer for offloading their
2913 // StrCat operands. It's about as good as we can do, unless we start doing
2914 // virtual register coalescing to ensure that operands to StrCat get spilled
2915 // in exactly the place where StrCat wants them, or else have the StrCat
2916 // refer to those operands' SetLocal instructions to force them to spill in
2917 // the right place. Basically, any way you cut it, the current approach
2918 // probably has the best balance of performance and sensibility in the sense
2919 // that it does not increase the complexity of the DFG JIT just to make StrCat
2920 // fast and pretty.
2921
2922 size_t scratchSize = sizeof(EncodedJSValue) * node.numChildren();
2923 ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(scratchSize);
2924 EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
2925
2926 for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
2927 JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
2928 GPRReg opTagGPR = operand.tagGPR();
2929 GPRReg opPayloadGPR = operand.payloadGPR();
2930 operand.use();
2931
2932 m_jit.store32(opTagGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
2933 m_jit.store32(opPayloadGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
2934 }
2935
2936 flushRegisters();
2937
2938 if (scratchSize) {
2939 GPRTemporary scratch(this);
2940
2941 // Tell GC mark phase how much of the scratch buffer is active during call.
2942 m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
2943 m_jit.storePtr(TrustedImmPtr(scratchSize), scratch.gpr());
2944 }
2945
2946 GPRResult resultPayload(this);
2947 GPRResult2 resultTag(this);
2948
2949 callOperation(op == StrCat ? operationStrCat : operationNewArray, resultTag.gpr(), resultPayload.gpr(), static_cast<void *>(buffer), node.numChildren());
2950
2951 if (scratchSize) {
2952 GPRTemporary scratch(this);
2953
2954 m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
2955 m_jit.storePtr(TrustedImmPtr(0), scratch.gpr());
2956 }
2957
2958 // FIXME: make the callOperation above explicitly return a cell result, or jitAssert the tag is a cell tag.
2959 cellResult(resultPayload.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
2960 break;
2961 }
2962
2963 case NewArrayBuffer: {
2964 flushRegisters();
2965 GPRResult resultPayload(this);
2966 GPRResult2 resultTag(this);
2967
2968 callOperation(operationNewArrayBuffer, resultTag.gpr(), resultPayload.gpr(), node.startConstant(), node.numConstants());
2969
2970 // FIXME: make the callOperation above explicitly return a cell result, or jitAssert the tag is a cell tag.
2971 cellResult(resultPayload.gpr(), m_compileIndex);
2972 break;
2973 }
2974
2975 case NewRegexp: {
2976 flushRegisters();
2977 GPRResult resultPayload(this);
2978 GPRResult2 resultTag(this);
2979
2980 callOperation(operationNewRegexp, resultTag.gpr(), resultPayload.gpr(), m_jit.codeBlock()->regexp(node.regexpIndex()));
2981
2982 // FIXME: make the callOperation above explicitly return a cell result, or jitAssert the tag is a cell tag.
2983 cellResult(resultPayload.gpr(), m_compileIndex);
2984 break;
2985 }
2986
2987 case ConvertThis: {
2988 if (isObjectPrediction(m_state.forNode(node.child1()).m_type)) {
2989 SpeculateCellOperand thisValue(this, node.child1());
2990 GPRTemporary result(this, thisValue);
2991 m_jit.move(thisValue.gpr(), result.gpr());
2992 cellResult(result.gpr(), m_compileIndex);
2993 break;
2994 }
2995
2996 if (isOtherPrediction(at(node.child1()).prediction())) {
2997 JSValueOperand thisValue(this, node.child1());
2998 GPRTemporary scratch(this);
2999
3000 GPRReg thisValueTagGPR = thisValue.tagGPR();
3001 GPRReg scratchGPR = scratch.gpr();
3002
3003 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
3004 m_jit.move(thisValueTagGPR, scratchGPR);
3005 m_jit.or32(TrustedImm32(1), scratchGPR);
3006 // This is hard. It would be better to save the value, but we can't quite do it,
3007 // since this operation does not otherwise get the payload.
3008 speculationCheck(BadType, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::NotEqual, scratchGPR, TrustedImm32(JSValue::NullTag)));
3009
3010 m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.globalThisObjectFor(node.codeOrigin)), scratchGPR);
3011 cellResult(scratchGPR, m_compileIndex);
3012 break;
3013 }
3014
3015 if (isObjectPrediction(at(node.child1()).prediction())) {
3016 SpeculateCellOperand thisValue(this, node.child1());
3017 GPRReg thisValueGPR = thisValue.gpr();
3018
3019 if (!isObjectPrediction(m_state.forNode(node.child1()).m_type))
3020 speculationCheck(BadType, JSValueSource::unboxedCell(thisValueGPR), node.child1(), m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(thisValueGPR, JSCell::classInfoOffset()), JITCompiler::TrustedImmPtr(&JSString::s_info)));
3021
3022 GPRTemporary result(this, thisValue);
3023 GPRReg resultGPR = result.gpr();
3024 m_jit.move(thisValueGPR, resultGPR);
3025 cellResult(resultGPR, m_compileIndex);
3026 break;
3027 }
3028
3029 JSValueOperand thisValue(this, node.child1());
3030 GPRReg thisValueTagGPR = thisValue.tagGPR();
3031 GPRReg thisValuePayloadGPR = thisValue.payloadGPR();
3032
3033 flushRegisters();
3034
3035 GPRResult2 resultTag(this);
3036 GPRResult resultPayload(this);
3037 callOperation(operationConvertThis, resultTag.gpr(), resultPayload.gpr(), thisValueTagGPR, thisValuePayloadGPR);
3038
3039 cellResult(resultPayload.gpr(), m_compileIndex);
3040 break;
3041 }
3042
3043 case CreateThis: {
3044 // Note that there is not so much profit to speculate here. The only things we
3045 // speculate on are (1) that it's a cell, since that eliminates cell checks
3046 // later if the proto is reused, and (2) if we have a FinalObject prediction
3047 // then we speculate because we want to get recompiled if it isn't (since
3048 // otherwise we'd start taking slow path a lot).
3049
3050 SpeculateCellOperand proto(this, node.child1());
3051 GPRTemporary result(this);
3052 GPRTemporary scratch(this);
3053
3054 GPRReg protoGPR = proto.gpr();
3055 GPRReg resultGPR = result.gpr();
3056 GPRReg scratchGPR = scratch.gpr();
3057
3058 proto.use();
3059
3060 MacroAssembler::JumpList slowPath;
3061
3062 // Need to verify that the prototype is an object. If we have reason to believe
3063 // that it's a FinalObject then we speculate on that directly. Otherwise we
3064 // do the slow (structure-based) check.
3065 if (at(node.child1()).shouldSpeculateFinalObject()) {
3066 if (!isFinalObjectPrediction(m_state.forNode(node.child1()).m_type))
3067 speculationCheck(BadType, JSValueSource::unboxedCell(protoGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(protoGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSFinalObject::s_info)));
3068 } else {
3069 m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSCell::structureOffset()), scratchGPR);
3070 slowPath.append(m_jit.branch8(MacroAssembler::Below, MacroAssembler::Address(scratchGPR, Structure::typeInfoTypeOffset()), MacroAssembler::TrustedImm32(ObjectType)));
3071 }
3072
3073 // Load the inheritorID (the Structure that objects who have protoGPR as the prototype
3074 // use to refer to that prototype). If the inheritorID is not set, go to slow path.
3075 m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSObject::offsetOfInheritorID()), scratchGPR);
3076 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, scratchGPR));
3077
3078 emitAllocateJSFinalObject(scratchGPR, resultGPR, scratchGPR, slowPath);
3079
3080 MacroAssembler::Jump done = m_jit.jump();
3081
3082 slowPath.link(&m_jit);
3083
3084 silentSpillAllRegisters(resultGPR);
3085 if (node.codeOrigin.inlineCallFrame)
3086 callOperation(operationCreateThisInlined, resultGPR, protoGPR, node.codeOrigin.inlineCallFrame->callee.get());
3087 else
3088 callOperation(operationCreateThis, resultGPR, protoGPR);
3089 silentFillAllRegisters(resultGPR);
3090
3091 done.link(&m_jit);
3092
3093 cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
3094 break;
3095 }
3096
3097 case NewObject: {
3098 GPRTemporary result(this);
3099 GPRTemporary scratch(this);
3100
3101 GPRReg resultGPR = result.gpr();
3102 GPRReg scratchGPR = scratch.gpr();
3103
3104 MacroAssembler::JumpList slowPath;
3105
3106 emitAllocateJSFinalObject(MacroAssembler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)->emptyObjectStructure()), resultGPR, scratchGPR, slowPath);
3107
3108 MacroAssembler::Jump done = m_jit.jump();
3109
3110 slowPath.link(&m_jit);
3111
3112 silentSpillAllRegisters(resultGPR);
3113 callOperation(operationNewObject, resultGPR);
3114 silentFillAllRegisters(resultGPR);
3115
3116 done.link(&m_jit);
3117
3118 cellResult(resultGPR, m_compileIndex);
3119 break;
3120 }
3121
3122 case GetCallee: {
3123 GPRTemporary result(this);
3124 m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(RegisterFile::Callee)), result.gpr());
3125 cellResult(result.gpr(), m_compileIndex);
3126 break;
3127 }
3128
3129 case GetScopeChain: {
3130 GPRTemporary result(this);
3131 GPRReg resultGPR = result.gpr();
3132
3133 m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(RegisterFile::ScopeChain)), resultGPR);
3134 bool checkTopLevel = m_jit.codeBlock()->codeType() == FunctionCode && m_jit.codeBlock()->needsFullScopeChain();
3135 int skip = node.scopeChainDepth();
3136 ASSERT(skip || !checkTopLevel);
3137 if (checkTopLevel && skip--) {
3138 JITCompiler::Jump activationNotCreated;
3139 if (checkTopLevel)
3140 activationNotCreated = m_jit.branchTestPtr(JITCompiler::Zero, JITCompiler::addressFor(static_cast<VirtualRegister>(m_jit.codeBlock()->activationRegister())));
3141 m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, next)), resultGPR);
3142 activationNotCreated.link(&m_jit);
3143 }
3144 while (skip--)
3145 m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, next)), resultGPR);
3146
3147 m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, object)), resultGPR);
3148
3149 cellResult(resultGPR, m_compileIndex);
3150 break;
3151 }
3152 case GetScopedVar: {
3153 SpeculateCellOperand scopeChain(this, node.child1());
3154 GPRTemporary resultTag(this);
3155 GPRTemporary resultPayload(this);
3156 GPRReg resultTagGPR = resultTag.gpr();
3157 GPRReg resultPayloadGPR = resultPayload.gpr();
3158 m_jit.loadPtr(JITCompiler::Address(scopeChain.gpr(), JSVariableObject::offsetOfRegisters()), resultPayloadGPR);
3159 m_jit.load32(JITCompiler::Address(resultPayloadGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
3160 m_jit.load32(JITCompiler::Address(resultPayloadGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
3161 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
3162 break;
3163 }
3164 case PutScopedVar: {
3165 SpeculateCellOperand scopeChain(this, node.child1());
3166 GPRTemporary scratchRegister(this);
3167 GPRReg scratchGPR = scratchRegister.gpr();
3168 m_jit.loadPtr(JITCompiler::Address(scopeChain.gpr(), JSVariableObject::offsetOfRegisters()), scratchGPR);
3169 JSValueOperand value(this, node.child2());
3170 m_jit.store32(value.tagGPR(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
3171 m_jit.store32(value.payloadGPR(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
3172 writeBarrier(scopeChain.gpr(), value.tagGPR(), node.child2(), WriteBarrierForVariableAccess, scratchGPR);
3173 noResult(m_compileIndex);
3174 break;
3175 }
3176
3177 case GetById: {
3178 if (!node.prediction()) {
3179 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
3180 break;
3181 }
3182
3183 if (isCellPrediction(at(node.child1()).prediction())) {
3184 SpeculateCellOperand base(this, node.child1());
3185 GPRTemporary resultTag(this, base);
3186 GPRTemporary resultPayload(this);
3187
3188 GPRReg baseGPR = base.gpr();
3189 GPRReg resultTagGPR = resultTag.gpr();
3190 GPRReg resultPayloadGPR = resultPayload.gpr();
3191 GPRReg scratchGPR;
3192
3193 if (resultTagGPR == baseGPR)
3194 scratchGPR = resultPayloadGPR;
3195 else
3196 scratchGPR = resultTagGPR;
3197
3198 base.use();
3199
3200 cachedGetById(node.codeOrigin, InvalidGPRReg, baseGPR, resultTagGPR, resultPayloadGPR, scratchGPR, node.identifierNumber());
3201
3202 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
3203 break;
3204 }
3205
3206 JSValueOperand base(this, node.child1());
3207 GPRTemporary resultTag(this, base);
3208 GPRTemporary resultPayload(this);
3209
3210 GPRReg baseTagGPR = base.tagGPR();
3211 GPRReg basePayloadGPR = base.payloadGPR();
3212 GPRReg resultTagGPR = resultTag.gpr();
3213 GPRReg resultPayloadGPR = resultPayload.gpr();
3214 GPRReg scratchGPR;
3215
3216 if (resultTagGPR == basePayloadGPR)
3217 scratchGPR = resultPayloadGPR;
3218 else
3219 scratchGPR = resultTagGPR;
3220
3221 base.use();
3222
3223 JITCompiler::Jump notCell = m_jit.branch32(JITCompiler::NotEqual, baseTagGPR, TrustedImm32(JSValue::CellTag));
3224
3225 cachedGetById(node.codeOrigin, baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, scratchGPR, node.identifierNumber(), notCell);
3226
3227 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
3228 break;
3229 }
3230
3231 case GetByIdFlush: {
3232 if (!node.prediction()) {
3233 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
3234 break;
3235 }
3236
3237 if (isCellPrediction(at(node.child1()).prediction())) {
3238 SpeculateCellOperand base(this, node.child1());
3239
3240 GPRReg baseGPR = base.gpr();
3241
3242 GPRResult resultTag(this);
3243 GPRResult2 resultPayload(this);
3244 GPRReg resultTagGPR = resultTag.gpr();
3245 GPRReg resultPayloadGPR = resultPayload.gpr();
3246
3247 GPRReg scratchGPR = selectScratchGPR(baseGPR, resultTagGPR, resultPayloadGPR);
3248
3249 base.use();
3250
3251 flushRegisters();
3252
3253 cachedGetById(node.codeOrigin, InvalidGPRReg, baseGPR, resultTagGPR, resultPayloadGPR, scratchGPR, node.identifierNumber(), JITCompiler::Jump(), DontSpill);
3254
3255 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
3256 break;
3257 }
3258
3259 JSValueOperand base(this, node.child1());
3260 GPRReg baseTagGPR = base.tagGPR();
3261 GPRReg basePayloadGPR = base.payloadGPR();
3262
3263 GPRResult resultTag(this);
3264 GPRResult2 resultPayload(this);
3265 GPRReg resultTagGPR = resultTag.gpr();
3266 GPRReg resultPayloadGPR = resultPayload.gpr();
3267
3268 GPRReg scratchGPR = selectScratchGPR(baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR);
3269
3270 base.use();
3271
3272 flushRegisters();
3273
3274 JITCompiler::Jump notCell = m_jit.branch32(JITCompiler::NotEqual, baseTagGPR, TrustedImm32(JSValue::CellTag));
3275
3276 cachedGetById(node.codeOrigin, baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, scratchGPR, node.identifierNumber(), notCell, DontSpill);
3277
3278 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
3279 break;
3280 }
3281
3282 case GetArrayLength: {
3283 SpeculateCellOperand base(this, node.child1());
3284 GPRReg baseGPR = base.gpr();
3285
3286 if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
3287 speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
3288
3289 GPRTemporary result(this);
3290 GPRReg resultGPR = result.gpr();
3291
3292 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR);
3293 m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR);
3294
3295 speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0)));
3296
3297 integerResult(resultGPR, m_compileIndex);
3298 break;
3299 }
3300
3301 case GetStringLength: {
3302 SpeculateCellOperand base(this, node.child1());
3303 GPRTemporary result(this);
3304
3305 GPRReg baseGPR = base.gpr();
3306 GPRReg resultGPR = result.gpr();
3307
3308 if (!isStringPrediction(m_state.forNode(node.child1()).m_type))
3309 speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSString::s_info)));
3310
3311 m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR);
3312
3313 integerResult(resultGPR, m_compileIndex);
3314 break;
3315 }
3316
3317 case GetInt8ArrayLength: {
3318 compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type));
3319 break;
3320 }
3321 case GetInt16ArrayLength: {
3322 compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type));
3323 break;
3324 }
3325 case GetInt32ArrayLength: {
3326 compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type));
3327 break;
3328 }
3329 case GetUint8ArrayLength: {
3330 compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type));
3331 break;
3332 }
3333 case GetUint8ClampedArrayLength: {
3334 compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type));
3335 break;
3336 }
3337 case GetUint16ArrayLength: {
3338 compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type));
3339 break;
3340 }
3341 case GetUint32ArrayLength: {
3342 compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type));
3343 break;
3344 }
3345 case GetFloat32ArrayLength: {
3346 compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type));
3347 break;
3348 }
3349 case GetFloat64ArrayLength: {
3350 compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type));
3351 break;
3352 }
3353
3354 case CheckFunction: {
3355 SpeculateCellOperand function(this, node.child1());
3356 speculationCheck(BadCache, JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node.function()));
3357 noResult(m_compileIndex);
3358 break;
3359 }
3360
3361 case CheckStructure: {
3362 if (m_state.forNode(node.child1()).m_structure.isSubsetOf(node.structureSet())) {
3363 noResult(m_compileIndex);
3364 break;
3365 }
3366
3367 SpeculateCellOperand base(this, node.child1());
3368
3369 ASSERT(node.structureSet().size());
3370
3371 if (node.structureSet().size() == 1)
3372 speculationCheck(BadCache, JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, JITCompiler::Address(base.gpr(), JSCell::structureOffset()), node.structureSet()[0]));
3373 else {
3374 GPRTemporary structure(this);
3375
3376 m_jit.loadPtr(JITCompiler::Address(base.gpr(), JSCell::structureOffset()), structure.gpr());
3377
3378 JITCompiler::JumpList done;
3379
3380 for (size_t i = 0; i < node.structureSet().size() - 1; ++i)
3381 done.append(m_jit.branchWeakPtr(JITCompiler::Equal, structure.gpr(), node.structureSet()[i]));
3382
3383 speculationCheck(BadCache, JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, structure.gpr(), node.structureSet().last()));
3384
3385 done.link(&m_jit);
3386 }
3387
3388 noResult(m_compileIndex);
3389 break;
3390 }
3391
3392 case PutStructure: {
3393 SpeculateCellOperand base(this, node.child1());
3394 GPRReg baseGPR = base.gpr();
3395
3396 m_jit.addWeakReferenceTransition(
3397 node.codeOrigin.codeOriginOwner(),
3398 node.structureTransitionData().previousStructure,
3399 node.structureTransitionData().newStructure);
3400
3401#if ENABLE(GGC) || ENABLE(WRITE_BARRIER_PROFILING)
3402 // Must always emit this write barrier as the structure transition itself requires it
3403 writeBarrier(baseGPR, node.structureTransitionData().newStructure, WriteBarrierForGenericAccess);
3404#endif
3405
3406 m_jit.storePtr(MacroAssembler::TrustedImmPtr(node.structureTransitionData().newStructure), MacroAssembler::Address(baseGPR, JSCell::structureOffset()));
3407
3408 noResult(m_compileIndex);
3409 break;
3410 }
3411
3412 case GetPropertyStorage: {
3413 SpeculateCellOperand base(this, node.child1());
3414 GPRTemporary result(this, base);
3415
3416 GPRReg baseGPR = base.gpr();
3417 GPRReg resultGPR = result.gpr();
3418
3419 m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
3420
3421 storageResult(resultGPR, m_compileIndex);
3422 break;
3423 }
3424
3425 case GetIndexedPropertyStorage: {
3426 compileGetIndexedPropertyStorage(node);
3427 break;
3428 }
3429
3430 case GetByOffset: {
3431 StorageOperand storage(this, node.child1());
3432 GPRTemporary resultTag(this, storage);
3433 GPRTemporary resultPayload(this);
3434
3435 GPRReg storageGPR = storage.gpr();
3436 GPRReg resultTagGPR = resultTag.gpr();
3437 GPRReg resultPayloadGPR = resultPayload.gpr();
3438
3439 StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node.storageAccessDataIndex()];
3440
3441 m_jit.load32(JITCompiler::Address(storageGPR, storageAccessData.offset * sizeof(EncodedJSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
3442 m_jit.load32(JITCompiler::Address(storageGPR, storageAccessData.offset * sizeof(EncodedJSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
3443
3444 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
3445 break;
3446 }
3447
3448 case PutByOffset: {
3449#if ENABLE(GGC) || ENABLE(WRITE_BARRIER_PROFILING)
3450 SpeculateCellOperand base(this, node.child1());
3451#endif
3452 StorageOperand storage(this, node.child2());
3453 JSValueOperand value(this, node.child3());
3454
3455 GPRReg storageGPR = storage.gpr();
3456 GPRReg valueTagGPR = value.tagGPR();
3457 GPRReg valuePayloadGPR = value.payloadGPR();
3458
3459#if ENABLE(GGC) || ENABLE(WRITE_BARRIER_PROFILING)
3460 writeBarrier(base.gpr(), valueTagGPR, node.child3(), WriteBarrierForPropertyAccess);
3461#endif
3462
3463 StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node.storageAccessDataIndex()];
3464
3465 m_jit.storePtr(valueTagGPR, JITCompiler::Address(storageGPR, storageAccessData.offset * sizeof(EncodedJSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
3466 m_jit.storePtr(valuePayloadGPR, JITCompiler::Address(storageGPR, storageAccessData.offset * sizeof(EncodedJSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
3467
3468 noResult(m_compileIndex);
3469 break;
3470 }
3471
3472 case PutById: {
3473 SpeculateCellOperand base(this, node.child1());
3474 JSValueOperand value(this, node.child2());
3475 GPRTemporary scratch(this);
3476
3477 GPRReg baseGPR = base.gpr();
3478 GPRReg valueTagGPR = value.tagGPR();
3479 GPRReg valuePayloadGPR = value.payloadGPR();
3480 GPRReg scratchGPR = scratch.gpr();
3481
3482 base.use();
3483 value.use();
3484
3485 cachedPutById(node.codeOrigin, baseGPR, valueTagGPR, valuePayloadGPR, node.child2(), scratchGPR, node.identifierNumber(), NotDirect);
3486
3487 noResult(m_compileIndex, UseChildrenCalledExplicitly);
3488 break;
3489 }
3490
3491 case PutByIdDirect: {
3492 SpeculateCellOperand base(this, node.child1());
3493 JSValueOperand value(this, node.child2());
3494 GPRTemporary scratch(this);
3495
3496 GPRReg baseGPR = base.gpr();
3497 GPRReg valueTagGPR = value.tagGPR();
3498 GPRReg valuePayloadGPR = value.payloadGPR();
3499 GPRReg scratchGPR = scratch.gpr();
3500
3501 base.use();
3502 value.use();
3503
3504 cachedPutById(node.codeOrigin, baseGPR, valueTagGPR, valuePayloadGPR, node.child2(), scratchGPR, node.identifierNumber(), Direct);
3505
3506 noResult(m_compileIndex, UseChildrenCalledExplicitly);
3507 break;
3508 }
3509
3510 case GetGlobalVar: {
3511 GPRTemporary result(this);
3512 GPRTemporary scratch(this);
3513
3514 JSVariableObject* globalObject = m_jit.globalObjectFor(node.codeOrigin);
3515 m_jit.loadPtr(const_cast<WriteBarrier<Unknown>**>(globalObject->addressOfRegisters()), result.gpr());
3516 m_jit.load32(JITCompiler::tagForGlobalVar(result.gpr(), node.varNumber()), scratch.gpr());
3517 m_jit.load32(JITCompiler::payloadForGlobalVar(result.gpr(), node.varNumber()), result.gpr());
3518
3519 jsValueResult(scratch.gpr(), result.gpr(), m_compileIndex);
3520 break;
3521 }
3522
3523 case PutGlobalVar: {
3524 JSValueOperand value(this, node.child1());
3525 GPRTemporary globalObject(this);
3526 GPRTemporary scratch(this);
3527
3528 GPRReg globalObjectReg = globalObject.gpr();
3529 GPRReg scratchReg = scratch.gpr();
3530
3531 m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)), globalObjectReg);
3532
3533 writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.tagGPR(), node.child1(), WriteBarrierForVariableAccess, scratchReg);
3534
3535 m_jit.loadPtr(MacroAssembler::Address(globalObjectReg, JSVariableObject::offsetOfRegisters()), scratchReg);
3536 m_jit.store32(value.tagGPR(), JITCompiler::tagForGlobalVar(scratchReg, node.varNumber()));
3537 m_jit.store32(value.payloadGPR(), JITCompiler::payloadForGlobalVar(scratchReg, node.varNumber()));
3538
3539 noResult(m_compileIndex);
3540 break;
3541 }
3542
3543 case CheckHasInstance: {
3544 SpeculateCellOperand base(this, node.child1());
3545 GPRTemporary structure(this);
3546
3547 // Speculate that base 'ImplementsDefaultHasInstance'.
3548 m_jit.loadPtr(MacroAssembler::Address(base.gpr(), JSCell::structureOffset()), structure.gpr());
3549 speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTest8(MacroAssembler::Zero, MacroAssembler::Address(structure.gpr(), Structure::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(ImplementsDefaultHasInstance)));
3550
3551 noResult(m_compileIndex);
3552 break;
3553 }
3554
3555 case InstanceOf: {
3556 compileInstanceOf(node);
3557 break;
3558 }
3559
3560 case IsUndefined: {
3561 JSValueOperand value(this, node.child1());
3562 GPRTemporary result(this);
3563
3564 JITCompiler::Jump isCell = m_jit.branch32(JITCompiler::Equal, value.tagGPR(), JITCompiler::TrustedImm32(JSValue::CellTag));
3565
3566 m_jit.compare32(JITCompiler::Equal, value.tagGPR(), TrustedImm32(JSValue::UndefinedTag), result.gpr());
3567 JITCompiler::Jump done = m_jit.jump();
3568
3569 isCell.link(&m_jit);
3570 m_jit.loadPtr(JITCompiler::Address(value.payloadGPR(), JSCell::structureOffset()), result.gpr());
3571 m_jit.test8(JITCompiler::NonZero, JITCompiler::Address(result.gpr(), Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined), result.gpr());
3572
3573 done.link(&m_jit);
3574 booleanResult(result.gpr(), m_compileIndex);
3575 break;
3576 }
3577
3578 case IsBoolean: {
3579 JSValueOperand value(this, node.child1());
3580 GPRTemporary result(this, value);
3581
3582 m_jit.compare32(JITCompiler::Equal, value.tagGPR(), JITCompiler::TrustedImm32(JSValue::BooleanTag), result.gpr());
3583 booleanResult(result.gpr(), m_compileIndex);
3584 break;
3585 }
3586
3587 case IsNumber: {
3588 JSValueOperand value(this, node.child1());
3589 GPRTemporary result(this, value);
3590
3591 m_jit.add32(TrustedImm32(1), value.tagGPR(), result.gpr());
3592 m_jit.compare32(JITCompiler::Below, result.gpr(), JITCompiler::TrustedImm32(JSValue::LowestTag + 1), result.gpr());
3593 booleanResult(result.gpr(), m_compileIndex);
3594 break;
3595 }
3596
3597 case IsString: {
3598 JSValueOperand value(this, node.child1());
3599 GPRTemporary result(this, value);
3600
3601 JITCompiler::Jump isNotCell = m_jit.branch32(JITCompiler::NotEqual, value.tagGPR(), JITCompiler::TrustedImm32(JSValue::CellTag));
3602
3603 m_jit.loadPtr(JITCompiler::Address(value.payloadGPR(), JSCell::structureOffset()), result.gpr());
3604 m_jit.compare8(JITCompiler::Equal, JITCompiler::Address(result.gpr(), Structure::typeInfoTypeOffset()), TrustedImm32(StringType), result.gpr());
3605 JITCompiler::Jump done = m_jit.jump();
3606
3607 isNotCell.link(&m_jit);
3608 m_jit.move(TrustedImm32(0), result.gpr());
3609
3610 done.link(&m_jit);
3611 booleanResult(result.gpr(), m_compileIndex);
3612 break;
3613 }
3614
3615 case IsObject: {
3616 JSValueOperand value(this, node.child1());
3617 GPRReg valueTagGPR = value.tagGPR();
3618 GPRReg valuePayloadGPR = value.payloadGPR();
3619 GPRResult result(this);
3620 GPRReg resultGPR = result.gpr();
3621 flushRegisters();
3622 callOperation(operationIsObject, resultGPR, valueTagGPR, valuePayloadGPR);
3623 booleanResult(result.gpr(), m_compileIndex);
3624 break;
3625 }
3626
3627 case IsFunction: {
3628 JSValueOperand value(this, node.child1());
3629 GPRReg valueTagGPR = value.tagGPR();
3630 GPRReg valuePayloadGPR = value.payloadGPR();
3631 GPRResult result(this);
3632 GPRReg resultGPR = result.gpr();
3633 flushRegisters();
3634 callOperation(operationIsFunction, resultGPR, valueTagGPR, valuePayloadGPR);
3635 booleanResult(result.gpr(), m_compileIndex);
3636 break;
3637 }
3638
3639 case Phi:
3640 case Flush:
3641 break;
3642
3643 case Breakpoint:
3644#if ENABLE(DEBUG_WITH_BREAKPOINT)
3645 m_jit.breakpoint();
3646#else
3647 ASSERT_NOT_REACHED();
3648#endif
3649 break;
3650
3651 case Call:
3652 case Construct:
3653 emitCall(node);
3654 break;
3655
3656 case Resolve: {
3657 flushRegisters();
3658 GPRResult resultPayload(this);
3659 GPRResult2 resultTag(this);
3660 callOperation(operationResolve, resultTag.gpr(), resultPayload.gpr(), identifier(node.identifierNumber()));
3661 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
3662 break;
3663 }
3664
3665 case ResolveBase: {
3666 flushRegisters();
3667 GPRResult resultPayload(this);
3668 GPRResult2 resultTag(this);
3669 callOperation(operationResolveBase, resultTag.gpr(), resultPayload.gpr(), identifier(node.identifierNumber()));
3670 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
3671 break;
3672 }
3673
3674 case ResolveBaseStrictPut: {
3675 flushRegisters();
3676 GPRResult resultPayload(this);
3677 GPRResult2 resultTag(this);
3678 callOperation(operationResolveBaseStrictPut, resultTag.gpr(), resultPayload.gpr(), identifier(node.identifierNumber()));
3679 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
3680 break;
3681 }
3682
3683 case ResolveGlobal: {
3684 GPRTemporary globalObject(this);
3685 GPRTemporary resolveInfo(this);
3686 GPRTemporary resultTag(this);
3687 GPRTemporary resultPayload(this);
3688
3689 GPRReg globalObjectGPR = globalObject.gpr();
3690 GPRReg resolveInfoGPR = resolveInfo.gpr();
3691 GPRReg resultTagGPR = resultTag.gpr();
3692 GPRReg resultPayloadGPR = resultPayload.gpr();
3693
3694 ResolveGlobalData& data = m_jit.graph().m_resolveGlobalData[node.resolveGlobalDataIndex()];
3695 GlobalResolveInfo* resolveInfoAddress = &(m_jit.codeBlock()->globalResolveInfo(data.resolveInfoIndex));
3696
3697 // Check Structure of global object
3698 m_jit.move(JITCompiler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)), globalObjectGPR);
3699 m_jit.move(JITCompiler::TrustedImmPtr(resolveInfoAddress), resolveInfoGPR);
3700 m_jit.loadPtr(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, structure)), resultPayloadGPR);
3701
3702 JITCompiler::Jump structuresNotMatch = m_jit.branchPtr(JITCompiler::NotEqual, resultPayloadGPR, JITCompiler::Address(globalObjectGPR, JSCell::structureOffset()));
3703
3704 // Fast case
3705 m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfPropertyStorage()), resultPayloadGPR);
3706 m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR);
3707 m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
3708 m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
3709
3710 JITCompiler::Jump wasFast = m_jit.jump();
3711
3712 structuresNotMatch.link(&m_jit);
3713 silentSpillAllRegisters(resultTagGPR, resultPayloadGPR);
3714 callOperation(operationResolveGlobal, resultTagGPR, resultPayloadGPR, resolveInfoGPR, &m_jit.codeBlock()->identifier(data.identifierNumber));
3715 silentFillAllRegisters(resultTagGPR, resultPayloadGPR);
3716
3717 wasFast.link(&m_jit);
3718
3719 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
3720 break;
3721 }
3722
3723 case CreateActivation: {
3724 JSValueOperand value(this, node.child1());
3725 GPRTemporary result(this, value, false);
3726
3727 GPRReg valueTagGPR = value.tagGPR();
3728 GPRReg valuePayloadGPR = value.payloadGPR();
3729 GPRReg resultGPR = result.gpr();
3730
3731 m_jit.move(valuePayloadGPR, resultGPR);
3732
3733 JITCompiler::Jump alreadyCreated = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
3734
3735 silentSpillAllRegisters(resultGPR);
3736 callOperation(operationCreateActivation, resultGPR);
3737 silentFillAllRegisters(resultGPR);
3738
3739 alreadyCreated.link(&m_jit);
3740
3741 cellResult(resultGPR, m_compileIndex);
3742 break;
3743 }
3744
3745 case TearOffActivation: {
3746 JSValueOperand value(this, node.child1());
3747
3748 GPRReg valueTagGPR = value.tagGPR();
3749 GPRReg valuePayloadGPR = value.payloadGPR();
3750
3751 JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
3752
3753 silentSpillAllRegisters(InvalidGPRReg);
3754 callOperation(operationTearOffActivation, valuePayloadGPR);
3755 silentFillAllRegisters(InvalidGPRReg);
3756
3757 notCreated.link(&m_jit);
3758
3759 noResult(m_compileIndex);
3760 break;
3761 }
3762
3763 case NewFunctionNoCheck:
3764 compileNewFunctionNoCheck(node);
3765 break;
3766
3767 case NewFunction: {
3768 JSValueOperand value(this, node.child1());
3769 GPRTemporary result(this, value, false);
3770
3771 GPRReg valueTagGPR = value.tagGPR();
3772 GPRReg valuePayloadGPR = value.payloadGPR();
3773 GPRReg resultGPR = result.gpr();
3774
3775 m_jit.move(valuePayloadGPR, resultGPR);
3776
3777 JITCompiler::Jump alreadyCreated = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
3778
3779 silentSpillAllRegisters(resultGPR);
3780 callOperation(
3781 operationNewFunction, resultGPR, m_jit.codeBlock()->functionDecl(node.functionDeclIndex()));
3782 silentFillAllRegisters(resultGPR);
3783
3784 alreadyCreated.link(&m_jit);
3785
3786 cellResult(resultGPR, m_compileIndex);
3787 break;
3788 }
3789
3790 case NewFunctionExpression:
3791 compileNewFunctionExpression(node);
3792 break;
3793
3794 case ForceOSRExit: {
3795 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
3796 break;
3797 }
3798
3799 case Phantom:
3800 // This is a no-op.
3801 noResult(m_compileIndex);
3802 break;
3803
3804 case InlineStart:
3805 case Nop:
3806 case LastNodeType:
3807 ASSERT_NOT_REACHED();
3808 break;
3809 }
3810
3811 if (!m_compileOkay)
3812 return;
3813
3814 if (node.hasResult() && node.mustGenerate())
3815 use(m_compileIndex);
3816}
3817
3818#endif
3819
3820} } // namespace JSC::DFG
3821
3822#endif