]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGSpeculativeJIT32_64.cpp
8b2b6965d9aa57a60dd18cb3e1b9389f591286bb
[apple/javascriptcore.git] / dfg / DFGSpeculativeJIT32_64.cpp
1 /*
2 * Copyright (C) 2011, 2012, 2013, 2014 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
32 #include "ArrayPrototype.h"
33 #include "DFGAbstractInterpreterInlines.h"
34 #include "DFGCallArrayAllocatorSlowPathGenerator.h"
35 #include "DFGOperations.h"
36 #include "DFGSlowPathGenerator.h"
37 #include "Debugger.h"
38 #include "JSActivation.h"
39 #include "ObjectPrototype.h"
40 #include "JSCInlines.h"
41
42 namespace JSC { namespace DFG {
43
44 #if USE(JSVALUE32_64)
45
46 bool SpeculativeJIT::fillJSValue(Edge edge, GPRReg& tagGPR, GPRReg& payloadGPR, FPRReg& fpr)
47 {
48 // FIXME: For double we could fill with a FPR.
49 UNUSED_PARAM(fpr);
50
51 VirtualRegister virtualRegister = edge->virtualRegister();
52 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
53
54 switch (info.registerFormat()) {
55 case DataFormatNone: {
56
57 if (edge->hasConstant()) {
58 tagGPR = allocate();
59 payloadGPR = allocate();
60 m_jit.move(Imm32(valueOfJSConstant(edge.node()).tag()), tagGPR);
61 m_jit.move(Imm32(valueOfJSConstant(edge.node()).payload()), payloadGPR);
62 m_gprs.retain(tagGPR, virtualRegister, SpillOrderConstant);
63 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderConstant);
64 info.fillJSValue(*m_stream, tagGPR, payloadGPR, isInt32Constant(edge.node()) ? DataFormatJSInt32 : DataFormatJS);
65 } else {
66 DataFormat spillFormat = info.spillFormat();
67 ASSERT(spillFormat != DataFormatNone && spillFormat != DataFormatStorage);
68 tagGPR = allocate();
69 payloadGPR = allocate();
70 switch (spillFormat) {
71 case DataFormatInt32:
72 m_jit.move(TrustedImm32(JSValue::Int32Tag), tagGPR);
73 spillFormat = DataFormatJSInt32; // This will be used as the new register format.
74 break;
75 case DataFormatCell:
76 m_jit.move(TrustedImm32(JSValue::CellTag), tagGPR);
77 spillFormat = DataFormatJSCell; // This will be used as the new register format.
78 break;
79 case DataFormatBoolean:
80 m_jit.move(TrustedImm32(JSValue::BooleanTag), tagGPR);
81 spillFormat = DataFormatJSBoolean; // This will be used as the new register format.
82 break;
83 default:
84 m_jit.load32(JITCompiler::tagFor(virtualRegister), tagGPR);
85 break;
86 }
87 m_jit.load32(JITCompiler::payloadFor(virtualRegister), payloadGPR);
88 m_gprs.retain(tagGPR, virtualRegister, SpillOrderSpilled);
89 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderSpilled);
90 info.fillJSValue(*m_stream, tagGPR, payloadGPR, spillFormat == DataFormatJSDouble ? DataFormatJS : spillFormat);
91 }
92
93 return true;
94 }
95
96 case DataFormatInt32:
97 case DataFormatCell:
98 case DataFormatBoolean: {
99 GPRReg gpr = info.gpr();
100 // If the register has already been locked we need to take a copy.
101 if (m_gprs.isLocked(gpr)) {
102 payloadGPR = allocate();
103 m_jit.move(gpr, payloadGPR);
104 } else {
105 payloadGPR = gpr;
106 m_gprs.lock(gpr);
107 }
108 tagGPR = allocate();
109 uint32_t tag = JSValue::EmptyValueTag;
110 DataFormat fillFormat = DataFormatJS;
111 switch (info.registerFormat()) {
112 case DataFormatInt32:
113 tag = JSValue::Int32Tag;
114 fillFormat = DataFormatJSInt32;
115 break;
116 case DataFormatCell:
117 tag = JSValue::CellTag;
118 fillFormat = DataFormatJSCell;
119 break;
120 case DataFormatBoolean:
121 tag = JSValue::BooleanTag;
122 fillFormat = DataFormatJSBoolean;
123 break;
124 default:
125 RELEASE_ASSERT_NOT_REACHED();
126 break;
127 }
128 m_jit.move(TrustedImm32(tag), tagGPR);
129 m_gprs.release(gpr);
130 m_gprs.retain(tagGPR, virtualRegister, SpillOrderJS);
131 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderJS);
132 info.fillJSValue(*m_stream, tagGPR, payloadGPR, fillFormat);
133 return true;
134 }
135
136 case DataFormatJSDouble:
137 case DataFormatJS:
138 case DataFormatJSInt32:
139 case DataFormatJSCell:
140 case DataFormatJSBoolean: {
141 tagGPR = info.tagGPR();
142 payloadGPR = info.payloadGPR();
143 m_gprs.lock(tagGPR);
144 m_gprs.lock(payloadGPR);
145 return true;
146 }
147
148 case DataFormatStorage:
149 case DataFormatDouble:
150 // this type currently never occurs
151 RELEASE_ASSERT_NOT_REACHED();
152
153 default:
154 RELEASE_ASSERT_NOT_REACHED();
155 return true;
156 }
157 }
158
159 void SpeculativeJIT::cachedGetById(
160 CodeOrigin codeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR,
161 unsigned identifierNumber, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
162 {
163 // This is a hacky fix for when the register allocator decides to alias the base payload with the result tag. This only happens
164 // in the case of GetByIdFlush, which has a relatively expensive register allocation story already so we probably don't need to
165 // trip over one move instruction.
166 if (basePayloadGPR == resultTagGPR) {
167 RELEASE_ASSERT(basePayloadGPR != resultPayloadGPR);
168
169 if (baseTagGPROrNone == resultPayloadGPR) {
170 m_jit.swap(basePayloadGPR, baseTagGPROrNone);
171 baseTagGPROrNone = resultTagGPR;
172 } else
173 m_jit.move(basePayloadGPR, resultPayloadGPR);
174 basePayloadGPR = resultPayloadGPR;
175 }
176
177 JITGetByIdGenerator gen(
178 m_jit.codeBlock(), codeOrigin, usedRegisters(),
179 JSValueRegs(baseTagGPROrNone, basePayloadGPR),
180 JSValueRegs(resultTagGPR, resultPayloadGPR), spillMode);
181
182 gen.generateFastPath(m_jit);
183
184 JITCompiler::JumpList slowCases;
185 if (slowPathTarget.isSet())
186 slowCases.append(slowPathTarget);
187 slowCases.append(gen.slowPathJump());
188
189 OwnPtr<SlowPathGenerator> slowPath;
190 if (baseTagGPROrNone == InvalidGPRReg) {
191 slowPath = slowPathCall(
192 slowCases, this, operationGetByIdOptimize,
193 JSValueRegs(resultTagGPR, resultPayloadGPR), gen.stubInfo(),
194 static_cast<int32_t>(JSValue::CellTag), basePayloadGPR,
195 identifierUID(identifierNumber));
196 } else {
197 slowPath = slowPathCall(
198 slowCases, this, operationGetByIdOptimize,
199 JSValueRegs(resultTagGPR, resultPayloadGPR), gen.stubInfo(), baseTagGPROrNone,
200 basePayloadGPR, identifierUID(identifierNumber));
201 }
202
203 m_jit.addGetById(gen, slowPath.get());
204 addSlowPathGenerator(slowPath.release());
205 }
206
207 void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
208 {
209 JITPutByIdGenerator gen(
210 m_jit.codeBlock(), codeOrigin, usedRegisters(),
211 JSValueRegs::payloadOnly(basePayloadGPR), JSValueRegs(valueTagGPR, valuePayloadGPR),
212 scratchGPR, spillMode, m_jit.ecmaModeFor(codeOrigin), putKind);
213
214 gen.generateFastPath(m_jit);
215
216 JITCompiler::JumpList slowCases;
217 if (slowPathTarget.isSet())
218 slowCases.append(slowPathTarget);
219 slowCases.append(gen.slowPathJump());
220
221 OwnPtr<SlowPathGenerator> slowPath = slowPathCall(
222 slowCases, this, gen.slowPathFunction(), NoResult, gen.stubInfo(), valueTagGPR,
223 valuePayloadGPR, basePayloadGPR, identifierUID(identifierNumber));
224
225 m_jit.addPutById(gen, slowPath.get());
226 addSlowPathGenerator(slowPath.release());
227 }
228
229 void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool invert)
230 {
231 JSValueOperand arg(this, operand);
232 GPRReg argTagGPR = arg.tagGPR();
233 GPRReg argPayloadGPR = arg.payloadGPR();
234
235 GPRTemporary resultPayload(this, Reuse, arg, PayloadWord);
236 GPRReg resultPayloadGPR = resultPayload.gpr();
237
238 JITCompiler::Jump notCell;
239 JITCompiler::Jump notMasqueradesAsUndefined;
240 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
241 if (!isKnownCell(operand.node()))
242 notCell = branchNotCell(arg.jsValueRegs());
243
244 m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR);
245 notMasqueradesAsUndefined = m_jit.jump();
246 } else {
247 GPRTemporary localGlobalObject(this);
248 GPRTemporary remoteGlobalObject(this);
249
250 if (!isKnownCell(operand.node()))
251 notCell = branchNotCell(arg.jsValueRegs());
252
253 JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8(
254 JITCompiler::NonZero,
255 JITCompiler::Address(argPayloadGPR, JSCell::typeInfoFlagsOffset()),
256 JITCompiler::TrustedImm32(MasqueradesAsUndefined));
257
258 m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR);
259 notMasqueradesAsUndefined = m_jit.jump();
260
261 isMasqueradesAsUndefined.link(&m_jit);
262 GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
263 GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
264 m_jit.move(JITCompiler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode->origin.semantic)), localGlobalObjectGPR);
265 m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureIDOffset()), resultPayloadGPR);
266 m_jit.loadPtr(JITCompiler::Address(resultPayloadGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
267 m_jit.compare32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, resultPayloadGPR);
268 }
269
270 if (!isKnownCell(operand.node())) {
271 JITCompiler::Jump done = m_jit.jump();
272
273 notCell.link(&m_jit);
274 // null or undefined?
275 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
276 m_jit.move(argTagGPR, resultPayloadGPR);
277 m_jit.or32(TrustedImm32(1), resultPayloadGPR);
278 m_jit.compare32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultPayloadGPR, TrustedImm32(JSValue::NullTag), resultPayloadGPR);
279
280 done.link(&m_jit);
281 }
282
283 notMasqueradesAsUndefined.link(&m_jit);
284
285 booleanResult(resultPayloadGPR, m_currentNode);
286 }
287
288 void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branchNode, bool invert)
289 {
290 BasicBlock* taken = branchNode->branchData()->taken.block;
291 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
292
293 if (taken == nextBlock()) {
294 invert = !invert;
295 BasicBlock* tmp = taken;
296 taken = notTaken;
297 notTaken = tmp;
298 }
299
300 JSValueOperand arg(this, operand);
301 GPRReg argTagGPR = arg.tagGPR();
302 GPRReg argPayloadGPR = arg.payloadGPR();
303
304 GPRTemporary result(this, Reuse, arg, TagWord);
305 GPRReg resultGPR = result.gpr();
306
307 JITCompiler::Jump notCell;
308
309 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
310 if (!isKnownCell(operand.node()))
311 notCell = branchNotCell(arg.jsValueRegs());
312
313 jump(invert ? taken : notTaken, ForceJump);
314 } else {
315 GPRTemporary localGlobalObject(this);
316 GPRTemporary remoteGlobalObject(this);
317
318 if (!isKnownCell(operand.node()))
319 notCell = branchNotCell(arg.jsValueRegs());
320
321 branchTest8(JITCompiler::Zero,
322 JITCompiler::Address(argPayloadGPR, JSCell::typeInfoFlagsOffset()),
323 JITCompiler::TrustedImm32(MasqueradesAsUndefined),
324 invert ? taken : notTaken);
325
326 GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
327 GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
328 m_jit.move(TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode->origin.semantic)), localGlobalObjectGPR);
329 m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureIDOffset()), resultGPR);
330 m_jit.loadPtr(JITCompiler::Address(resultGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
331 branchPtr(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, invert ? notTaken : taken);
332 }
333
334 if (!isKnownCell(operand.node())) {
335 jump(notTaken, ForceJump);
336
337 notCell.link(&m_jit);
338 // null or undefined?
339 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
340 m_jit.move(argTagGPR, resultGPR);
341 m_jit.or32(TrustedImm32(1), resultGPR);
342 branch32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultGPR, JITCompiler::TrustedImm32(JSValue::NullTag), taken);
343 }
344
345 jump(notTaken);
346 }
347
348 bool SpeculativeJIT::nonSpeculativeCompareNull(Node* node, Edge operand, bool invert)
349 {
350 unsigned branchIndexInBlock = detectPeepHoleBranch();
351 if (branchIndexInBlock != UINT_MAX) {
352 Node* branchNode = m_block->at(branchIndexInBlock);
353
354 ASSERT(node->adjustedRefCount() == 1);
355
356 nonSpeculativePeepholeBranchNull(operand, branchNode, invert);
357
358 use(node->child1());
359 use(node->child2());
360 m_indexInBlock = branchIndexInBlock;
361 m_currentNode = branchNode;
362
363 return true;
364 }
365
366 nonSpeculativeNonPeepholeCompareNull(operand, invert);
367
368 return false;
369 }
370
371 void SpeculativeJIT::nonSpeculativePeepholeBranch(Node* node, Node* branchNode, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
372 {
373 BasicBlock* taken = branchNode->branchData()->taken.block;
374 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
375
376 JITCompiler::ResultCondition callResultCondition = JITCompiler::NonZero;
377
378 // The branch instruction will branch to the taken block.
379 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
380 if (taken == nextBlock()) {
381 cond = JITCompiler::invert(cond);
382 callResultCondition = JITCompiler::Zero;
383 BasicBlock* tmp = taken;
384 taken = notTaken;
385 notTaken = tmp;
386 }
387
388 JSValueOperand arg1(this, node->child1());
389 JSValueOperand arg2(this, node->child2());
390 GPRReg arg1TagGPR = arg1.tagGPR();
391 GPRReg arg1PayloadGPR = arg1.payloadGPR();
392 GPRReg arg2TagGPR = arg2.tagGPR();
393 GPRReg arg2PayloadGPR = arg2.payloadGPR();
394
395 JITCompiler::JumpList slowPath;
396
397 if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) {
398 GPRResult result(this);
399 GPRReg resultGPR = result.gpr();
400
401 arg1.use();
402 arg2.use();
403
404 flushRegisters();
405 callOperation(helperFunction, resultGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
406
407 branchTest32(callResultCondition, resultGPR, taken);
408 } else {
409 GPRTemporary result(this);
410 GPRReg resultGPR = result.gpr();
411
412 arg1.use();
413 arg2.use();
414
415 if (!isKnownInteger(node->child1().node()))
416 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg1TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
417 if (!isKnownInteger(node->child2().node()))
418 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg2TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
419
420 branch32(cond, arg1PayloadGPR, arg2PayloadGPR, taken);
421
422 if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node())) {
423 jump(notTaken, ForceJump);
424
425 slowPath.link(&m_jit);
426
427 silentSpillAllRegisters(resultGPR);
428 callOperation(helperFunction, resultGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
429 silentFillAllRegisters(resultGPR);
430
431 branchTest32(callResultCondition, resultGPR, taken);
432 }
433 }
434
435 jump(notTaken);
436
437 m_indexInBlock = m_block->size() - 1;
438 m_currentNode = branchNode;
439 }
440
441 template<typename JumpType>
442 class CompareAndBoxBooleanSlowPathGenerator
443 : public CallSlowPathGenerator<JumpType, S_JITOperation_EJJ, GPRReg> {
444 public:
445 CompareAndBoxBooleanSlowPathGenerator(
446 JumpType from, SpeculativeJIT* jit,
447 S_JITOperation_EJJ function, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload,
448 GPRReg arg2Tag, GPRReg arg2Payload)
449 : CallSlowPathGenerator<JumpType, S_JITOperation_EJJ, GPRReg>(
450 from, jit, function, NeedToSpill, result)
451 , m_arg1Tag(arg1Tag)
452 , m_arg1Payload(arg1Payload)
453 , m_arg2Tag(arg2Tag)
454 , m_arg2Payload(arg2Payload)
455 {
456 }
457
458 protected:
459 virtual void generateInternal(SpeculativeJIT* jit)
460 {
461 this->setUp(jit);
462 this->recordCall(
463 jit->callOperation(
464 this->m_function, this->m_result, m_arg1Tag, m_arg1Payload, m_arg2Tag,
465 m_arg2Payload));
466 jit->m_jit.and32(JITCompiler::TrustedImm32(1), this->m_result);
467 this->tearDown(jit);
468 }
469
470 private:
471 GPRReg m_arg1Tag;
472 GPRReg m_arg1Payload;
473 GPRReg m_arg2Tag;
474 GPRReg m_arg2Payload;
475 };
476
477 void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node* node, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
478 {
479 JSValueOperand arg1(this, node->child1());
480 JSValueOperand arg2(this, node->child2());
481 GPRReg arg1TagGPR = arg1.tagGPR();
482 GPRReg arg1PayloadGPR = arg1.payloadGPR();
483 GPRReg arg2TagGPR = arg2.tagGPR();
484 GPRReg arg2PayloadGPR = arg2.payloadGPR();
485
486 JITCompiler::JumpList slowPath;
487
488 if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) {
489 GPRResult result(this);
490 GPRReg resultPayloadGPR = result.gpr();
491
492 arg1.use();
493 arg2.use();
494
495 flushRegisters();
496 callOperation(helperFunction, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
497
498 booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
499 } else {
500 GPRTemporary resultPayload(this, Reuse, arg1, PayloadWord);
501 GPRReg resultPayloadGPR = resultPayload.gpr();
502
503 arg1.use();
504 arg2.use();
505
506 if (!isKnownInteger(node->child1().node()))
507 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg1TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
508 if (!isKnownInteger(node->child2().node()))
509 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg2TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
510
511 m_jit.compare32(cond, arg1PayloadGPR, arg2PayloadGPR, resultPayloadGPR);
512
513 if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node())) {
514 addSlowPathGenerator(adoptPtr(
515 new CompareAndBoxBooleanSlowPathGenerator<JITCompiler::JumpList>(
516 slowPath, this, helperFunction, resultPayloadGPR, arg1TagGPR,
517 arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR)));
518 }
519
520 booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
521 }
522 }
523
524 void SpeculativeJIT::nonSpeculativePeepholeStrictEq(Node* node, Node* branchNode, bool invert)
525 {
526 BasicBlock* taken = branchNode->branchData()->taken.block;
527 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
528
529 // The branch instruction will branch to the taken block.
530 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
531 if (taken == nextBlock()) {
532 invert = !invert;
533 BasicBlock* tmp = taken;
534 taken = notTaken;
535 notTaken = tmp;
536 }
537
538 JSValueOperand arg1(this, node->child1());
539 JSValueOperand arg2(this, node->child2());
540 GPRReg arg1TagGPR = arg1.tagGPR();
541 GPRReg arg1PayloadGPR = arg1.payloadGPR();
542 GPRReg arg2TagGPR = arg2.tagGPR();
543 GPRReg arg2PayloadGPR = arg2.payloadGPR();
544
545 GPRTemporary resultPayload(this, Reuse, arg1, PayloadWord);
546 GPRReg resultPayloadGPR = resultPayload.gpr();
547
548 arg1.use();
549 arg2.use();
550
551 if (isKnownCell(node->child1().node()) && isKnownCell(node->child2().node())) {
552 // see if we get lucky: if the arguments are cells and they reference the same
553 // cell, then they must be strictly equal.
554 branchPtr(JITCompiler::Equal, arg1PayloadGPR, arg2PayloadGPR, invert ? notTaken : taken);
555
556 silentSpillAllRegisters(resultPayloadGPR);
557 callOperation(operationCompareStrictEqCell, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
558 silentFillAllRegisters(resultPayloadGPR);
559
560 branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, resultPayloadGPR, taken);
561 } else {
562 // FIXME: Add fast paths for twoCells, number etc.
563
564 silentSpillAllRegisters(resultPayloadGPR);
565 callOperation(operationCompareStrictEq, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
566 silentFillAllRegisters(resultPayloadGPR);
567
568 branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, resultPayloadGPR, taken);
569 }
570
571 jump(notTaken);
572 }
573
574 void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node* node, bool invert)
575 {
576 JSValueOperand arg1(this, node->child1());
577 JSValueOperand arg2(this, node->child2());
578 GPRReg arg1TagGPR = arg1.tagGPR();
579 GPRReg arg1PayloadGPR = arg1.payloadGPR();
580 GPRReg arg2TagGPR = arg2.tagGPR();
581 GPRReg arg2PayloadGPR = arg2.payloadGPR();
582
583 GPRTemporary resultPayload(this, Reuse, arg1, PayloadWord);
584 GPRReg resultPayloadGPR = resultPayload.gpr();
585
586 arg1.use();
587 arg2.use();
588
589 if (isKnownCell(node->child1().node()) && isKnownCell(node->child2().node())) {
590 // see if we get lucky: if the arguments are cells and they reference the same
591 // cell, then they must be strictly equal.
592 // FIXME: this should flush registers instead of silent spill/fill.
593 JITCompiler::Jump notEqualCase = m_jit.branchPtr(JITCompiler::NotEqual, arg1PayloadGPR, arg2PayloadGPR);
594
595 m_jit.move(JITCompiler::TrustedImm32(!invert), resultPayloadGPR);
596 JITCompiler::Jump done = m_jit.jump();
597
598 notEqualCase.link(&m_jit);
599
600 silentSpillAllRegisters(resultPayloadGPR);
601 callOperation(operationCompareStrictEqCell, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
602 silentFillAllRegisters(resultPayloadGPR);
603
604 m_jit.andPtr(JITCompiler::TrustedImm32(1), resultPayloadGPR);
605
606 done.link(&m_jit);
607 } else {
608 // FIXME: Add fast paths.
609
610 silentSpillAllRegisters(resultPayloadGPR);
611 callOperation(operationCompareStrictEq, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
612 silentFillAllRegisters(resultPayloadGPR);
613
614 m_jit.andPtr(JITCompiler::TrustedImm32(1), resultPayloadGPR);
615 }
616
617 booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
618 }
619
620 void SpeculativeJIT::compileMiscStrictEq(Node* node)
621 {
622 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
623 JSValueOperand op2(this, node->child2(), ManualOperandSpeculation);
624 GPRTemporary result(this);
625
626 if (node->child1().useKind() == MiscUse)
627 speculateMisc(node->child1(), op1.jsValueRegs());
628 if (node->child2().useKind() == MiscUse)
629 speculateMisc(node->child2(), op2.jsValueRegs());
630
631 m_jit.move(TrustedImm32(0), result.gpr());
632 JITCompiler::Jump notEqual = m_jit.branch32(JITCompiler::NotEqual, op1.tagGPR(), op2.tagGPR());
633 m_jit.compare32(JITCompiler::Equal, op1.payloadGPR(), op2.payloadGPR(), result.gpr());
634 notEqual.link(&m_jit);
635 booleanResult(result.gpr(), node);
636 }
637
638 void SpeculativeJIT::emitCall(Node* node)
639 {
640 if (node->op() != Call)
641 ASSERT(node->op() == Construct);
642
643 // For constructors, the this argument is not passed but we have to make space
644 // for it.
645 int dummyThisArgument = node->op() == Call ? 0 : 1;
646
647 CallLinkInfo::CallType callType = node->op() == Call ? CallLinkInfo::Call : CallLinkInfo::Construct;
648
649 Edge calleeEdge = m_jit.graph().m_varArgChildren[node->firstChild()];
650 JSValueOperand callee(this, calleeEdge);
651 GPRReg calleeTagGPR = callee.tagGPR();
652 GPRReg calleePayloadGPR = callee.payloadGPR();
653 use(calleeEdge);
654
655 // The call instruction's first child is either the function (normal call) or the
656 // receiver (method call). subsequent children are the arguments.
657 int numPassedArgs = node->numChildren() - 1;
658
659 int numArgs = numPassedArgs + dummyThisArgument;
660
661 m_jit.store32(MacroAssembler::TrustedImm32(numArgs), calleeFramePayloadSlot(JSStack::ArgumentCount));
662 m_jit.store32(calleePayloadGPR, calleeFramePayloadSlot(JSStack::Callee));
663 m_jit.store32(calleeTagGPR, calleeFrameTagSlot(JSStack::Callee));
664
665 for (int i = 0; i < numPassedArgs; i++) {
666 Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
667 JSValueOperand arg(this, argEdge);
668 GPRReg argTagGPR = arg.tagGPR();
669 GPRReg argPayloadGPR = arg.payloadGPR();
670 use(argEdge);
671
672 m_jit.store32(argTagGPR, calleeArgumentTagSlot(i + dummyThisArgument));
673 m_jit.store32(argPayloadGPR, calleeArgumentPayloadSlot(i + dummyThisArgument));
674 }
675
676 flushRegisters();
677
678 GPRResult resultPayload(this);
679 GPRResult2 resultTag(this);
680 GPRReg resultPayloadGPR = resultPayload.gpr();
681 GPRReg resultTagGPR = resultTag.gpr();
682
683 JITCompiler::DataLabelPtr targetToCheck;
684 JITCompiler::JumpList slowPath;
685
686 m_jit.emitStoreCodeOrigin(node->origin.semantic);
687
688 slowPath.append(branchNotCell(callee.jsValueRegs()));
689 slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
690 m_jit.loadPtr(MacroAssembler::Address(calleePayloadGPR, OBJECT_OFFSETOF(JSFunction, m_scope)), resultPayloadGPR);
691 m_jit.storePtr(resultPayloadGPR, calleeFramePayloadSlot(JSStack::ScopeChain));
692 m_jit.storePtr(MacroAssembler::TrustedImm32(JSValue::CellTag), calleeFrameTagSlot(JSStack::ScopeChain));
693
694 JITCompiler::Call fastCall = m_jit.nearCall();
695
696 JITCompiler::Jump done = m_jit.jump();
697
698 slowPath.link(&m_jit);
699
700 // Callee payload needs to be in regT0, tag in regT1
701 if (calleeTagGPR == GPRInfo::regT0) {
702 if (calleePayloadGPR == GPRInfo::regT1)
703 m_jit.swap(GPRInfo::regT1, GPRInfo::regT0);
704 else {
705 m_jit.move(calleeTagGPR, GPRInfo::regT1);
706 m_jit.move(calleePayloadGPR, GPRInfo::regT0);
707 }
708 } else {
709 m_jit.move(calleePayloadGPR, GPRInfo::regT0);
710 m_jit.move(calleeTagGPR, GPRInfo::regT1);
711 }
712 CallLinkInfo* info = m_jit.codeBlock()->addCallLinkInfo();
713 m_jit.move(MacroAssembler::TrustedImmPtr(info), GPRInfo::regT2);
714 JITCompiler::Call slowCall = m_jit.nearCall();
715
716 done.link(&m_jit);
717
718 m_jit.setupResults(resultPayloadGPR, resultTagGPR);
719
720 jsValueResult(resultTagGPR, resultPayloadGPR, node, DataFormatJS, UseChildrenCalledExplicitly);
721
722 info->callType = callType;
723 info->codeOrigin = node->origin.semantic;
724 info->calleeGPR = calleePayloadGPR;
725 m_jit.addJSCall(fastCall, slowCall, targetToCheck, info);
726 }
727
728 template<bool strict>
729 GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnFormat)
730 {
731 AbstractValue& value = m_state.forNode(edge);
732 SpeculatedType type = value.m_type;
733 ASSERT(edge.useKind() != KnownInt32Use || !(value.m_type & ~SpecInt32));
734 m_interpreter.filter(value, SpecInt32);
735 VirtualRegister virtualRegister = edge->virtualRegister();
736 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
737
738 if (edge->hasConstant() && !isInt32Constant(edge.node())) {
739 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
740 returnFormat = DataFormatInt32;
741 return allocate();
742 }
743
744 switch (info.registerFormat()) {
745 case DataFormatNone: {
746 if (edge->hasConstant()) {
747 ASSERT(isInt32Constant(edge.node()));
748 GPRReg gpr = allocate();
749 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(edge.node())), gpr);
750 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
751 info.fillInt32(*m_stream, gpr);
752 returnFormat = DataFormatInt32;
753 return gpr;
754 }
755
756 DataFormat spillFormat = info.spillFormat();
757 ASSERT_UNUSED(spillFormat, (spillFormat & DataFormatJS) || spillFormat == DataFormatInt32);
758
759 // If we know this was spilled as an integer we can fill without checking.
760 if (type & ~SpecInt32)
761 speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), edge, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)));
762
763 GPRReg gpr = allocate();
764 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
765 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
766 info.fillInt32(*m_stream, gpr);
767 returnFormat = DataFormatInt32;
768 return gpr;
769 }
770
771 case DataFormatJSInt32:
772 case DataFormatJS: {
773 // Check the value is an integer.
774 GPRReg tagGPR = info.tagGPR();
775 GPRReg payloadGPR = info.payloadGPR();
776 m_gprs.lock(tagGPR);
777 m_gprs.lock(payloadGPR);
778 if (type & ~SpecInt32)
779 speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), edge, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::Int32Tag)));
780 m_gprs.unlock(tagGPR);
781 m_gprs.release(tagGPR);
782 m_gprs.release(payloadGPR);
783 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderInteger);
784 info.fillInt32(*m_stream, payloadGPR);
785 // If !strict we're done, return.
786 returnFormat = DataFormatInt32;
787 return payloadGPR;
788 }
789
790 case DataFormatInt32: {
791 GPRReg gpr = info.gpr();
792 m_gprs.lock(gpr);
793 returnFormat = DataFormatInt32;
794 return gpr;
795 }
796
797 case DataFormatCell:
798 case DataFormatBoolean:
799 case DataFormatJSDouble:
800 case DataFormatJSCell:
801 case DataFormatJSBoolean:
802 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
803 returnFormat = DataFormatInt32;
804 return allocate();
805
806 case DataFormatDouble:
807 case DataFormatStorage:
808 default:
809 RELEASE_ASSERT_NOT_REACHED();
810 return InvalidGPRReg;
811 }
812 }
813
814 GPRReg SpeculativeJIT::fillSpeculateInt32(Edge edge, DataFormat& returnFormat)
815 {
816 return fillSpeculateInt32Internal<false>(edge, returnFormat);
817 }
818
819 GPRReg SpeculativeJIT::fillSpeculateInt32Strict(Edge edge)
820 {
821 DataFormat mustBeDataFormatInt32;
822 GPRReg result = fillSpeculateInt32Internal<true>(edge, mustBeDataFormatInt32);
823 ASSERT(mustBeDataFormatInt32 == DataFormatInt32);
824 return result;
825 }
826
827 FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge)
828 {
829 ASSERT(isDouble(edge.useKind()));
830 ASSERT(edge->hasDoubleResult());
831 VirtualRegister virtualRegister = edge->virtualRegister();
832 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
833
834 if (info.registerFormat() == DataFormatNone) {
835
836 if (edge->hasConstant()) {
837 RELEASE_ASSERT(isNumberConstant(edge.node()));
838 FPRReg fpr = fprAllocate();
839 m_jit.loadDouble(TrustedImmPtr(addressOfDoubleConstant(edge.node())), fpr);
840 m_fprs.retain(fpr, virtualRegister, SpillOrderConstant);
841 info.fillDouble(*m_stream, fpr);
842 return fpr;
843 }
844
845 RELEASE_ASSERT(info.spillFormat() == DataFormatDouble);
846 FPRReg fpr = fprAllocate();
847 m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
848 m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
849 info.fillDouble(*m_stream, fpr);
850 return fpr;
851 }
852
853 RELEASE_ASSERT(info.registerFormat() == DataFormatDouble);
854 FPRReg fpr = info.fpr();
855 m_fprs.lock(fpr);
856 return fpr;
857 }
858
859 GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge)
860 {
861 AbstractValue& value = m_state.forNode(edge);
862 SpeculatedType type = value.m_type;
863 ASSERT((edge.useKind() != KnownCellUse && edge.useKind() != KnownStringUse) || !(value.m_type & ~SpecCell));
864 m_interpreter.filter(value, SpecCell);
865 VirtualRegister virtualRegister = edge->virtualRegister();
866 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
867
868 switch (info.registerFormat()) {
869 case DataFormatNone: {
870 if (info.spillFormat() == DataFormatInt32) {
871 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
872 return allocate();
873 }
874
875 if (edge->hasConstant()) {
876 JSValue jsValue = valueOfJSConstant(edge.node());
877 GPRReg gpr = allocate();
878 if (jsValue.isCell()) {
879 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
880 m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr);
881 info.fillCell(*m_stream, gpr);
882 return gpr;
883 }
884 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
885 return gpr;
886 }
887
888 ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatCell);
889 if (type & ~SpecCell) {
890 speculationCheck(
891 BadType,
892 JSValueSource(JITCompiler::addressFor(virtualRegister)),
893 edge,
894 m_jit.branch32(
895 MacroAssembler::NotEqual,
896 JITCompiler::tagFor(virtualRegister),
897 TrustedImm32(JSValue::CellTag)));
898 }
899 GPRReg gpr = allocate();
900 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
901 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
902 info.fillCell(*m_stream, gpr);
903 return gpr;
904 }
905
906 case DataFormatCell: {
907 GPRReg gpr = info.gpr();
908 m_gprs.lock(gpr);
909 return gpr;
910 }
911
912 case DataFormatJSCell:
913 case DataFormatJS: {
914 GPRReg tagGPR = info.tagGPR();
915 GPRReg payloadGPR = info.payloadGPR();
916 m_gprs.lock(tagGPR);
917 m_gprs.lock(payloadGPR);
918 if (type & ~SpecCell) {
919 speculationCheck(
920 BadType, JSValueRegs(tagGPR, payloadGPR), edge,
921 branchNotCell(info.jsValueRegs()));
922 }
923 m_gprs.unlock(tagGPR);
924 m_gprs.release(tagGPR);
925 m_gprs.release(payloadGPR);
926 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderCell);
927 info.fillCell(*m_stream, payloadGPR);
928 return payloadGPR;
929 }
930
931 case DataFormatJSInt32:
932 case DataFormatInt32:
933 case DataFormatJSDouble:
934 case DataFormatJSBoolean:
935 case DataFormatBoolean:
936 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
937 return allocate();
938
939 case DataFormatDouble:
940 case DataFormatStorage:
941 RELEASE_ASSERT_NOT_REACHED();
942
943 default:
944 RELEASE_ASSERT_NOT_REACHED();
945 return InvalidGPRReg;
946 }
947 }
948
949 GPRReg SpeculativeJIT::fillSpeculateBoolean(Edge edge)
950 {
951 AbstractValue& value = m_state.forNode(edge);
952 SpeculatedType type = value.m_type;
953 m_interpreter.filter(value, SpecBoolean);
954 VirtualRegister virtualRegister = edge->virtualRegister();
955 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
956
957 switch (info.registerFormat()) {
958 case DataFormatNone: {
959 if (info.spillFormat() == DataFormatInt32) {
960 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
961 return allocate();
962 }
963
964 if (edge->hasConstant()) {
965 JSValue jsValue = valueOfJSConstant(edge.node());
966 GPRReg gpr = allocate();
967 if (jsValue.isBoolean()) {
968 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
969 m_jit.move(MacroAssembler::TrustedImm32(jsValue.asBoolean()), gpr);
970 info.fillBoolean(*m_stream, gpr);
971 return gpr;
972 }
973 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
974 return gpr;
975 }
976
977 ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatBoolean);
978
979 if (type & ~SpecBoolean)
980 speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), edge, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)));
981
982 GPRReg gpr = allocate();
983 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
984 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
985 info.fillBoolean(*m_stream, gpr);
986 return gpr;
987 }
988
989 case DataFormatBoolean: {
990 GPRReg gpr = info.gpr();
991 m_gprs.lock(gpr);
992 return gpr;
993 }
994
995 case DataFormatJSBoolean:
996 case DataFormatJS: {
997 GPRReg tagGPR = info.tagGPR();
998 GPRReg payloadGPR = info.payloadGPR();
999 m_gprs.lock(tagGPR);
1000 m_gprs.lock(payloadGPR);
1001 if (type & ~SpecBoolean)
1002 speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), edge, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::BooleanTag)));
1003
1004 m_gprs.unlock(tagGPR);
1005 m_gprs.release(tagGPR);
1006 m_gprs.release(payloadGPR);
1007 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderBoolean);
1008 info.fillBoolean(*m_stream, payloadGPR);
1009 return payloadGPR;
1010 }
1011
1012 case DataFormatJSInt32:
1013 case DataFormatInt32:
1014 case DataFormatJSDouble:
1015 case DataFormatJSCell:
1016 case DataFormatCell:
1017 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
1018 return allocate();
1019
1020 case DataFormatDouble:
1021 case DataFormatStorage:
1022 RELEASE_ASSERT_NOT_REACHED();
1023
1024 default:
1025 RELEASE_ASSERT_NOT_REACHED();
1026 return InvalidGPRReg;
1027 }
1028 }
1029
1030 void SpeculativeJIT::compileBaseValueStoreBarrier(Edge& baseEdge, Edge& valueEdge)
1031 {
1032 #if ENABLE(GGC)
1033 ASSERT(!isKnownNotCell(valueEdge.node()));
1034
1035 SpeculateCellOperand base(this, baseEdge);
1036 JSValueOperand value(this, valueEdge);
1037 GPRTemporary scratch1(this);
1038 GPRTemporary scratch2(this);
1039
1040 writeBarrier(base.gpr(), value.tagGPR(), valueEdge, scratch1.gpr(), scratch2.gpr());
1041 #else
1042 UNUSED_PARAM(baseEdge);
1043 UNUSED_PARAM(valueEdge);
1044 #endif
1045 }
1046
1047 void SpeculativeJIT::compileObjectEquality(Node* node)
1048 {
1049 SpeculateCellOperand op1(this, node->child1());
1050 SpeculateCellOperand op2(this, node->child2());
1051 GPRReg op1GPR = op1.gpr();
1052 GPRReg op2GPR = op2.gpr();
1053
1054 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
1055 DFG_TYPE_CHECK(
1056 JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
1057 MacroAssembler::Equal,
1058 MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
1059 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1060 DFG_TYPE_CHECK(
1061 JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchPtr(
1062 MacroAssembler::Equal,
1063 MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()),
1064 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1065 } else {
1066 DFG_TYPE_CHECK(
1067 JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
1068 MacroAssembler::Equal,
1069 MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
1070 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1071 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
1072 m_jit.branchTest8(
1073 MacroAssembler::NonZero,
1074 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
1075 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1076
1077 DFG_TYPE_CHECK(
1078 JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchPtr(
1079 MacroAssembler::Equal,
1080 MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()),
1081 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1082 speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
1083 m_jit.branchTest8(
1084 MacroAssembler::NonZero,
1085 MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()),
1086 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1087 }
1088
1089 GPRTemporary resultPayload(this, Reuse, op2);
1090 GPRReg resultPayloadGPR = resultPayload.gpr();
1091
1092 MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2GPR);
1093 m_jit.move(TrustedImm32(1), resultPayloadGPR);
1094 MacroAssembler::Jump done = m_jit.jump();
1095 falseCase.link(&m_jit);
1096 m_jit.move(TrustedImm32(0), resultPayloadGPR);
1097 done.link(&m_jit);
1098
1099 booleanResult(resultPayloadGPR, node);
1100 }
1101
1102 void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild)
1103 {
1104 SpeculateCellOperand op1(this, leftChild);
1105 JSValueOperand op2(this, rightChild, ManualOperandSpeculation);
1106 GPRTemporary result(this);
1107
1108 GPRReg op1GPR = op1.gpr();
1109 GPRReg op2TagGPR = op2.tagGPR();
1110 GPRReg op2PayloadGPR = op2.payloadGPR();
1111 GPRReg resultGPR = result.gpr();
1112
1113 bool masqueradesAsUndefinedWatchpointValid =
1114 masqueradesAsUndefinedWatchpointIsStillValid();
1115
1116 if (masqueradesAsUndefinedWatchpointValid) {
1117 DFG_TYPE_CHECK(
1118 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
1119 MacroAssembler::Equal,
1120 MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
1121 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1122 } else {
1123 DFG_TYPE_CHECK(
1124 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
1125 MacroAssembler::Equal,
1126 MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
1127 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1128 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
1129 m_jit.branchTest8(
1130 MacroAssembler::NonZero,
1131 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
1132 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1133 }
1134
1135
1136 // It seems that most of the time when programs do a == b where b may be either null/undefined
1137 // or an object, b is usually an object. Balance the branches to make that case fast.
1138 MacroAssembler::Jump rightNotCell = branchNotCell(op2.jsValueRegs());
1139
1140 // We know that within this branch, rightChild must be a cell.
1141 if (masqueradesAsUndefinedWatchpointValid) {
1142 DFG_TYPE_CHECK(
1143 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
1144 m_jit.branchPtr(
1145 MacroAssembler::Equal,
1146 MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()),
1147 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1148 } else {
1149 DFG_TYPE_CHECK(
1150 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
1151 m_jit.branchPtr(
1152 MacroAssembler::Equal,
1153 MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()),
1154 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1155 speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
1156 m_jit.branchTest8(
1157 MacroAssembler::NonZero,
1158 MacroAssembler::Address(op2PayloadGPR, JSCell::typeInfoFlagsOffset()),
1159 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1160 }
1161
1162 // At this point we know that we can perform a straight-forward equality comparison on pointer
1163 // values because both left and right are pointers to objects that have no special equality
1164 // protocols.
1165 MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2PayloadGPR);
1166 MacroAssembler::Jump trueCase = m_jit.jump();
1167
1168 rightNotCell.link(&m_jit);
1169
1170 // We know that within this branch, rightChild must not be a cell. Check if that is enough to
1171 // prove that it is either null or undefined.
1172 if (needsTypeCheck(rightChild, SpecCell | SpecOther)) {
1173 m_jit.move(op2TagGPR, resultGPR);
1174 m_jit.or32(TrustedImm32(1), resultGPR);
1175
1176 typeCheck(
1177 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, SpecCell | SpecOther,
1178 m_jit.branch32(
1179 MacroAssembler::NotEqual, resultGPR,
1180 MacroAssembler::TrustedImm32(JSValue::NullTag)));
1181 }
1182
1183 falseCase.link(&m_jit);
1184 m_jit.move(TrustedImm32(0), resultGPR);
1185 MacroAssembler::Jump done = m_jit.jump();
1186 trueCase.link(&m_jit);
1187 m_jit.move(TrustedImm32(1), resultGPR);
1188 done.link(&m_jit);
1189
1190 booleanResult(resultGPR, m_currentNode);
1191 }
1192
1193 void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild, Node* branchNode)
1194 {
1195 BasicBlock* taken = branchNode->branchData()->taken.block;
1196 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1197
1198 SpeculateCellOperand op1(this, leftChild);
1199 JSValueOperand op2(this, rightChild, ManualOperandSpeculation);
1200 GPRTemporary result(this);
1201
1202 GPRReg op1GPR = op1.gpr();
1203 GPRReg op2TagGPR = op2.tagGPR();
1204 GPRReg op2PayloadGPR = op2.payloadGPR();
1205 GPRReg resultGPR = result.gpr();
1206
1207 bool masqueradesAsUndefinedWatchpointValid =
1208 masqueradesAsUndefinedWatchpointIsStillValid();
1209
1210 if (masqueradesAsUndefinedWatchpointValid) {
1211 DFG_TYPE_CHECK(
1212 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
1213 MacroAssembler::Equal,
1214 MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
1215 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1216 } else {
1217 DFG_TYPE_CHECK(
1218 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
1219 MacroAssembler::Equal,
1220 MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
1221 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1222 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
1223 m_jit.branchTest8(
1224 MacroAssembler::NonZero,
1225 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
1226 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1227 }
1228
1229 // It seems that most of the time when programs do a == b where b may be either null/undefined
1230 // or an object, b is usually an object. Balance the branches to make that case fast.
1231 MacroAssembler::Jump rightNotCell = branchNotCell(op2.jsValueRegs());
1232
1233 // We know that within this branch, rightChild must be a cell.
1234 if (masqueradesAsUndefinedWatchpointValid) {
1235 DFG_TYPE_CHECK(
1236 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
1237 m_jit.branchPtr(
1238 MacroAssembler::Equal,
1239 MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()),
1240 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1241 } else {
1242 DFG_TYPE_CHECK(
1243 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
1244 m_jit.branchPtr(
1245 MacroAssembler::Equal,
1246 MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()),
1247 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1248 speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
1249 m_jit.branchTest8(
1250 MacroAssembler::NonZero,
1251 MacroAssembler::Address(op2PayloadGPR, JSCell::typeInfoFlagsOffset()),
1252 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1253 }
1254
1255 // At this point we know that we can perform a straight-forward equality comparison on pointer
1256 // values because both left and right are pointers to objects that have no special equality
1257 // protocols.
1258 branch32(MacroAssembler::Equal, op1GPR, op2PayloadGPR, taken);
1259
1260 // We know that within this branch, rightChild must not be a cell. Check if that is enough to
1261 // prove that it is either null or undefined.
1262 if (!needsTypeCheck(rightChild, SpecCell | SpecOther))
1263 rightNotCell.link(&m_jit);
1264 else {
1265 jump(notTaken, ForceJump);
1266
1267 rightNotCell.link(&m_jit);
1268 m_jit.move(op2TagGPR, resultGPR);
1269 m_jit.or32(TrustedImm32(1), resultGPR);
1270
1271 typeCheck(
1272 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, SpecCell | SpecOther,
1273 m_jit.branch32(
1274 MacroAssembler::NotEqual, resultGPR,
1275 MacroAssembler::TrustedImm32(JSValue::NullTag)));
1276 }
1277
1278 jump(notTaken);
1279 }
1280
1281 void SpeculativeJIT::compileInt32Compare(Node* node, MacroAssembler::RelationalCondition condition)
1282 {
1283 SpeculateInt32Operand op1(this, node->child1());
1284 SpeculateInt32Operand op2(this, node->child2());
1285 GPRTemporary resultPayload(this);
1286
1287 m_jit.compare32(condition, op1.gpr(), op2.gpr(), resultPayload.gpr());
1288
1289 // If we add a DataFormatBool, we should use it here.
1290 booleanResult(resultPayload.gpr(), node);
1291 }
1292
1293 void SpeculativeJIT::compileDoubleCompare(Node* node, MacroAssembler::DoubleCondition condition)
1294 {
1295 SpeculateDoubleOperand op1(this, node->child1());
1296 SpeculateDoubleOperand op2(this, node->child2());
1297 GPRTemporary resultPayload(this);
1298
1299 m_jit.move(TrustedImm32(1), resultPayload.gpr());
1300 MacroAssembler::Jump trueCase = m_jit.branchDouble(condition, op1.fpr(), op2.fpr());
1301 m_jit.move(TrustedImm32(0), resultPayload.gpr());
1302 trueCase.link(&m_jit);
1303
1304 booleanResult(resultPayload.gpr(), node);
1305 }
1306
1307 void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
1308 {
1309 JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
1310 GPRTemporary resultPayload(this);
1311 GPRReg valueTagGPR = value.tagGPR();
1312 GPRReg valuePayloadGPR = value.payloadGPR();
1313 GPRReg resultPayloadGPR = resultPayload.gpr();
1314 GPRTemporary structure;
1315 GPRReg structureGPR = InvalidGPRReg;
1316
1317 bool masqueradesAsUndefinedWatchpointValid =
1318 masqueradesAsUndefinedWatchpointIsStillValid();
1319
1320 if (!masqueradesAsUndefinedWatchpointValid) {
1321 // The masquerades as undefined case will use the structure register, so allocate it here.
1322 // Do this at the top of the function to avoid branching around a register allocation.
1323 GPRTemporary realStructure(this);
1324 structure.adopt(realStructure);
1325 structureGPR = structure.gpr();
1326 }
1327
1328 MacroAssembler::Jump notCell = branchNotCell(value.jsValueRegs());
1329 if (masqueradesAsUndefinedWatchpointValid) {
1330 DFG_TYPE_CHECK(
1331 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
1332 m_jit.branchPtr(
1333 MacroAssembler::Equal,
1334 MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()),
1335 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1336 } else {
1337 m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), structureGPR);
1338
1339 DFG_TYPE_CHECK(
1340 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
1341 m_jit.branchPtr(
1342 MacroAssembler::Equal,
1343 structureGPR,
1344 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1345
1346 MacroAssembler::Jump isNotMasqueradesAsUndefined =
1347 m_jit.branchTest8(
1348 MacroAssembler::Zero,
1349 MacroAssembler::Address(valuePayloadGPR, JSCell::typeInfoFlagsOffset()),
1350 MacroAssembler::TrustedImm32(MasqueradesAsUndefined));
1351
1352 speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
1353 m_jit.branchPtr(
1354 MacroAssembler::Equal,
1355 MacroAssembler::Address(structureGPR, Structure::globalObjectOffset()),
1356 MacroAssembler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode->origin.semantic))));
1357
1358 isNotMasqueradesAsUndefined.link(&m_jit);
1359 }
1360 m_jit.move(TrustedImm32(0), resultPayloadGPR);
1361 MacroAssembler::Jump done = m_jit.jump();
1362
1363 notCell.link(&m_jit);
1364
1365 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
1366 if (needsTypeCheck(nodeUse, SpecCell | SpecOther)) {
1367 m_jit.move(valueTagGPR, resultPayloadGPR);
1368 m_jit.or32(TrustedImm32(1), resultPayloadGPR);
1369 typeCheck(
1370 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, SpecCell | SpecOther,
1371 m_jit.branch32(
1372 MacroAssembler::NotEqual,
1373 resultPayloadGPR,
1374 TrustedImm32(JSValue::NullTag)));
1375 }
1376 m_jit.move(TrustedImm32(1), resultPayloadGPR);
1377
1378 done.link(&m_jit);
1379
1380 booleanResult(resultPayloadGPR, m_currentNode);
1381 }
1382
1383 void SpeculativeJIT::compileLogicalNot(Node* node)
1384 {
1385 switch (node->child1().useKind()) {
1386 case BooleanUse: {
1387 SpeculateBooleanOperand value(this, node->child1());
1388 GPRTemporary result(this, Reuse, value);
1389 m_jit.xor32(TrustedImm32(1), value.gpr(), result.gpr());
1390 booleanResult(result.gpr(), node);
1391 return;
1392 }
1393
1394 case ObjectOrOtherUse: {
1395 compileObjectOrOtherLogicalNot(node->child1());
1396 return;
1397 }
1398
1399 case Int32Use: {
1400 SpeculateInt32Operand value(this, node->child1());
1401 GPRTemporary resultPayload(this, Reuse, value);
1402 m_jit.compare32(MacroAssembler::Equal, value.gpr(), MacroAssembler::TrustedImm32(0), resultPayload.gpr());
1403 booleanResult(resultPayload.gpr(), node);
1404 return;
1405 }
1406
1407 case DoubleRepUse: {
1408 SpeculateDoubleOperand value(this, node->child1());
1409 FPRTemporary scratch(this);
1410 GPRTemporary resultPayload(this);
1411 m_jit.move(TrustedImm32(0), resultPayload.gpr());
1412 MacroAssembler::Jump nonZero = m_jit.branchDoubleNonZero(value.fpr(), scratch.fpr());
1413 m_jit.move(TrustedImm32(1), resultPayload.gpr());
1414 nonZero.link(&m_jit);
1415 booleanResult(resultPayload.gpr(), node);
1416 return;
1417 }
1418
1419 case UntypedUse: {
1420 JSValueOperand arg1(this, node->child1());
1421 GPRTemporary resultPayload(this, Reuse, arg1, PayloadWord);
1422 GPRReg arg1TagGPR = arg1.tagGPR();
1423 GPRReg arg1PayloadGPR = arg1.payloadGPR();
1424 GPRReg resultPayloadGPR = resultPayload.gpr();
1425
1426 arg1.use();
1427
1428 JITCompiler::Jump slowCase = m_jit.branch32(JITCompiler::NotEqual, arg1TagGPR, TrustedImm32(JSValue::BooleanTag));
1429
1430 m_jit.move(arg1PayloadGPR, resultPayloadGPR);
1431
1432 addSlowPathGenerator(
1433 slowPathCall(
1434 slowCase, this, operationConvertJSValueToBoolean, resultPayloadGPR, arg1TagGPR,
1435 arg1PayloadGPR));
1436
1437 m_jit.xor32(TrustedImm32(1), resultPayloadGPR);
1438 booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
1439 return;
1440 }
1441 case StringUse:
1442 return compileStringZeroLength(node);
1443
1444 default:
1445 RELEASE_ASSERT_NOT_REACHED();
1446 break;
1447 }
1448 }
1449
1450 void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BasicBlock* taken, BasicBlock* notTaken)
1451 {
1452 JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
1453 GPRTemporary scratch(this);
1454 GPRReg valueTagGPR = value.tagGPR();
1455 GPRReg valuePayloadGPR = value.payloadGPR();
1456 GPRReg scratchGPR = scratch.gpr();
1457
1458 MacroAssembler::Jump notCell = branchNotCell(value.jsValueRegs());
1459 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
1460 DFG_TYPE_CHECK(
1461 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
1462 m_jit.branchPtr(
1463 MacroAssembler::Equal,
1464 MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()),
1465 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1466 } else {
1467 m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), scratchGPR);
1468
1469 DFG_TYPE_CHECK(
1470 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
1471 m_jit.branchPtr(
1472 MacroAssembler::Equal,
1473 scratchGPR,
1474 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1475
1476 JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8(
1477 JITCompiler::Zero,
1478 MacroAssembler::Address(valuePayloadGPR, JSCell::typeInfoFlagsOffset()),
1479 TrustedImm32(MasqueradesAsUndefined));
1480
1481 speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
1482 m_jit.branchPtr(
1483 MacroAssembler::Equal,
1484 MacroAssembler::Address(scratchGPR, Structure::globalObjectOffset()),
1485 MacroAssembler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode->origin.semantic))));
1486
1487 isNotMasqueradesAsUndefined.link(&m_jit);
1488 }
1489 jump(taken, ForceJump);
1490
1491 notCell.link(&m_jit);
1492
1493 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
1494 if (needsTypeCheck(nodeUse, SpecCell | SpecOther)) {
1495 m_jit.move(valueTagGPR, scratchGPR);
1496 m_jit.or32(TrustedImm32(1), scratchGPR);
1497 typeCheck(
1498 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, SpecCell | SpecOther,
1499 m_jit.branch32(MacroAssembler::NotEqual, scratchGPR, TrustedImm32(JSValue::NullTag)));
1500 }
1501
1502 jump(notTaken);
1503
1504 noResult(m_currentNode);
1505 }
1506
1507 void SpeculativeJIT::emitBranch(Node* node)
1508 {
1509 BasicBlock* taken = node->branchData()->taken.block;
1510 BasicBlock* notTaken = node->branchData()->notTaken.block;
1511
1512 switch (node->child1().useKind()) {
1513 case BooleanUse: {
1514 SpeculateBooleanOperand value(this, node->child1());
1515 MacroAssembler::ResultCondition condition = MacroAssembler::NonZero;
1516
1517 if (taken == nextBlock()) {
1518 condition = MacroAssembler::Zero;
1519 BasicBlock* tmp = taken;
1520 taken = notTaken;
1521 notTaken = tmp;
1522 }
1523
1524 branchTest32(condition, value.gpr(), TrustedImm32(1), taken);
1525 jump(notTaken);
1526
1527 noResult(node);
1528 return;
1529 }
1530
1531 case ObjectOrOtherUse: {
1532 emitObjectOrOtherBranch(node->child1(), taken, notTaken);
1533 return;
1534 }
1535
1536 case DoubleRepUse:
1537 case Int32Use: {
1538 if (node->child1().useKind() == Int32Use) {
1539 bool invert = false;
1540
1541 if (taken == nextBlock()) {
1542 invert = true;
1543 BasicBlock* tmp = taken;
1544 taken = notTaken;
1545 notTaken = tmp;
1546 }
1547
1548 SpeculateInt32Operand value(this, node->child1());
1549 branchTest32(invert ? MacroAssembler::Zero : MacroAssembler::NonZero, value.gpr(), taken);
1550 } else {
1551 SpeculateDoubleOperand value(this, node->child1());
1552 FPRTemporary scratch(this);
1553 branchDoubleNonZero(value.fpr(), scratch.fpr(), taken);
1554 }
1555
1556 jump(notTaken);
1557
1558 noResult(node);
1559 return;
1560 }
1561
1562 case UntypedUse: {
1563 JSValueOperand value(this, node->child1());
1564 value.fill();
1565 GPRReg valueTagGPR = value.tagGPR();
1566 GPRReg valuePayloadGPR = value.payloadGPR();
1567
1568 GPRTemporary result(this);
1569 GPRReg resultGPR = result.gpr();
1570
1571 use(node->child1());
1572
1573 JITCompiler::Jump fastPath = m_jit.branch32(JITCompiler::Equal, valueTagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag));
1574 JITCompiler::Jump slowPath = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, JITCompiler::TrustedImm32(JSValue::BooleanTag));
1575
1576 fastPath.link(&m_jit);
1577 branchTest32(JITCompiler::Zero, valuePayloadGPR, notTaken);
1578 jump(taken, ForceJump);
1579
1580 slowPath.link(&m_jit);
1581 silentSpillAllRegisters(resultGPR);
1582 callOperation(operationConvertJSValueToBoolean, resultGPR, valueTagGPR, valuePayloadGPR);
1583 silentFillAllRegisters(resultGPR);
1584
1585 branchTest32(JITCompiler::NonZero, resultGPR, taken);
1586 jump(notTaken);
1587
1588 noResult(node, UseChildrenCalledExplicitly);
1589 return;
1590 }
1591
1592 default:
1593 RELEASE_ASSERT_NOT_REACHED();
1594 break;
1595 }
1596 }
1597
1598 template<typename BaseOperandType, typename PropertyOperandType, typename ValueOperandType, typename TagType>
1599 void SpeculativeJIT::compileContiguousPutByVal(Node* node, BaseOperandType& base, PropertyOperandType& property, ValueOperandType& value, GPRReg valuePayloadReg, TagType valueTag)
1600 {
1601 Edge child4 = m_jit.graph().varArgChild(node, 3);
1602
1603 ArrayMode arrayMode = node->arrayMode();
1604
1605 GPRReg baseReg = base.gpr();
1606 GPRReg propertyReg = property.gpr();
1607
1608 StorageOperand storage(this, child4);
1609 GPRReg storageReg = storage.gpr();
1610
1611 if (node->op() == PutByValAlias) {
1612 // Store the value to the array.
1613 GPRReg propertyReg = property.gpr();
1614 m_jit.store32(valueTag, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
1615 m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
1616
1617 noResult(node);
1618 return;
1619 }
1620
1621 MacroAssembler::Jump slowCase;
1622
1623 if (arrayMode.isInBounds()) {
1624 speculationCheck(
1625 OutOfBounds, JSValueRegs(), 0,
1626 m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
1627 } else {
1628 MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
1629
1630 slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength()));
1631
1632 if (!arrayMode.isOutOfBounds())
1633 speculationCheck(OutOfBounds, JSValueRegs(), 0, slowCase);
1634
1635 m_jit.add32(TrustedImm32(1), propertyReg);
1636 m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
1637 m_jit.sub32(TrustedImm32(1), propertyReg);
1638
1639 inBounds.link(&m_jit);
1640 }
1641
1642 m_jit.store32(valueTag, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
1643 m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
1644
1645 base.use();
1646 property.use();
1647 value.use();
1648 storage.use();
1649
1650 if (arrayMode.isOutOfBounds()) {
1651 if (node->op() == PutByValDirect) {
1652 addSlowPathGenerator(slowPathCall(
1653 slowCase, this,
1654 m_jit.codeBlock()->isStrictMode() ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValDirectBeyondArrayBoundsNonStrict,
1655 NoResult, baseReg, propertyReg, valueTag, valuePayloadReg));
1656 } else {
1657 addSlowPathGenerator(slowPathCall(
1658 slowCase, this,
1659 m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
1660 NoResult, baseReg, propertyReg, valueTag, valuePayloadReg));
1661 }
1662 }
1663
1664 noResult(node, UseChildrenCalledExplicitly);
1665 }
1666
1667 void SpeculativeJIT::compile(Node* node)
1668 {
1669 NodeType op = node->op();
1670
1671 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
1672 m_jit.clearRegisterAllocationOffsets();
1673 #endif
1674
1675 switch (op) {
1676 case JSConstant:
1677 case DoubleConstant:
1678 initConstantInfo(node);
1679 break;
1680
1681 case PhantomArguments:
1682 initConstantInfo(node);
1683 break;
1684
1685 case WeakJSConstant:
1686 m_jit.addWeakReference(node->weakConstant());
1687 initConstantInfo(node);
1688 break;
1689
1690 case Identity: {
1691 RELEASE_ASSERT_NOT_REACHED();
1692 break;
1693 }
1694
1695 case GetLocal: {
1696 AbstractValue& value = m_state.variables().operand(node->local());
1697
1698 // If the CFA is tracking this variable and it found that the variable
1699 // cannot have been assigned, then don't attempt to proceed.
1700 if (value.isClear()) {
1701 // FIXME: We should trap instead.
1702 // https://bugs.webkit.org/show_bug.cgi?id=110383
1703 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
1704 break;
1705 }
1706
1707 switch (node->variableAccessData()->flushFormat()) {
1708 case FlushedDouble: {
1709 FPRTemporary result(this);
1710 m_jit.loadDouble(JITCompiler::addressFor(node->machineLocal()), result.fpr());
1711 VirtualRegister virtualRegister = node->virtualRegister();
1712 m_fprs.retain(result.fpr(), virtualRegister, SpillOrderDouble);
1713 generationInfoFromVirtualRegister(virtualRegister).initDouble(node, node->refCount(), result.fpr());
1714 break;
1715 }
1716
1717 case FlushedInt32: {
1718 GPRTemporary result(this);
1719 m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr());
1720
1721 // Like int32Result, but don't useChildren - our children are phi nodes,
1722 // and don't represent values within this dataflow with virtual registers.
1723 VirtualRegister virtualRegister = node->virtualRegister();
1724 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderInteger);
1725 generationInfoFromVirtualRegister(virtualRegister).initInt32(node, node->refCount(), result.gpr());
1726 break;
1727 }
1728
1729 case FlushedCell: {
1730 GPRTemporary result(this);
1731 m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr());
1732
1733 // Like cellResult, but don't useChildren - our children are phi nodes,
1734 // and don't represent values within this dataflow with virtual registers.
1735 VirtualRegister virtualRegister = node->virtualRegister();
1736 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderCell);
1737 generationInfoFromVirtualRegister(virtualRegister).initCell(node, node->refCount(), result.gpr());
1738 break;
1739 }
1740
1741 case FlushedBoolean: {
1742 GPRTemporary result(this);
1743 m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr());
1744
1745 // Like booleanResult, but don't useChildren - our children are phi nodes,
1746 // and don't represent values within this dataflow with virtual registers.
1747 VirtualRegister virtualRegister = node->virtualRegister();
1748 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderBoolean);
1749 generationInfoFromVirtualRegister(virtualRegister).initBoolean(node, node->refCount(), result.gpr());
1750 break;
1751 }
1752
1753 case FlushedJSValue:
1754 case FlushedArguments: {
1755 GPRTemporary result(this);
1756 GPRTemporary tag(this);
1757 m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr());
1758 m_jit.load32(JITCompiler::tagFor(node->machineLocal()), tag.gpr());
1759
1760 // Like jsValueResult, but don't useChildren - our children are phi nodes,
1761 // and don't represent values within this dataflow with virtual registers.
1762 VirtualRegister virtualRegister = node->virtualRegister();
1763 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
1764 m_gprs.retain(tag.gpr(), virtualRegister, SpillOrderJS);
1765
1766 generationInfoFromVirtualRegister(virtualRegister).initJSValue(node, node->refCount(), tag.gpr(), result.gpr(), DataFormatJS);
1767 break;
1768 }
1769
1770 default:
1771 RELEASE_ASSERT_NOT_REACHED();
1772 }
1773 break;
1774 }
1775
1776 case GetLocalUnlinked: {
1777 GPRTemporary payload(this);
1778 GPRTemporary tag(this);
1779 m_jit.load32(JITCompiler::payloadFor(node->unlinkedMachineLocal()), payload.gpr());
1780 m_jit.load32(JITCompiler::tagFor(node->unlinkedMachineLocal()), tag.gpr());
1781 jsValueResult(tag.gpr(), payload.gpr(), node);
1782 break;
1783 }
1784
1785 case MovHint:
1786 case ZombieHint:
1787 case Check: {
1788 RELEASE_ASSERT_NOT_REACHED();
1789 break;
1790 }
1791
1792 case SetLocal: {
1793 switch (node->variableAccessData()->flushFormat()) {
1794 case FlushedDouble: {
1795 SpeculateDoubleOperand value(this, node->child1());
1796 m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node->machineLocal()));
1797 noResult(node);
1798 // Indicate that it's no longer necessary to retrieve the value of
1799 // this bytecode variable from registers or other locations in the stack,
1800 // but that it is stored as a double.
1801 recordSetLocal(DataFormatDouble);
1802 break;
1803 }
1804
1805 case FlushedInt32: {
1806 SpeculateInt32Operand value(this, node->child1());
1807 m_jit.store32(value.gpr(), JITCompiler::payloadFor(node->machineLocal()));
1808 noResult(node);
1809 recordSetLocal(DataFormatInt32);
1810 break;
1811 }
1812
1813 case FlushedCell: {
1814 SpeculateCellOperand cell(this, node->child1());
1815 GPRReg cellGPR = cell.gpr();
1816 m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node->machineLocal()));
1817 noResult(node);
1818 recordSetLocal(DataFormatCell);
1819 break;
1820 }
1821
1822 case FlushedBoolean: {
1823 SpeculateBooleanOperand value(this, node->child1());
1824 m_jit.store32(value.gpr(), JITCompiler::payloadFor(node->machineLocal()));
1825 noResult(node);
1826 recordSetLocal(DataFormatBoolean);
1827 break;
1828 }
1829
1830 case FlushedJSValue:
1831 case FlushedArguments: {
1832 JSValueOperand value(this, node->child1());
1833 m_jit.store32(value.payloadGPR(), JITCompiler::payloadFor(node->machineLocal()));
1834 m_jit.store32(value.tagGPR(), JITCompiler::tagFor(node->machineLocal()));
1835 noResult(node);
1836 recordSetLocal(dataFormatFor(node->variableAccessData()->flushFormat()));
1837 break;
1838 }
1839
1840 default:
1841 RELEASE_ASSERT_NOT_REACHED();
1842 break;
1843 }
1844 break;
1845 }
1846
1847 case SetArgument:
1848 // This is a no-op; it just marks the fact that the argument is being used.
1849 // But it may be profitable to use this as a hook to run speculation checks
1850 // on arguments, thereby allowing us to trivially eliminate such checks if
1851 // the argument is not used.
1852 recordSetLocal(dataFormatFor(node->variableAccessData()->flushFormat()));
1853 break;
1854
1855 case BitAnd:
1856 case BitOr:
1857 case BitXor:
1858 if (isInt32Constant(node->child1().node())) {
1859 SpeculateInt32Operand op2(this, node->child2());
1860 GPRTemporary result(this, Reuse, op2);
1861
1862 bitOp(op, valueOfInt32Constant(node->child1().node()), op2.gpr(), result.gpr());
1863
1864 int32Result(result.gpr(), node);
1865 } else if (isInt32Constant(node->child2().node())) {
1866 SpeculateInt32Operand op1(this, node->child1());
1867 GPRTemporary result(this, Reuse, op1);
1868
1869 bitOp(op, valueOfInt32Constant(node->child2().node()), op1.gpr(), result.gpr());
1870
1871 int32Result(result.gpr(), node);
1872 } else {
1873 SpeculateInt32Operand op1(this, node->child1());
1874 SpeculateInt32Operand op2(this, node->child2());
1875 GPRTemporary result(this, Reuse, op1, op2);
1876
1877 GPRReg reg1 = op1.gpr();
1878 GPRReg reg2 = op2.gpr();
1879 bitOp(op, reg1, reg2, result.gpr());
1880
1881 int32Result(result.gpr(), node);
1882 }
1883 break;
1884
1885 case BitRShift:
1886 case BitLShift:
1887 case BitURShift:
1888 if (isInt32Constant(node->child2().node())) {
1889 SpeculateInt32Operand op1(this, node->child1());
1890 GPRTemporary result(this, Reuse, op1);
1891
1892 shiftOp(op, op1.gpr(), valueOfInt32Constant(node->child2().node()) & 0x1f, result.gpr());
1893
1894 int32Result(result.gpr(), node);
1895 } else {
1896 // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.
1897 SpeculateInt32Operand op1(this, node->child1());
1898 SpeculateInt32Operand op2(this, node->child2());
1899 GPRTemporary result(this, Reuse, op1);
1900
1901 GPRReg reg1 = op1.gpr();
1902 GPRReg reg2 = op2.gpr();
1903 shiftOp(op, reg1, reg2, result.gpr());
1904
1905 int32Result(result.gpr(), node);
1906 }
1907 break;
1908
1909 case UInt32ToNumber: {
1910 compileUInt32ToNumber(node);
1911 break;
1912 }
1913
1914 case DoubleAsInt32: {
1915 compileDoubleAsInt32(node);
1916 break;
1917 }
1918
1919 case ValueToInt32: {
1920 compileValueToInt32(node);
1921 break;
1922 }
1923
1924 case DoubleRep: {
1925 compileDoubleRep(node);
1926 break;
1927 }
1928
1929 case ValueRep: {
1930 compileValueRep(node);
1931 break;
1932 }
1933
1934 case ValueAdd: {
1935 JSValueOperand op1(this, node->child1());
1936 JSValueOperand op2(this, node->child2());
1937
1938 GPRReg op1TagGPR = op1.tagGPR();
1939 GPRReg op1PayloadGPR = op1.payloadGPR();
1940 GPRReg op2TagGPR = op2.tagGPR();
1941 GPRReg op2PayloadGPR = op2.payloadGPR();
1942
1943 flushRegisters();
1944
1945 GPRResult2 resultTag(this);
1946 GPRResult resultPayload(this);
1947 if (isKnownNotNumber(node->child1().node()) || isKnownNotNumber(node->child2().node()))
1948 callOperation(operationValueAddNotNumber, resultTag.gpr(), resultPayload.gpr(), op1TagGPR, op1PayloadGPR, op2TagGPR, op2PayloadGPR);
1949 else
1950 callOperation(operationValueAdd, resultTag.gpr(), resultPayload.gpr(), op1TagGPR, op1PayloadGPR, op2TagGPR, op2PayloadGPR);
1951
1952 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
1953 break;
1954 }
1955
1956 case ArithAdd:
1957 compileAdd(node);
1958 break;
1959
1960 case MakeRope:
1961 compileMakeRope(node);
1962 break;
1963
1964 case ArithSub:
1965 compileArithSub(node);
1966 break;
1967
1968 case ArithNegate:
1969 compileArithNegate(node);
1970 break;
1971
1972 case ArithMul:
1973 compileArithMul(node);
1974 break;
1975
1976 case ArithDiv: {
1977 compileArithDiv(node);
1978 break;
1979 }
1980
1981 case ArithMod: {
1982 compileArithMod(node);
1983 break;
1984 }
1985
1986 case ArithAbs: {
1987 switch (node->child1().useKind()) {
1988 case Int32Use: {
1989 SpeculateStrictInt32Operand op1(this, node->child1());
1990 GPRTemporary result(this, Reuse, op1);
1991 GPRTemporary scratch(this);
1992
1993 m_jit.move(op1.gpr(), result.gpr());
1994 m_jit.rshift32(result.gpr(), MacroAssembler::TrustedImm32(31), scratch.gpr());
1995 m_jit.add32(scratch.gpr(), result.gpr());
1996 m_jit.xor32(scratch.gpr(), result.gpr());
1997 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Equal, result.gpr(), MacroAssembler::TrustedImm32(1 << 31)));
1998 int32Result(result.gpr(), node);
1999 break;
2000 }
2001
2002
2003 case DoubleRepUse: {
2004 SpeculateDoubleOperand op1(this, node->child1());
2005 FPRTemporary result(this);
2006
2007 m_jit.absDouble(op1.fpr(), result.fpr());
2008 doubleResult(result.fpr(), node);
2009 break;
2010 }
2011
2012 default:
2013 RELEASE_ASSERT_NOT_REACHED();
2014 break;
2015 }
2016 break;
2017 }
2018
2019 case ArithMin:
2020 case ArithMax: {
2021 switch (node->binaryUseKind()) {
2022 case Int32Use: {
2023 SpeculateStrictInt32Operand op1(this, node->child1());
2024 SpeculateStrictInt32Operand op2(this, node->child2());
2025 GPRTemporary result(this, Reuse, op1);
2026
2027 GPRReg op1GPR = op1.gpr();
2028 GPRReg op2GPR = op2.gpr();
2029 GPRReg resultGPR = result.gpr();
2030
2031 MacroAssembler::Jump op1Less = m_jit.branch32(op == ArithMin ? MacroAssembler::LessThan : MacroAssembler::GreaterThan, op1GPR, op2GPR);
2032 m_jit.move(op2GPR, resultGPR);
2033 if (op1GPR != resultGPR) {
2034 MacroAssembler::Jump done = m_jit.jump();
2035 op1Less.link(&m_jit);
2036 m_jit.move(op1GPR, resultGPR);
2037 done.link(&m_jit);
2038 } else
2039 op1Less.link(&m_jit);
2040
2041 int32Result(resultGPR, node);
2042 break;
2043 }
2044
2045 case DoubleRepUse: {
2046 SpeculateDoubleOperand op1(this, node->child1());
2047 SpeculateDoubleOperand op2(this, node->child2());
2048 FPRTemporary result(this, op1);
2049
2050 FPRReg op1FPR = op1.fpr();
2051 FPRReg op2FPR = op2.fpr();
2052 FPRReg resultFPR = result.fpr();
2053
2054 MacroAssembler::JumpList done;
2055
2056 MacroAssembler::Jump op1Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleLessThan : MacroAssembler::DoubleGreaterThan, op1FPR, op2FPR);
2057
2058 // op2 is eather the lesser one or one of then is NaN
2059 MacroAssembler::Jump op2Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleGreaterThanOrEqual : MacroAssembler::DoubleLessThanOrEqual, op1FPR, op2FPR);
2060
2061 // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding
2062 // op1 + op2 and putting it into result.
2063 m_jit.addDouble(op1FPR, op2FPR, resultFPR);
2064 done.append(m_jit.jump());
2065
2066 op2Less.link(&m_jit);
2067 m_jit.moveDouble(op2FPR, resultFPR);
2068
2069 if (op1FPR != resultFPR) {
2070 done.append(m_jit.jump());
2071
2072 op1Less.link(&m_jit);
2073 m_jit.moveDouble(op1FPR, resultFPR);
2074 } else
2075 op1Less.link(&m_jit);
2076
2077 done.link(&m_jit);
2078
2079 doubleResult(resultFPR, node);
2080 break;
2081 }
2082
2083 default:
2084 RELEASE_ASSERT_NOT_REACHED();
2085 break;
2086 }
2087 break;
2088 }
2089
2090 case ArithSqrt: {
2091 SpeculateDoubleOperand op1(this, node->child1());
2092 FPRTemporary result(this, op1);
2093
2094 m_jit.sqrtDouble(op1.fpr(), result.fpr());
2095
2096 doubleResult(result.fpr(), node);
2097 break;
2098 }
2099
2100 case ArithFRound: {
2101 SpeculateDoubleOperand op1(this, node->child1());
2102 FPRTemporary result(this, op1);
2103
2104 m_jit.convertDoubleToFloat(op1.fpr(), result.fpr());
2105 m_jit.convertFloatToDouble(result.fpr(), result.fpr());
2106
2107 doubleResult(result.fpr(), node);
2108 break;
2109 }
2110
2111 case ArithSin: {
2112 SpeculateDoubleOperand op1(this, node->child1());
2113 FPRReg op1FPR = op1.fpr();
2114
2115 flushRegisters();
2116
2117 FPRResult result(this);
2118 callOperation(sin, result.fpr(), op1FPR);
2119 doubleResult(result.fpr(), node);
2120 break;
2121 }
2122
2123 case ArithCos: {
2124 SpeculateDoubleOperand op1(this, node->child1());
2125 FPRReg op1FPR = op1.fpr();
2126
2127 flushRegisters();
2128
2129 FPRResult result(this);
2130 callOperation(cos, result.fpr(), op1FPR);
2131 doubleResult(result.fpr(), node);
2132 break;
2133 }
2134
2135 case LogicalNot:
2136 compileLogicalNot(node);
2137 break;
2138
2139 case CompareLess:
2140 if (compare(node, JITCompiler::LessThan, JITCompiler::DoubleLessThan, operationCompareLess))
2141 return;
2142 break;
2143
2144 case CompareLessEq:
2145 if (compare(node, JITCompiler::LessThanOrEqual, JITCompiler::DoubleLessThanOrEqual, operationCompareLessEq))
2146 return;
2147 break;
2148
2149 case CompareGreater:
2150 if (compare(node, JITCompiler::GreaterThan, JITCompiler::DoubleGreaterThan, operationCompareGreater))
2151 return;
2152 break;
2153
2154 case CompareGreaterEq:
2155 if (compare(node, JITCompiler::GreaterThanOrEqual, JITCompiler::DoubleGreaterThanOrEqual, operationCompareGreaterEq))
2156 return;
2157 break;
2158
2159 case CompareEqConstant:
2160 ASSERT(isNullConstant(node->child2().node()));
2161 if (nonSpeculativeCompareNull(node, node->child1()))
2162 return;
2163 break;
2164
2165 case CompareEq:
2166 if (compare(node, JITCompiler::Equal, JITCompiler::DoubleEqual, operationCompareEq))
2167 return;
2168 break;
2169
2170 case CompareStrictEq:
2171 if (compileStrictEq(node))
2172 return;
2173 break;
2174
2175 case StringCharCodeAt: {
2176 compileGetCharCodeAt(node);
2177 break;
2178 }
2179
2180 case StringCharAt: {
2181 // Relies on StringCharAt node having same basic layout as GetByVal
2182 compileGetByValOnString(node);
2183 break;
2184 }
2185
2186 case StringFromCharCode: {
2187 compileFromCharCode(node);
2188 break;
2189 }
2190
2191 case CheckArray: {
2192 checkArray(node);
2193 break;
2194 }
2195
2196 case Arrayify:
2197 case ArrayifyToStructure: {
2198 arrayify(node);
2199 break;
2200 }
2201
2202 case GetByVal: {
2203 switch (node->arrayMode().type()) {
2204 case Array::SelectUsingPredictions:
2205 case Array::ForceExit:
2206 RELEASE_ASSERT_NOT_REACHED();
2207 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
2208 break;
2209 case Array::Generic: {
2210 SpeculateCellOperand base(this, node->child1()); // Save a register, speculate cell. We'll probably be right.
2211 JSValueOperand property(this, node->child2());
2212 GPRReg baseGPR = base.gpr();
2213 GPRReg propertyTagGPR = property.tagGPR();
2214 GPRReg propertyPayloadGPR = property.payloadGPR();
2215
2216 flushRegisters();
2217 GPRResult2 resultTag(this);
2218 GPRResult resultPayload(this);
2219 callOperation(operationGetByValCell, resultTag.gpr(), resultPayload.gpr(), baseGPR, propertyTagGPR, propertyPayloadGPR);
2220
2221 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
2222 break;
2223 }
2224 case Array::Int32:
2225 case Array::Contiguous: {
2226 if (node->arrayMode().isInBounds()) {
2227 SpeculateStrictInt32Operand property(this, node->child2());
2228 StorageOperand storage(this, node->child3());
2229
2230 GPRReg propertyReg = property.gpr();
2231 GPRReg storageReg = storage.gpr();
2232
2233 if (!m_compileOkay)
2234 return;
2235
2236 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2237
2238 GPRTemporary resultPayload(this);
2239 if (node->arrayMode().type() == Array::Int32) {
2240 speculationCheck(
2241 OutOfBounds, JSValueRegs(), 0,
2242 m_jit.branch32(
2243 MacroAssembler::Equal,
2244 MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)),
2245 TrustedImm32(JSValue::EmptyValueTag)));
2246 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
2247 int32Result(resultPayload.gpr(), node);
2248 break;
2249 }
2250
2251 GPRTemporary resultTag(this);
2252 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr());
2253 speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag)));
2254 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
2255 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
2256 break;
2257 }
2258
2259 SpeculateCellOperand base(this, node->child1());
2260 SpeculateStrictInt32Operand property(this, node->child2());
2261 StorageOperand storage(this, node->child3());
2262
2263 GPRReg baseReg = base.gpr();
2264 GPRReg propertyReg = property.gpr();
2265 GPRReg storageReg = storage.gpr();
2266
2267 if (!m_compileOkay)
2268 return;
2269
2270 GPRTemporary resultTag(this);
2271 GPRTemporary resultPayload(this);
2272 GPRReg resultTagReg = resultTag.gpr();
2273 GPRReg resultPayloadReg = resultPayload.gpr();
2274
2275 MacroAssembler::JumpList slowCases;
2276
2277 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2278
2279 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagReg);
2280 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayloadReg);
2281 slowCases.append(m_jit.branch32(MacroAssembler::Equal, resultTagReg, TrustedImm32(JSValue::EmptyValueTag)));
2282
2283 addSlowPathGenerator(
2284 slowPathCall(
2285 slowCases, this, operationGetByValArrayInt,
2286 JSValueRegs(resultTagReg, resultPayloadReg), baseReg, propertyReg));
2287
2288 jsValueResult(resultTagReg, resultPayloadReg, node);
2289 break;
2290 }
2291 case Array::Double: {
2292 if (node->arrayMode().isInBounds()) {
2293 SpeculateStrictInt32Operand property(this, node->child2());
2294 StorageOperand storage(this, node->child3());
2295
2296 GPRReg propertyReg = property.gpr();
2297 GPRReg storageReg = storage.gpr();
2298
2299 if (!m_compileOkay)
2300 return;
2301
2302 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2303
2304 FPRTemporary result(this);
2305 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr());
2306 if (!node->arrayMode().isSaneChain())
2307 speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr()));
2308 doubleResult(result.fpr(), node);
2309 break;
2310 }
2311
2312 SpeculateCellOperand base(this, node->child1());
2313 SpeculateStrictInt32Operand property(this, node->child2());
2314 StorageOperand storage(this, node->child3());
2315
2316 GPRReg baseReg = base.gpr();
2317 GPRReg propertyReg = property.gpr();
2318 GPRReg storageReg = storage.gpr();
2319
2320 if (!m_compileOkay)
2321 return;
2322
2323 GPRTemporary resultTag(this);
2324 GPRTemporary resultPayload(this);
2325 FPRTemporary temp(this);
2326 GPRReg resultTagReg = resultTag.gpr();
2327 GPRReg resultPayloadReg = resultPayload.gpr();
2328 FPRReg tempReg = temp.fpr();
2329
2330 MacroAssembler::JumpList slowCases;
2331
2332 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2333
2334 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
2335 slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempReg, tempReg));
2336 boxDouble(tempReg, resultTagReg, resultPayloadReg);
2337
2338 addSlowPathGenerator(
2339 slowPathCall(
2340 slowCases, this, operationGetByValArrayInt,
2341 JSValueRegs(resultTagReg, resultPayloadReg), baseReg, propertyReg));
2342
2343 jsValueResult(resultTagReg, resultPayloadReg, node);
2344 break;
2345 }
2346 case Array::ArrayStorage:
2347 case Array::SlowPutArrayStorage: {
2348 if (node->arrayMode().isInBounds()) {
2349 SpeculateStrictInt32Operand property(this, node->child2());
2350 StorageOperand storage(this, node->child3());
2351 GPRReg propertyReg = property.gpr();
2352 GPRReg storageReg = storage.gpr();
2353
2354 if (!m_compileOkay)
2355 return;
2356
2357 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())));
2358
2359 GPRTemporary resultTag(this);
2360 GPRTemporary resultPayload(this);
2361
2362 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr());
2363 speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag)));
2364 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
2365
2366 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
2367 break;
2368 }
2369
2370 SpeculateCellOperand base(this, node->child1());
2371 SpeculateStrictInt32Operand property(this, node->child2());
2372 StorageOperand storage(this, node->child3());
2373 GPRReg propertyReg = property.gpr();
2374 GPRReg storageReg = storage.gpr();
2375 GPRReg baseReg = base.gpr();
2376
2377 if (!m_compileOkay)
2378 return;
2379
2380 GPRTemporary resultTag(this);
2381 GPRTemporary resultPayload(this);
2382 GPRReg resultTagReg = resultTag.gpr();
2383 GPRReg resultPayloadReg = resultPayload.gpr();
2384
2385 JITCompiler::Jump outOfBounds = m_jit.branch32(
2386 MacroAssembler::AboveOrEqual, propertyReg,
2387 MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset()));
2388
2389 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagReg);
2390 JITCompiler::Jump hole = m_jit.branch32(
2391 MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag));
2392 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayloadReg);
2393
2394 JITCompiler::JumpList slowCases;
2395 slowCases.append(outOfBounds);
2396 slowCases.append(hole);
2397 addSlowPathGenerator(
2398 slowPathCall(
2399 slowCases, this, operationGetByValArrayInt,
2400 JSValueRegs(resultTagReg, resultPayloadReg),
2401 baseReg, propertyReg));
2402
2403 jsValueResult(resultTagReg, resultPayloadReg, node);
2404 break;
2405 }
2406 case Array::String:
2407 compileGetByValOnString(node);
2408 break;
2409 case Array::Arguments:
2410 compileGetByValOnArguments(node);
2411 break;
2412 default: {
2413 TypedArrayType type = node->arrayMode().typedArrayType();
2414 if (isInt(type))
2415 compileGetByValOnIntTypedArray(node, type);
2416 else
2417 compileGetByValOnFloatTypedArray(node, type);
2418 } }
2419 break;
2420 }
2421
2422 case PutByValDirect:
2423 case PutByVal:
2424 case PutByValAlias: {
2425 Edge child1 = m_jit.graph().varArgChild(node, 0);
2426 Edge child2 = m_jit.graph().varArgChild(node, 1);
2427 Edge child3 = m_jit.graph().varArgChild(node, 2);
2428 Edge child4 = m_jit.graph().varArgChild(node, 3);
2429
2430 ArrayMode arrayMode = node->arrayMode().modeForPut();
2431 bool alreadyHandled = false;
2432
2433 switch (arrayMode.type()) {
2434 case Array::SelectUsingPredictions:
2435 case Array::ForceExit:
2436 RELEASE_ASSERT_NOT_REACHED();
2437 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
2438 alreadyHandled = true;
2439 break;
2440 case Array::Generic: {
2441 ASSERT(node->op() == PutByVal || node->op() == PutByValDirect);
2442
2443 SpeculateCellOperand base(this, child1); // Save a register, speculate cell. We'll probably be right.
2444 JSValueOperand property(this, child2);
2445 JSValueOperand value(this, child3);
2446 GPRReg baseGPR = base.gpr();
2447 GPRReg propertyTagGPR = property.tagGPR();
2448 GPRReg propertyPayloadGPR = property.payloadGPR();
2449 GPRReg valueTagGPR = value.tagGPR();
2450 GPRReg valuePayloadGPR = value.payloadGPR();
2451
2452 flushRegisters();
2453 if (node->op() == PutByValDirect)
2454 callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValDirectCellStrict : operationPutByValDirectCellNonStrict, baseGPR, propertyTagGPR, propertyPayloadGPR, valueTagGPR, valuePayloadGPR);
2455 else
2456 callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValCellStrict : operationPutByValCellNonStrict, baseGPR, propertyTagGPR, propertyPayloadGPR, valueTagGPR, valuePayloadGPR);
2457
2458 noResult(node);
2459 alreadyHandled = true;
2460 break;
2461 }
2462 default:
2463 break;
2464 }
2465
2466 if (alreadyHandled)
2467 break;
2468
2469 SpeculateCellOperand base(this, child1);
2470 SpeculateStrictInt32Operand property(this, child2);
2471
2472 GPRReg baseReg = base.gpr();
2473 GPRReg propertyReg = property.gpr();
2474
2475 switch (arrayMode.type()) {
2476 case Array::Int32: {
2477 SpeculateInt32Operand value(this, child3);
2478
2479 GPRReg valuePayloadReg = value.gpr();
2480
2481 if (!m_compileOkay)
2482 return;
2483
2484 compileContiguousPutByVal(node, base, property, value, valuePayloadReg, TrustedImm32(JSValue::Int32Tag));
2485 break;
2486 }
2487 case Array::Contiguous: {
2488 JSValueOperand value(this, child3);
2489
2490 GPRReg valueTagReg = value.tagGPR();
2491 GPRReg valuePayloadReg = value.payloadGPR();
2492
2493 if (!m_compileOkay)
2494 return;
2495
2496 compileContiguousPutByVal(node, base, property, value, valuePayloadReg, valueTagReg);
2497 break;
2498 }
2499 case Array::Double: {
2500 compileDoublePutByVal(node, base, property);
2501 break;
2502 }
2503 case Array::ArrayStorage:
2504 case Array::SlowPutArrayStorage: {
2505 JSValueOperand value(this, child3);
2506
2507 GPRReg valueTagReg = value.tagGPR();
2508 GPRReg valuePayloadReg = value.payloadGPR();
2509
2510 if (!m_compileOkay)
2511 return;
2512
2513 StorageOperand storage(this, child4);
2514 GPRReg storageReg = storage.gpr();
2515
2516 if (node->op() == PutByValAlias) {
2517 // Store the value to the array.
2518 GPRReg propertyReg = property.gpr();
2519 m_jit.store32(value.tagGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2520 m_jit.store32(value.payloadGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2521
2522 noResult(node);
2523 break;
2524 }
2525
2526 MacroAssembler::JumpList slowCases;
2527
2528 MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset()));
2529 if (!arrayMode.isOutOfBounds())
2530 speculationCheck(OutOfBounds, JSValueRegs(), 0, beyondArrayBounds);
2531 else
2532 slowCases.append(beyondArrayBounds);
2533
2534 // Check if we're writing to a hole; if so increment m_numValuesInVector.
2535 if (arrayMode.isInBounds()) {
2536 speculationCheck(
2537 StoreToHole, JSValueRegs(), 0,
2538 m_jit.branch32(MacroAssembler::Equal, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)));
2539 } else {
2540 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));
2541 if (arrayMode.isSlowPut()) {
2542 // This is sort of strange. If we wanted to optimize this code path, we would invert
2543 // the above branch. But it's simply not worth it since this only happens if we're
2544 // already having a bad time.
2545 slowCases.append(m_jit.jump());
2546 } else {
2547 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, ArrayStorage::numValuesInVectorOffset()));
2548
2549 // If we're writing to a hole we might be growing the array;
2550 MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
2551 m_jit.add32(TrustedImm32(1), propertyReg);
2552 m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
2553 m_jit.sub32(TrustedImm32(1), propertyReg);
2554
2555 lengthDoesNotNeedUpdate.link(&m_jit);
2556 }
2557 notHoleValue.link(&m_jit);
2558 }
2559
2560 // Store the value to the array.
2561 m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2562 m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2563
2564 base.use();
2565 property.use();
2566 value.use();
2567 storage.use();
2568
2569 if (!slowCases.empty()) {
2570 if (node->op() == PutByValDirect) {
2571 addSlowPathGenerator(slowPathCall(
2572 slowCases, this,
2573 m_jit.codeBlock()->isStrictMode() ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValDirectBeyondArrayBoundsNonStrict,
2574 NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg));
2575 } else {
2576 addSlowPathGenerator(slowPathCall(
2577 slowCases, this,
2578 m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
2579 NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg));
2580 }
2581 }
2582
2583 noResult(node, UseChildrenCalledExplicitly);
2584 break;
2585 }
2586
2587 case Array::Arguments:
2588 // FIXME: we could at some point make this work. Right now we're assuming that the register
2589 // pressure would be too great.
2590 RELEASE_ASSERT_NOT_REACHED();
2591 break;
2592
2593 default: {
2594 TypedArrayType type = arrayMode.typedArrayType();
2595 if (isInt(type))
2596 compilePutByValForIntTypedArray(base.gpr(), property.gpr(), node, type);
2597 else
2598 compilePutByValForFloatTypedArray(base.gpr(), property.gpr(), node, type);
2599 } }
2600 break;
2601 }
2602
2603 case RegExpExec: {
2604 if (compileRegExpExec(node))
2605 return;
2606
2607 if (!node->adjustedRefCount()) {
2608 SpeculateCellOperand base(this, node->child1());
2609 SpeculateCellOperand argument(this, node->child2());
2610 GPRReg baseGPR = base.gpr();
2611 GPRReg argumentGPR = argument.gpr();
2612
2613 flushRegisters();
2614 GPRResult result(this);
2615 callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
2616
2617 // Must use jsValueResult because otherwise we screw up register
2618 // allocation, which thinks that this node has a result.
2619 booleanResult(result.gpr(), node);
2620 break;
2621 }
2622
2623 SpeculateCellOperand base(this, node->child1());
2624 SpeculateCellOperand argument(this, node->child2());
2625 GPRReg baseGPR = base.gpr();
2626 GPRReg argumentGPR = argument.gpr();
2627
2628 flushRegisters();
2629 GPRResult2 resultTag(this);
2630 GPRResult resultPayload(this);
2631 callOperation(operationRegExpExec, resultTag.gpr(), resultPayload.gpr(), baseGPR, argumentGPR);
2632
2633 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
2634 break;
2635 }
2636
2637 case RegExpTest: {
2638 SpeculateCellOperand base(this, node->child1());
2639 SpeculateCellOperand argument(this, node->child2());
2640 GPRReg baseGPR = base.gpr();
2641 GPRReg argumentGPR = argument.gpr();
2642
2643 flushRegisters();
2644 GPRResult result(this);
2645 callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
2646
2647 // If we add a DataFormatBool, we should use it here.
2648 booleanResult(result.gpr(), node);
2649 break;
2650 }
2651
2652 case ArrayPush: {
2653 ASSERT(node->arrayMode().isJSArray());
2654
2655 SpeculateCellOperand base(this, node->child1());
2656 GPRTemporary storageLength(this);
2657
2658 GPRReg baseGPR = base.gpr();
2659 GPRReg storageLengthGPR = storageLength.gpr();
2660
2661 StorageOperand storage(this, node->child3());
2662 GPRReg storageGPR = storage.gpr();
2663
2664 switch (node->arrayMode().type()) {
2665 case Array::Int32: {
2666 SpeculateInt32Operand value(this, node->child2());
2667 GPRReg valuePayloadGPR = value.gpr();
2668
2669 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
2670 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
2671 m_jit.store32(TrustedImm32(JSValue::Int32Tag), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2672 m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2673 m_jit.add32(TrustedImm32(1), storageLengthGPR);
2674 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
2675 m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
2676
2677 addSlowPathGenerator(
2678 slowPathCall(
2679 slowPath, this, operationArrayPush,
2680 JSValueRegs(storageGPR, storageLengthGPR),
2681 TrustedImm32(JSValue::Int32Tag), valuePayloadGPR, baseGPR));
2682
2683 jsValueResult(storageGPR, storageLengthGPR, node);
2684 break;
2685 }
2686
2687 case Array::Contiguous: {
2688 JSValueOperand value(this, node->child2());
2689 GPRReg valueTagGPR = value.tagGPR();
2690 GPRReg valuePayloadGPR = value.payloadGPR();
2691
2692 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
2693 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
2694 m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2695 m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2696 m_jit.add32(TrustedImm32(1), storageLengthGPR);
2697 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
2698 m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
2699
2700 addSlowPathGenerator(
2701 slowPathCall(
2702 slowPath, this, operationArrayPush,
2703 JSValueRegs(storageGPR, storageLengthGPR),
2704 valueTagGPR, valuePayloadGPR, baseGPR));
2705
2706 jsValueResult(storageGPR, storageLengthGPR, node);
2707 break;
2708 }
2709
2710 case Array::Double: {
2711 SpeculateDoubleOperand value(this, node->child2());
2712 FPRReg valueFPR = value.fpr();
2713
2714 DFG_TYPE_CHECK(
2715 JSValueRegs(), node->child2(), SpecDoubleReal,
2716 m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
2717
2718 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
2719 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
2720 m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
2721 m_jit.add32(TrustedImm32(1), storageLengthGPR);
2722 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
2723 m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
2724
2725 addSlowPathGenerator(
2726 slowPathCall(
2727 slowPath, this, operationArrayPushDouble,
2728 JSValueRegs(storageGPR, storageLengthGPR),
2729 valueFPR, baseGPR));
2730
2731 jsValueResult(storageGPR, storageLengthGPR, node);
2732 break;
2733 }
2734
2735 case Array::ArrayStorage: {
2736 JSValueOperand value(this, node->child2());
2737 GPRReg valueTagGPR = value.tagGPR();
2738 GPRReg valuePayloadGPR = value.payloadGPR();
2739
2740 m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
2741
2742 // Refuse to handle bizarre lengths.
2743 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(0x7ffffffe)));
2744
2745 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
2746
2747 m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2748 m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2749
2750 m_jit.add32(TrustedImm32(1), storageLengthGPR);
2751 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
2752 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
2753 m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
2754
2755 addSlowPathGenerator(slowPathCall(slowPath, this, operationArrayPush, JSValueRegs(storageGPR, storageLengthGPR), valueTagGPR, valuePayloadGPR, baseGPR));
2756
2757 jsValueResult(storageGPR, storageLengthGPR, node);
2758 break;
2759 }
2760
2761 default:
2762 CRASH();
2763 break;
2764 }
2765 break;
2766 }
2767
2768 case ArrayPop: {
2769 ASSERT(node->arrayMode().isJSArray());
2770
2771 SpeculateCellOperand base(this, node->child1());
2772 StorageOperand storage(this, node->child2());
2773 GPRTemporary valueTag(this);
2774 GPRTemporary valuePayload(this);
2775
2776 GPRReg baseGPR = base.gpr();
2777 GPRReg valueTagGPR = valueTag.gpr();
2778 GPRReg valuePayloadGPR = valuePayload.gpr();
2779 GPRReg storageGPR = storage.gpr();
2780
2781 switch (node->arrayMode().type()) {
2782 case Array::Int32:
2783 case Array::Contiguous: {
2784 m_jit.load32(
2785 MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), valuePayloadGPR);
2786 MacroAssembler::Jump undefinedCase =
2787 m_jit.branchTest32(MacroAssembler::Zero, valuePayloadGPR);
2788 m_jit.sub32(TrustedImm32(1), valuePayloadGPR);
2789 m_jit.store32(
2790 valuePayloadGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
2791 m_jit.load32(
2792 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)),
2793 valueTagGPR);
2794 MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
2795 m_jit.store32(
2796 MacroAssembler::TrustedImm32(JSValue::EmptyValueTag),
2797 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2798 m_jit.load32(
2799 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)),
2800 valuePayloadGPR);
2801
2802 addSlowPathGenerator(
2803 slowPathMove(
2804 undefinedCase, this,
2805 MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR,
2806 MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR));
2807 addSlowPathGenerator(
2808 slowPathCall(
2809 slowCase, this, operationArrayPopAndRecoverLength,
2810 JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR));
2811
2812 jsValueResult(valueTagGPR, valuePayloadGPR, node);
2813 break;
2814 }
2815
2816 case Array::Double: {
2817 FPRTemporary temp(this);
2818 FPRReg tempFPR = temp.fpr();
2819
2820 m_jit.load32(
2821 MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), valuePayloadGPR);
2822 MacroAssembler::Jump undefinedCase =
2823 m_jit.branchTest32(MacroAssembler::Zero, valuePayloadGPR);
2824 m_jit.sub32(TrustedImm32(1), valuePayloadGPR);
2825 m_jit.store32(
2826 valuePayloadGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
2827 m_jit.loadDouble(
2828 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight),
2829 tempFPR);
2830 MacroAssembler::Jump slowCase = m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempFPR, tempFPR);
2831 JSValue nan = JSValue(JSValue::EncodeAsDouble, PNaN);
2832 m_jit.store32(
2833 MacroAssembler::TrustedImm32(nan.u.asBits.tag),
2834 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2835 m_jit.store32(
2836 MacroAssembler::TrustedImm32(nan.u.asBits.payload),
2837 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2838 boxDouble(tempFPR, valueTagGPR, valuePayloadGPR);
2839
2840 addSlowPathGenerator(
2841 slowPathMove(
2842 undefinedCase, this,
2843 MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR,
2844 MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR));
2845 addSlowPathGenerator(
2846 slowPathCall(
2847 slowCase, this, operationArrayPopAndRecoverLength,
2848 JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR));
2849
2850 jsValueResult(valueTagGPR, valuePayloadGPR, node);
2851 break;
2852 }
2853
2854 case Array::ArrayStorage: {
2855 GPRTemporary storageLength(this);
2856 GPRReg storageLengthGPR = storageLength.gpr();
2857
2858 m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
2859
2860 JITCompiler::JumpList setUndefinedCases;
2861 setUndefinedCases.append(m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR));
2862
2863 m_jit.sub32(TrustedImm32(1), storageLengthGPR);
2864
2865 MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
2866
2867 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), valueTagGPR);
2868 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), valuePayloadGPR);
2869
2870 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
2871
2872 setUndefinedCases.append(m_jit.branch32(MacroAssembler::Equal, TrustedImm32(JSValue::EmptyValueTag), valueTagGPR));
2873
2874 m_jit.store32(TrustedImm32(JSValue::EmptyValueTag), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2875
2876 m_jit.sub32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
2877
2878 addSlowPathGenerator(
2879 slowPathMove(
2880 setUndefinedCases, this,
2881 MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR,
2882 MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR));
2883
2884 addSlowPathGenerator(
2885 slowPathCall(
2886 slowCase, this, operationArrayPop,
2887 JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR));
2888
2889 jsValueResult(valueTagGPR, valuePayloadGPR, node);
2890 break;
2891 }
2892
2893 default:
2894 CRASH();
2895 break;
2896 }
2897 break;
2898 }
2899
2900 case DFG::Jump: {
2901 jump(node->targetBlock());
2902 noResult(node);
2903 break;
2904 }
2905
2906 case Branch:
2907 emitBranch(node);
2908 break;
2909
2910 case Switch:
2911 emitSwitch(node);
2912 break;
2913
2914 case Return: {
2915 ASSERT(GPRInfo::callFrameRegister != GPRInfo::regT2);
2916 ASSERT(GPRInfo::regT1 != GPRInfo::returnValueGPR);
2917 ASSERT(GPRInfo::returnValueGPR != GPRInfo::callFrameRegister);
2918
2919 // Return the result in returnValueGPR.
2920 JSValueOperand op1(this, node->child1());
2921 op1.fill();
2922 if (op1.isDouble())
2923 boxDouble(op1.fpr(), GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
2924 else {
2925 if (op1.payloadGPR() == GPRInfo::returnValueGPR2 && op1.tagGPR() == GPRInfo::returnValueGPR)
2926 m_jit.swap(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2);
2927 else if (op1.payloadGPR() == GPRInfo::returnValueGPR2) {
2928 m_jit.move(op1.payloadGPR(), GPRInfo::returnValueGPR);
2929 m_jit.move(op1.tagGPR(), GPRInfo::returnValueGPR2);
2930 } else {
2931 m_jit.move(op1.tagGPR(), GPRInfo::returnValueGPR2);
2932 m_jit.move(op1.payloadGPR(), GPRInfo::returnValueGPR);
2933 }
2934 }
2935
2936 m_jit.emitFunctionEpilogue();
2937 m_jit.ret();
2938
2939 noResult(node);
2940 break;
2941 }
2942
2943 case Throw:
2944 case ThrowReferenceError: {
2945 // We expect that throw statements are rare and are intended to exit the code block
2946 // anyway, so we just OSR back to the old JIT for now.
2947 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
2948 break;
2949 }
2950
2951 case BooleanToNumber: {
2952 switch (node->child1().useKind()) {
2953 case BooleanUse: {
2954 SpeculateBooleanOperand value(this, node->child1());
2955 GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).
2956
2957 m_jit.move(value.gpr(), result.gpr());
2958
2959 int32Result(result.gpr(), node);
2960 break;
2961 }
2962
2963 case UntypedUse: {
2964 JSValueOperand value(this, node->child1());
2965 GPRTemporary resultTag(this);
2966 GPRTemporary resultPayload(this);
2967
2968 GPRReg valueTagGPR = value.tagGPR();
2969 GPRReg valuePayloadGPR = value.payloadGPR();
2970 GPRReg resultTagGPR = resultTag.gpr();
2971 GPRReg resultPayloadGPR = resultPayload.gpr();
2972
2973 m_jit.move(valuePayloadGPR, resultPayloadGPR);
2974 JITCompiler::Jump isBoolean = m_jit.branch32(
2975 JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::BooleanTag));
2976 m_jit.move(valueTagGPR, resultTagGPR);
2977 JITCompiler::Jump done = m_jit.jump();
2978 isBoolean.link(&m_jit);
2979 m_jit.move(TrustedImm32(JSValue::Int32Tag), resultTagGPR);
2980 done.link(&m_jit);
2981
2982 jsValueResult(resultTagGPR, resultPayloadGPR, node);
2983 break;
2984 }
2985
2986 default:
2987 RELEASE_ASSERT_NOT_REACHED();
2988 break;
2989 }
2990 break;
2991 }
2992
2993 case ToPrimitive: {
2994 RELEASE_ASSERT(node->child1().useKind() == UntypedUse);
2995 JSValueOperand op1(this, node->child1());
2996 GPRTemporary resultTag(this, Reuse, op1, TagWord);
2997 GPRTemporary resultPayload(this, Reuse, op1, PayloadWord);
2998
2999 GPRReg op1TagGPR = op1.tagGPR();
3000 GPRReg op1PayloadGPR = op1.payloadGPR();
3001 GPRReg resultTagGPR = resultTag.gpr();
3002 GPRReg resultPayloadGPR = resultPayload.gpr();
3003
3004 op1.use();
3005
3006 if (!(m_state.forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean))) {
3007 m_jit.move(op1TagGPR, resultTagGPR);
3008 m_jit.move(op1PayloadGPR, resultPayloadGPR);
3009 } else {
3010 MacroAssembler::Jump alreadyPrimitive = branchNotCell(op1.jsValueRegs());
3011 MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1PayloadGPR, JSCell::structureIDOffset()), MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()));
3012
3013 alreadyPrimitive.link(&m_jit);
3014 m_jit.move(op1TagGPR, resultTagGPR);
3015 m_jit.move(op1PayloadGPR, resultPayloadGPR);
3016
3017 addSlowPathGenerator(
3018 slowPathCall(
3019 notPrimitive, this, operationToPrimitive,
3020 JSValueRegs(resultTagGPR, resultPayloadGPR), op1TagGPR, op1PayloadGPR));
3021 }
3022
3023 jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
3024 break;
3025 }
3026
3027 case ToString: {
3028 if (node->child1().useKind() == UntypedUse) {
3029 JSValueOperand op1(this, node->child1());
3030 GPRReg op1PayloadGPR = op1.payloadGPR();
3031 GPRReg op1TagGPR = op1.tagGPR();
3032
3033 GPRResult result(this);
3034 GPRReg resultGPR = result.gpr();
3035
3036 flushRegisters();
3037
3038 JITCompiler::Jump done;
3039 if (node->child1()->prediction() & SpecString) {
3040 JITCompiler::Jump slowPath1 = branchNotCell(op1.jsValueRegs());
3041 JITCompiler::Jump slowPath2 = m_jit.branchPtr(
3042 JITCompiler::NotEqual,
3043 JITCompiler::Address(op1PayloadGPR, JSCell::structureIDOffset()),
3044 TrustedImmPtr(m_jit.vm()->stringStructure.get()));
3045 m_jit.move(op1PayloadGPR, resultGPR);
3046 done = m_jit.jump();
3047 slowPath1.link(&m_jit);
3048 slowPath2.link(&m_jit);
3049 }
3050 callOperation(operationToString, resultGPR, op1TagGPR, op1PayloadGPR);
3051 if (done.isSet())
3052 done.link(&m_jit);
3053 cellResult(resultGPR, node);
3054 break;
3055 }
3056
3057 compileToStringOnCell(node);
3058 break;
3059 }
3060
3061 case NewStringObject: {
3062 compileNewStringObject(node);
3063 break;
3064 }
3065
3066 case NewArray: {
3067 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
3068 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(node->indexingType())) {
3069 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType());
3070 ASSERT(structure->indexingType() == node->indexingType());
3071 ASSERT(
3072 hasUndecided(structure->indexingType())
3073 || hasInt32(structure->indexingType())
3074 || hasDouble(structure->indexingType())
3075 || hasContiguous(structure->indexingType()));
3076
3077 unsigned numElements = node->numChildren();
3078
3079 GPRTemporary result(this);
3080 GPRTemporary storage(this);
3081
3082 GPRReg resultGPR = result.gpr();
3083 GPRReg storageGPR = storage.gpr();
3084
3085 emitAllocateJSArray(resultGPR, structure, storageGPR, numElements);
3086
3087 // At this point, one way or another, resultGPR and storageGPR have pointers to
3088 // the JSArray and the Butterfly, respectively.
3089
3090 ASSERT(!hasUndecided(structure->indexingType()) || !node->numChildren());
3091
3092 for (unsigned operandIdx = 0; operandIdx < node->numChildren(); ++operandIdx) {
3093 Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + operandIdx];
3094 switch (node->indexingType()) {
3095 case ALL_BLANK_INDEXING_TYPES:
3096 case ALL_UNDECIDED_INDEXING_TYPES:
3097 CRASH();
3098 break;
3099 case ALL_DOUBLE_INDEXING_TYPES: {
3100 SpeculateDoubleOperand operand(this, use);
3101 FPRReg opFPR = operand.fpr();
3102 DFG_TYPE_CHECK(
3103 JSValueRegs(), use, SpecDoubleReal,
3104 m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
3105
3106 m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx));
3107 break;
3108 }
3109 case ALL_INT32_INDEXING_TYPES: {
3110 SpeculateInt32Operand operand(this, use);
3111 m_jit.store32(TrustedImm32(JSValue::Int32Tag), MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
3112 m_jit.store32(operand.gpr(), MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
3113 break;
3114 }
3115 case ALL_CONTIGUOUS_INDEXING_TYPES: {
3116 JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node->firstChild() + operandIdx]);
3117 GPRReg opTagGPR = operand.tagGPR();
3118 GPRReg opPayloadGPR = operand.payloadGPR();
3119 m_jit.store32(opTagGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
3120 m_jit.store32(opPayloadGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
3121 break;
3122 }
3123 default:
3124 CRASH();
3125 break;
3126 }
3127 }
3128
3129 // Yuck, we should *really* have a way of also returning the storageGPR. But
3130 // that's the least of what's wrong with this code. We really shouldn't be
3131 // allocating the array after having computed - and probably spilled to the
3132 // stack - all of the things that will go into the array. The solution to that
3133 // bigger problem will also likely fix the redundancy in reloading the storage
3134 // pointer that we currently have.
3135
3136 cellResult(resultGPR, node);
3137 break;
3138 }
3139
3140 if (!node->numChildren()) {
3141 flushRegisters();
3142 GPRResult result(this);
3143 callOperation(
3144 operationNewEmptyArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
3145 cellResult(result.gpr(), node);
3146 break;
3147 }
3148
3149 size_t scratchSize = sizeof(EncodedJSValue) * node->numChildren();
3150 ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
3151 EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
3152
3153 for (unsigned operandIdx = 0; operandIdx < node->numChildren(); ++operandIdx) {
3154 // Need to perform the speculations that this node promises to perform. If we're
3155 // emitting code here and the indexing type is not array storage then there is
3156 // probably something hilarious going on and we're already failing at all the
3157 // things, but at least we're going to be sound.
3158 Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + operandIdx];
3159 switch (node->indexingType()) {
3160 case ALL_BLANK_INDEXING_TYPES:
3161 case ALL_UNDECIDED_INDEXING_TYPES:
3162 CRASH();
3163 break;
3164 case ALL_DOUBLE_INDEXING_TYPES: {
3165 SpeculateDoubleOperand operand(this, use);
3166 FPRReg opFPR = operand.fpr();
3167 DFG_TYPE_CHECK(
3168 JSValueRegs(), use, SpecFullRealNumber,
3169 m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
3170
3171 m_jit.storeDouble(opFPR, TrustedImmPtr(reinterpret_cast<char*>(buffer + operandIdx)));
3172 break;
3173 }
3174 case ALL_INT32_INDEXING_TYPES: {
3175 SpeculateInt32Operand operand(this, use);
3176 GPRReg opGPR = operand.gpr();
3177 m_jit.store32(TrustedImm32(JSValue::Int32Tag), reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
3178 m_jit.store32(opGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
3179 break;
3180 }
3181 case ALL_CONTIGUOUS_INDEXING_TYPES:
3182 case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
3183 JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node->firstChild() + operandIdx]);
3184 GPRReg opTagGPR = operand.tagGPR();
3185 GPRReg opPayloadGPR = operand.payloadGPR();
3186
3187 m_jit.store32(opTagGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
3188 m_jit.store32(opPayloadGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
3189 operand.use();
3190 break;
3191 }
3192 default:
3193 CRASH();
3194 break;
3195 }
3196 }
3197
3198 switch (node->indexingType()) {
3199 case ALL_DOUBLE_INDEXING_TYPES:
3200 case ALL_INT32_INDEXING_TYPES:
3201 useChildren(node);
3202 break;
3203 default:
3204 break;
3205 }
3206
3207 flushRegisters();
3208
3209 if (scratchSize) {
3210 GPRTemporary scratch(this);
3211
3212 // Tell GC mark phase how much of the scratch buffer is active during call.
3213 m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
3214 m_jit.storePtr(TrustedImmPtr(scratchSize), scratch.gpr());
3215 }
3216
3217 GPRResult result(this);
3218
3219 callOperation(
3220 operationNewArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()),
3221 static_cast<void*>(buffer), node->numChildren());
3222
3223 if (scratchSize) {
3224 GPRTemporary scratch(this);
3225
3226 m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
3227 m_jit.storePtr(TrustedImmPtr(0), scratch.gpr());
3228 }
3229
3230 cellResult(result.gpr(), node, UseChildrenCalledExplicitly);
3231 break;
3232 }
3233
3234 case NewArrayWithSize: {
3235 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
3236 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(node->indexingType())) {
3237 SpeculateStrictInt32Operand size(this, node->child1());
3238 GPRTemporary result(this);
3239 GPRTemporary storage(this);
3240 GPRTemporary scratch(this);
3241 GPRTemporary scratch2(this);
3242
3243 GPRReg sizeGPR = size.gpr();
3244 GPRReg resultGPR = result.gpr();
3245 GPRReg storageGPR = storage.gpr();
3246 GPRReg scratchGPR = scratch.gpr();
3247 GPRReg scratch2GPR = scratch2.gpr();
3248
3249 MacroAssembler::JumpList slowCases;
3250 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)));
3251
3252 ASSERT((1 << 3) == sizeof(JSValue));
3253 m_jit.move(sizeGPR, scratchGPR);
3254 m_jit.lshift32(TrustedImm32(3), scratchGPR);
3255 m_jit.add32(TrustedImm32(sizeof(IndexingHeader)), scratchGPR, resultGPR);
3256 slowCases.append(
3257 emitAllocateBasicStorage(resultGPR, storageGPR));
3258 m_jit.subPtr(scratchGPR, storageGPR);
3259 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType());
3260 emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
3261
3262 m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
3263 m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
3264
3265 if (hasDouble(node->indexingType())) {
3266 JSValue nan = JSValue(JSValue::EncodeAsDouble, PNaN);
3267
3268 m_jit.move(sizeGPR, scratchGPR);
3269 MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratchGPR);
3270 MacroAssembler::Label loop = m_jit.label();
3271 m_jit.sub32(TrustedImm32(1), scratchGPR);
3272 m_jit.store32(TrustedImm32(nan.u.asBits.tag), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
3273 m_jit.store32(TrustedImm32(nan.u.asBits.payload), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
3274 m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
3275 done.link(&m_jit);
3276 }
3277
3278 addSlowPathGenerator(adoptPtr(
3279 new CallArrayAllocatorWithVariableSizeSlowPathGenerator(
3280 slowCases, this, operationNewArrayWithSize, resultGPR,
3281 globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()),
3282 globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage),
3283 sizeGPR)));
3284
3285 cellResult(resultGPR, node);
3286 break;
3287 }
3288
3289 SpeculateStrictInt32Operand size(this, node->child1());
3290 GPRReg sizeGPR = size.gpr();
3291 flushRegisters();
3292 GPRResult result(this);
3293 GPRReg resultGPR = result.gpr();
3294 GPRReg structureGPR = selectScratchGPR(sizeGPR);
3295 MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX));
3296 m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())), structureGPR);
3297 MacroAssembler::Jump done = m_jit.jump();
3298 bigLength.link(&m_jit);
3299 m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)), structureGPR);
3300 done.link(&m_jit);
3301 callOperation(
3302 operationNewArrayWithSize, resultGPR, structureGPR, sizeGPR);
3303 cellResult(resultGPR, node);
3304 break;
3305 }
3306
3307 case NewArrayBuffer: {
3308 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
3309 IndexingType indexingType = node->indexingType();
3310 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(indexingType)) {
3311 unsigned numElements = node->numConstants();
3312
3313 GPRTemporary result(this);
3314 GPRTemporary storage(this);
3315
3316 GPRReg resultGPR = result.gpr();
3317 GPRReg storageGPR = storage.gpr();
3318
3319 emitAllocateJSArray(resultGPR, globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), storageGPR, numElements);
3320
3321 if (node->indexingType() == ArrayWithDouble) {
3322 JSValue* data = m_jit.codeBlock()->constantBuffer(node->startConstant());
3323 for (unsigned index = 0; index < node->numConstants(); ++index) {
3324 union {
3325 int32_t halves[2];
3326 double value;
3327 } u;
3328 u.value = data[index].asNumber();
3329 m_jit.store32(Imm32(u.halves[0]), MacroAssembler::Address(storageGPR, sizeof(double) * index));
3330 m_jit.store32(Imm32(u.halves[1]), MacroAssembler::Address(storageGPR, sizeof(double) * index + sizeof(int32_t)));
3331 }
3332 } else {
3333 int32_t* data = bitwise_cast<int32_t*>(m_jit.codeBlock()->constantBuffer(node->startConstant()));
3334 for (unsigned index = 0; index < node->numConstants() * 2; ++index) {
3335 m_jit.store32(
3336 Imm32(data[index]), MacroAssembler::Address(storageGPR, sizeof(int32_t) * index));
3337 }
3338 }
3339
3340 cellResult(resultGPR, node);
3341 break;
3342 }
3343
3344 flushRegisters();
3345 GPRResult result(this);
3346
3347 callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()), node->startConstant(), node->numConstants());
3348
3349 cellResult(result.gpr(), node);
3350 break;
3351 }
3352
3353 case NewTypedArray: {
3354 switch (node->child1().useKind()) {
3355 case Int32Use:
3356 compileNewTypedArray(node);
3357 break;
3358 case UntypedUse: {
3359 JSValueOperand argument(this, node->child1());
3360 GPRReg argumentTagGPR = argument.tagGPR();
3361 GPRReg argumentPayloadGPR = argument.payloadGPR();
3362
3363 flushRegisters();
3364
3365 GPRResult result(this);
3366 GPRReg resultGPR = result.gpr();
3367
3368 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
3369 callOperation(
3370 operationNewTypedArrayWithOneArgumentForType(node->typedArrayType()),
3371 resultGPR, globalObject->typedArrayStructure(node->typedArrayType()),
3372 argumentTagGPR, argumentPayloadGPR);
3373
3374 cellResult(resultGPR, node);
3375 break;
3376 }
3377 default:
3378 RELEASE_ASSERT_NOT_REACHED();
3379 break;
3380 }
3381 break;
3382 }
3383
3384 case NewRegexp: {
3385 flushRegisters();
3386 GPRResult resultPayload(this);
3387 GPRResult2 resultTag(this);
3388
3389 callOperation(operationNewRegexp, resultTag.gpr(), resultPayload.gpr(), m_jit.codeBlock()->regexp(node->regexpIndex()));
3390
3391 // FIXME: make the callOperation above explicitly return a cell result, or jitAssert the tag is a cell tag.
3392 cellResult(resultPayload.gpr(), node);
3393 break;
3394 }
3395
3396 case ToThis: {
3397 ASSERT(node->child1().useKind() == UntypedUse);
3398 JSValueOperand thisValue(this, node->child1());
3399 GPRTemporary temp(this);
3400 GPRTemporary tempTag(this);
3401 GPRReg thisValuePayloadGPR = thisValue.payloadGPR();
3402 GPRReg thisValueTagGPR = thisValue.tagGPR();
3403 GPRReg tempGPR = temp.gpr();
3404 GPRReg tempTagGPR = tempTag.gpr();
3405
3406 MacroAssembler::JumpList slowCases;
3407 slowCases.append(branchNotCell(thisValue.jsValueRegs()));
3408 slowCases.append(m_jit.branch8(
3409 MacroAssembler::NotEqual,
3410 MacroAssembler::Address(thisValuePayloadGPR, JSCell::typeInfoTypeOffset()),
3411 TrustedImm32(FinalObjectType)));
3412 m_jit.move(thisValuePayloadGPR, tempGPR);
3413 m_jit.move(thisValueTagGPR, tempTagGPR);
3414 J_JITOperation_EJ function;
3415 if (m_jit.graph().executableFor(node->origin.semantic)->isStrictMode())
3416 function = operationToThisStrict;
3417 else
3418 function = operationToThis;
3419 addSlowPathGenerator(
3420 slowPathCall(
3421 slowCases, this, function,
3422 JSValueRegs(tempTagGPR, tempGPR), thisValueTagGPR, thisValuePayloadGPR));
3423
3424 jsValueResult(tempTagGPR, tempGPR, node);
3425 break;
3426 }
3427
3428 case CreateThis: {
3429 // Note that there is not so much profit to speculate here. The only things we
3430 // speculate on are (1) that it's a cell, since that eliminates cell checks
3431 // later if the proto is reused, and (2) if we have a FinalObject prediction
3432 // then we speculate because we want to get recompiled if it isn't (since
3433 // otherwise we'd start taking slow path a lot).
3434
3435 SpeculateCellOperand callee(this, node->child1());
3436 GPRTemporary result(this);
3437 GPRTemporary allocator(this);
3438 GPRTemporary structure(this);
3439 GPRTemporary scratch(this);
3440
3441 GPRReg calleeGPR = callee.gpr();
3442 GPRReg resultGPR = result.gpr();
3443 GPRReg allocatorGPR = allocator.gpr();
3444 GPRReg structureGPR = structure.gpr();
3445 GPRReg scratchGPR = scratch.gpr();
3446
3447 MacroAssembler::JumpList slowPath;
3448
3449 m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorGPR);
3450 m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureGPR);
3451 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, allocatorGPR));
3452 emitAllocateJSObject(resultGPR, allocatorGPR, structureGPR, TrustedImmPtr(0), scratchGPR, slowPath);
3453
3454 addSlowPathGenerator(slowPathCall(slowPath, this, operationCreateThis, resultGPR, calleeGPR, node->inlineCapacity()));
3455
3456 cellResult(resultGPR, node);
3457 break;
3458 }
3459
3460 case AllocationProfileWatchpoint:
3461 case TypedArrayWatchpoint: {
3462 noResult(node);
3463 break;
3464 }
3465
3466 case NewObject: {
3467 GPRTemporary result(this);
3468 GPRTemporary allocator(this);
3469 GPRTemporary scratch(this);
3470
3471 GPRReg resultGPR = result.gpr();
3472 GPRReg allocatorGPR = allocator.gpr();
3473 GPRReg scratchGPR = scratch.gpr();
3474
3475 MacroAssembler::JumpList slowPath;
3476
3477 Structure* structure = node->structure();
3478 size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity());
3479 MarkedAllocator* allocatorPtr = &m_jit.vm()->heap.allocatorForObjectWithoutDestructor(allocationSize);
3480
3481 m_jit.move(TrustedImmPtr(allocatorPtr), allocatorGPR);
3482 emitAllocateJSObject(resultGPR, allocatorGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratchGPR, slowPath);
3483
3484 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewObject, resultGPR, structure));
3485
3486 cellResult(resultGPR, node);
3487 break;
3488 }
3489
3490 case GetCallee: {
3491 GPRTemporary result(this);
3492 m_jit.loadPtr(JITCompiler::payloadFor(JSStack::Callee), result.gpr());
3493 cellResult(result.gpr(), node);
3494 break;
3495 }
3496
3497 case GetScope: {
3498 SpeculateCellOperand function(this, node->child1());
3499 GPRTemporary result(this, Reuse, function);
3500 m_jit.loadPtr(JITCompiler::Address(function.gpr(), JSFunction::offsetOfScopeChain()), result.gpr());
3501 cellResult(result.gpr(), node);
3502 break;
3503 }
3504
3505 case GetMyScope: {
3506 GPRTemporary result(this);
3507 GPRReg resultGPR = result.gpr();
3508
3509 m_jit.loadPtr(JITCompiler::payloadFor(JSStack::ScopeChain), resultGPR);
3510 cellResult(resultGPR, node);
3511 break;
3512 }
3513
3514 case SkipTopScope: {
3515 SpeculateCellOperand scope(this, node->child1());
3516 GPRTemporary result(this, Reuse, scope);
3517 GPRReg resultGPR = result.gpr();
3518 m_jit.move(scope.gpr(), resultGPR);
3519 JITCompiler::Jump activationNotCreated =
3520 m_jit.branchTestPtr(
3521 JITCompiler::Zero,
3522 JITCompiler::payloadFor(
3523 static_cast<VirtualRegister>(m_jit.graph().machineActivationRegister())));
3524 m_jit.loadPtr(JITCompiler::Address(resultGPR, JSScope::offsetOfNext()), resultGPR);
3525 activationNotCreated.link(&m_jit);
3526 cellResult(resultGPR, node);
3527 break;
3528 }
3529
3530 case SkipScope: {
3531 SpeculateCellOperand scope(this, node->child1());
3532 GPRTemporary result(this, Reuse, scope);
3533 m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSScope::offsetOfNext()), result.gpr());
3534 cellResult(result.gpr(), node);
3535 break;
3536 }
3537
3538 case GetClosureRegisters: {
3539 if (WriteBarrierBase<Unknown>* registers = m_jit.graph().tryGetRegisters(node->child1().node())) {
3540 GPRTemporary result(this);
3541 GPRReg resultGPR = result.gpr();
3542 m_jit.move(TrustedImmPtr(registers), resultGPR);
3543 storageResult(resultGPR, node);
3544 break;
3545 }
3546
3547 SpeculateCellOperand scope(this, node->child1());
3548 GPRTemporary result(this);
3549 GPRReg scopeGPR = scope.gpr();
3550 GPRReg resultGPR = result.gpr();
3551
3552 m_jit.loadPtr(JITCompiler::Address(scopeGPR, JSVariableObject::offsetOfRegisters()), resultGPR);
3553 storageResult(resultGPR, node);
3554 break;
3555 }
3556 case GetClosureVar: {
3557 StorageOperand registers(this, node->child1());
3558 GPRTemporary resultTag(this);
3559 GPRTemporary resultPayload(this);
3560 GPRReg registersGPR = registers.gpr();
3561 GPRReg resultTagGPR = resultTag.gpr();
3562 GPRReg resultPayloadGPR = resultPayload.gpr();
3563 m_jit.load32(JITCompiler::Address(registersGPR, node->varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
3564 m_jit.load32(JITCompiler::Address(registersGPR, node->varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
3565 jsValueResult(resultTagGPR, resultPayloadGPR, node);
3566 break;
3567 }
3568 case PutClosureVar: {
3569 StorageOperand registers(this, node->child2());
3570 JSValueOperand value(this, node->child3());
3571 GPRTemporary scratchRegister(this);
3572
3573 GPRReg registersGPR = registers.gpr();
3574 GPRReg valueTagGPR = value.tagGPR();
3575 GPRReg valuePayloadGPR = value.payloadGPR();
3576
3577 speculate(node, node->child1());
3578
3579 m_jit.store32(valueTagGPR, JITCompiler::Address(registersGPR, node->varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
3580 m_jit.store32(valuePayloadGPR, JITCompiler::Address(registersGPR, node->varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
3581 noResult(node);
3582 break;
3583 }
3584
3585 case GetById: {
3586 ASSERT(node->prediction());
3587
3588 switch (node->child1().useKind()) {
3589 case CellUse: {
3590 SpeculateCellOperand base(this, node->child1());
3591 GPRTemporary resultTag(this);
3592 GPRTemporary resultPayload(this, Reuse, base);
3593
3594 GPRReg baseGPR = base.gpr();
3595 GPRReg resultTagGPR = resultTag.gpr();
3596 GPRReg resultPayloadGPR = resultPayload.gpr();
3597
3598 base.use();
3599
3600 cachedGetById(node->origin.semantic, InvalidGPRReg, baseGPR, resultTagGPR, resultPayloadGPR, node->identifierNumber());
3601
3602 jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
3603 break;
3604 }
3605
3606 case UntypedUse: {
3607 JSValueOperand base(this, node->child1());
3608 GPRTemporary resultTag(this);
3609 GPRTemporary resultPayload(this, Reuse, base, TagWord);
3610
3611 GPRReg baseTagGPR = base.tagGPR();
3612 GPRReg basePayloadGPR = base.payloadGPR();
3613 GPRReg resultTagGPR = resultTag.gpr();
3614 GPRReg resultPayloadGPR = resultPayload.gpr();
3615
3616 base.use();
3617
3618 JITCompiler::Jump notCell = branchNotCell(base.jsValueRegs());
3619
3620 cachedGetById(node->origin.semantic, baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, node->identifierNumber(), notCell);
3621
3622 jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
3623 break;
3624 }
3625
3626 default:
3627 RELEASE_ASSERT_NOT_REACHED();
3628 break;
3629 }
3630 break;
3631 }
3632
3633 case GetByIdFlush: {
3634 if (!node->prediction()) {
3635 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
3636 break;
3637 }
3638
3639 switch (node->child1().useKind()) {
3640 case CellUse: {
3641 SpeculateCellOperand base(this, node->child1());
3642
3643 GPRReg baseGPR = base.gpr();
3644
3645 GPRResult resultPayload(this);
3646 GPRResult2 resultTag(this);
3647 GPRReg resultPayloadGPR = resultPayload.gpr();
3648 GPRReg resultTagGPR = resultTag.gpr();
3649
3650 base.use();
3651
3652 flushRegisters();
3653
3654 cachedGetById(node->origin.semantic, InvalidGPRReg, baseGPR, resultTagGPR, resultPayloadGPR, node->identifierNumber(), JITCompiler::Jump(), DontSpill);
3655
3656 jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
3657 break;
3658 }
3659
3660 case UntypedUse: {
3661 JSValueOperand base(this, node->child1());
3662 GPRReg baseTagGPR = base.tagGPR();
3663 GPRReg basePayloadGPR = base.payloadGPR();
3664
3665 GPRResult resultPayload(this);
3666 GPRResult2 resultTag(this);
3667 GPRReg resultPayloadGPR = resultPayload.gpr();
3668 GPRReg resultTagGPR = resultTag.gpr();
3669
3670 base.use();
3671
3672 flushRegisters();
3673
3674 JITCompiler::Jump notCell = branchNotCell(base.jsValueRegs());
3675
3676 cachedGetById(node->origin.semantic, baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, node->identifierNumber(), notCell, DontSpill);
3677
3678 jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
3679 break;
3680 }
3681
3682 default:
3683 RELEASE_ASSERT_NOT_REACHED();
3684 break;
3685 }
3686 break;
3687 }
3688
3689 case GetArrayLength:
3690 compileGetArrayLength(node);
3691 break;
3692
3693 case CheckFunction: {
3694 SpeculateCellOperand function(this, node->child1());
3695 speculationCheck(BadFunction, JSValueSource::unboxedCell(function.gpr()), node->child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node->function()));
3696 noResult(node);
3697 break;
3698 }
3699
3700 case CheckExecutable: {
3701 SpeculateCellOperand function(this, node->child1());
3702 speculationCheck(BadExecutable, JSValueSource::unboxedCell(function.gpr()), node->child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, JITCompiler::Address(function.gpr(), JSFunction::offsetOfExecutable()), node->executable()));
3703 noResult(node);
3704 break;
3705 }
3706
3707 case CheckStructure: {
3708 SpeculateCellOperand base(this, node->child1());
3709
3710 ASSERT(node->structureSet().size());
3711
3712 if (node->structureSet().size() == 1) {
3713 speculationCheck(
3714 BadCache, JSValueSource::unboxedCell(base.gpr()), 0,
3715 m_jit.branchWeakPtr(
3716 JITCompiler::NotEqual,
3717 JITCompiler::Address(base.gpr(), JSCell::structureIDOffset()),
3718 node->structureSet()[0]));
3719 } else {
3720 GPRTemporary structure(this);
3721
3722 m_jit.loadPtr(JITCompiler::Address(base.gpr(), JSCell::structureIDOffset()), structure.gpr());
3723
3724 JITCompiler::JumpList done;
3725
3726 for (size_t i = 0; i < node->structureSet().size() - 1; ++i)
3727 done.append(m_jit.branchWeakPtr(JITCompiler::Equal, structure.gpr(), node->structureSet()[i]));
3728
3729 speculationCheck(
3730 BadCache, JSValueSource::unboxedCell(base.gpr()), 0,
3731 m_jit.branchWeakPtr(
3732 JITCompiler::NotEqual, structure.gpr(), node->structureSet().last()));
3733
3734 done.link(&m_jit);
3735 }
3736
3737 noResult(node);
3738 break;
3739 }
3740
3741 case StructureTransitionWatchpoint: {
3742 // There is a fascinating question here of what to do about array profiling.
3743 // We *could* try to tell the OSR exit about where the base of the access is.
3744 // The DFG will have kept it alive, though it may not be in a register, and
3745 // we shouldn't really load it since that could be a waste. For now though,
3746 // we'll just rely on the fact that when a watchpoint fires then that's
3747 // quite a hint already.
3748
3749 m_jit.addWeakReference(node->structure());
3750
3751 #if !ASSERT_DISABLED
3752 SpeculateCellOperand op1(this, node->child1());
3753 JITCompiler::Jump isOK = m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(op1.gpr(), JSCell::structureIDOffset()), TrustedImmPtr(node->structure()));
3754 m_jit.abortWithReason(DFGIneffectiveWatchpoint);
3755 isOK.link(&m_jit);
3756 #else
3757 speculateCell(node->child1());
3758 #endif
3759
3760 noResult(node);
3761 break;
3762 }
3763
3764 case PhantomPutStructure: {
3765 ASSERT(isKnownCell(node->child1().node()));
3766 m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node);
3767 noResult(node);
3768 break;
3769 }
3770
3771 case PutStructure: {
3772 m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node);
3773
3774 SpeculateCellOperand base(this, node->child1());
3775 GPRReg baseGPR = base.gpr();
3776
3777 m_jit.storePtr(MacroAssembler::TrustedImmPtr(node->structureTransitionData().newStructure), MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()));
3778
3779 noResult(node);
3780 break;
3781 }
3782
3783 case AllocatePropertyStorage:
3784 compileAllocatePropertyStorage(node);
3785 break;
3786
3787 case ReallocatePropertyStorage:
3788 compileReallocatePropertyStorage(node);
3789 break;
3790
3791 case GetButterfly: {
3792 SpeculateCellOperand base(this, node->child1());
3793 GPRTemporary result(this, Reuse, base);
3794
3795 GPRReg baseGPR = base.gpr();
3796 GPRReg resultGPR = result.gpr();
3797
3798 m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::butterflyOffset()), resultGPR);
3799
3800 storageResult(resultGPR, node);
3801 break;
3802 }
3803
3804 case GetIndexedPropertyStorage: {
3805 compileGetIndexedPropertyStorage(node);
3806 break;
3807 }
3808
3809 case ConstantStoragePointer: {
3810 compileConstantStoragePointer(node);
3811 break;
3812 }
3813
3814 case GetTypedArrayByteOffset: {
3815 compileGetTypedArrayByteOffset(node);
3816 break;
3817 }
3818
3819 case GetByOffset: {
3820 StorageOperand storage(this, node->child1());
3821 GPRTemporary resultTag(this, Reuse, storage);
3822 GPRTemporary resultPayload(this);
3823
3824 GPRReg storageGPR = storage.gpr();
3825 GPRReg resultTagGPR = resultTag.gpr();
3826 GPRReg resultPayloadGPR = resultPayload.gpr();
3827
3828 StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node->storageAccessDataIndex()];
3829
3830 m_jit.load32(JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
3831 m_jit.load32(JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
3832
3833 jsValueResult(resultTagGPR, resultPayloadGPR, node);
3834 break;
3835 }
3836
3837 case PutByOffset: {
3838 StorageOperand storage(this, node->child1());
3839 JSValueOperand value(this, node->child3());
3840
3841 GPRReg storageGPR = storage.gpr();
3842 GPRReg valueTagGPR = value.tagGPR();
3843 GPRReg valuePayloadGPR = value.payloadGPR();
3844
3845 speculate(node, node->child2());
3846
3847 StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node->storageAccessDataIndex()];
3848
3849 m_jit.storePtr(valueTagGPR, JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
3850 m_jit.storePtr(valuePayloadGPR, JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
3851
3852 noResult(node);
3853 break;
3854 }
3855
3856 case PutByIdFlush: {
3857 SpeculateCellOperand base(this, node->child1());
3858 JSValueOperand value(this, node->child2());
3859 GPRTemporary scratch(this);
3860
3861 GPRReg baseGPR = base.gpr();
3862 GPRReg valueTagGPR = value.tagGPR();
3863 GPRReg valuePayloadGPR = value.payloadGPR();
3864 GPRReg scratchGPR = scratch.gpr();
3865 flushRegisters();
3866
3867 cachedPutById(node->origin.semantic, baseGPR, valueTagGPR, valuePayloadGPR, scratchGPR, node->identifierNumber(), NotDirect, MacroAssembler::Jump(), DontSpill);
3868
3869 noResult(node);
3870 break;
3871 }
3872
3873 case PutById: {
3874 SpeculateCellOperand base(this, node->child1());
3875 JSValueOperand value(this, node->child2());
3876 GPRTemporary scratch(this);
3877
3878 GPRReg baseGPR = base.gpr();
3879 GPRReg valueTagGPR = value.tagGPR();
3880 GPRReg valuePayloadGPR = value.payloadGPR();
3881 GPRReg scratchGPR = scratch.gpr();
3882
3883 cachedPutById(node->origin.semantic, baseGPR, valueTagGPR, valuePayloadGPR, scratchGPR, node->identifierNumber(), NotDirect);
3884
3885 noResult(node);
3886 break;
3887 }
3888
3889 case PutByIdDirect: {
3890 SpeculateCellOperand base(this, node->child1());
3891 JSValueOperand value(this, node->child2());
3892 GPRTemporary scratch(this);
3893
3894 GPRReg baseGPR = base.gpr();
3895 GPRReg valueTagGPR = value.tagGPR();
3896 GPRReg valuePayloadGPR = value.payloadGPR();
3897 GPRReg scratchGPR = scratch.gpr();
3898
3899 cachedPutById(node->origin.semantic, baseGPR, valueTagGPR, valuePayloadGPR, scratchGPR, node->identifierNumber(), Direct);
3900
3901 noResult(node);
3902 break;
3903 }
3904
3905 case GetGlobalVar: {
3906 GPRTemporary resultPayload(this);
3907 GPRTemporary resultTag(this);
3908
3909 m_jit.move(TrustedImmPtr(node->registerPointer()), resultPayload.gpr());
3910 m_jit.load32(JITCompiler::Address(resultPayload.gpr(), OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTag.gpr());
3911 m_jit.load32(JITCompiler::Address(resultPayload.gpr(), OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayload.gpr());
3912
3913 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
3914 break;
3915 }
3916
3917 case PutGlobalVar: {
3918 JSValueOperand value(this, node->child1());
3919
3920 // FIXME: if we happen to have a spare register - and _ONLY_ if we happen to have
3921 // a spare register - a good optimization would be to put the register pointer into
3922 // a register and then do a zero offset store followed by a four-offset store (or
3923 // vice-versa depending on endianness).
3924 m_jit.store32(value.tagGPR(), node->registerPointer()->tagPointer());
3925 m_jit.store32(value.payloadGPR(), node->registerPointer()->payloadPointer());
3926
3927 noResult(node);
3928 break;
3929 }
3930
3931 case NotifyWrite: {
3932 VariableWatchpointSet* set = node->variableWatchpointSet();
3933
3934 JSValueOperand value(this, node->child1());
3935 GPRReg valueTagGPR = value.tagGPR();
3936 GPRReg valuePayloadGPR = value.payloadGPR();
3937
3938 GPRTemporary temp(this);
3939 GPRReg tempGPR = temp.gpr();
3940
3941 m_jit.load8(set->addressOfState(), tempGPR);
3942
3943 JITCompiler::Jump isDone = m_jit.branch32(JITCompiler::Equal, tempGPR, TrustedImm32(IsInvalidated));
3944 JITCompiler::JumpList notifySlow;
3945 notifySlow.append(m_jit.branch32(
3946 JITCompiler::NotEqual,
3947 JITCompiler::AbsoluteAddress(set->addressOfInferredValue()->payloadPointer()),
3948 valuePayloadGPR));
3949 notifySlow.append(m_jit.branch32(
3950 JITCompiler::NotEqual,
3951 JITCompiler::AbsoluteAddress(set->addressOfInferredValue()->tagPointer()),
3952 valueTagGPR));
3953 addSlowPathGenerator(
3954 slowPathCall(notifySlow, this, operationNotifyWrite, NoResult, set, valueTagGPR, valuePayloadGPR));
3955 isDone.link(&m_jit);
3956
3957 noResult(node);
3958 break;
3959 }
3960
3961 case VarInjectionWatchpoint:
3962 case VariableWatchpoint: {
3963 noResult(node);
3964 break;
3965 }
3966
3967 case CheckHasInstance: {
3968 SpeculateCellOperand base(this, node->child1());
3969 GPRTemporary structure(this);
3970
3971 // Speculate that base 'ImplementsDefaultHasInstance'.
3972 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branchTest8(
3973 MacroAssembler::Zero,
3974 MacroAssembler::Address(base.gpr(), JSCell::typeInfoFlagsOffset()),
3975 MacroAssembler::TrustedImm32(ImplementsDefaultHasInstance)));
3976
3977 noResult(node);
3978 break;
3979 }
3980
3981 case InstanceOf: {
3982 compileInstanceOf(node);
3983 break;
3984 }
3985
3986 case IsUndefined: {
3987 JSValueOperand value(this, node->child1());
3988 GPRTemporary result(this);
3989 GPRTemporary localGlobalObject(this);
3990 GPRTemporary remoteGlobalObject(this);
3991
3992 JITCompiler::Jump isCell = branchIsCell(value.jsValueRegs());
3993
3994 m_jit.compare32(JITCompiler::Equal, value.tagGPR(), TrustedImm32(JSValue::UndefinedTag), result.gpr());
3995 JITCompiler::Jump done = m_jit.jump();
3996
3997 isCell.link(&m_jit);
3998 JITCompiler::Jump notMasqueradesAsUndefined;
3999 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
4000 m_jit.move(TrustedImm32(0), result.gpr());
4001 notMasqueradesAsUndefined = m_jit.jump();
4002 } else {
4003 JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8(
4004 JITCompiler::NonZero,
4005 JITCompiler::Address(value.payloadGPR(), JSCell::typeInfoFlagsOffset()),
4006 TrustedImm32(MasqueradesAsUndefined));
4007 m_jit.move(TrustedImm32(0), result.gpr());
4008 notMasqueradesAsUndefined = m_jit.jump();
4009
4010 isMasqueradesAsUndefined.link(&m_jit);
4011 GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
4012 GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
4013 m_jit.move(TrustedImmPtr(m_jit.globalObjectFor(node->origin.semantic)), localGlobalObjectGPR);
4014 m_jit.loadPtr(JITCompiler::Address(value.payloadGPR(), JSCell::structureIDOffset()), result.gpr());
4015 m_jit.loadPtr(JITCompiler::Address(result.gpr(), Structure::globalObjectOffset()), remoteGlobalObjectGPR);
4016 m_jit.compare32(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, result.gpr());
4017 }
4018
4019 notMasqueradesAsUndefined.link(&m_jit);
4020 done.link(&m_jit);
4021 booleanResult(result.gpr(), node);
4022 break;
4023 }
4024
4025 case IsBoolean: {
4026 JSValueOperand value(this, node->child1());
4027 GPRTemporary result(this, Reuse, value, TagWord);
4028
4029 m_jit.compare32(JITCompiler::Equal, value.tagGPR(), JITCompiler::TrustedImm32(JSValue::BooleanTag), result.gpr());
4030 booleanResult(result.gpr(), node);
4031 break;
4032 }
4033
4034 case IsNumber: {
4035 JSValueOperand value(this, node->child1());
4036 GPRTemporary result(this, Reuse, value, TagWord);
4037
4038 m_jit.add32(TrustedImm32(1), value.tagGPR(), result.gpr());
4039 m_jit.compare32(JITCompiler::Below, result.gpr(), JITCompiler::TrustedImm32(JSValue::LowestTag + 1), result.gpr());
4040 booleanResult(result.gpr(), node);
4041 break;
4042 }
4043
4044 case IsString: {
4045 JSValueOperand value(this, node->child1());
4046 GPRTemporary result(this, Reuse, value, TagWord);
4047
4048 JITCompiler::Jump isNotCell = branchNotCell(value.jsValueRegs());
4049
4050 m_jit.compare8(JITCompiler::Equal,
4051 JITCompiler::Address(value.payloadGPR(), JSCell::typeInfoTypeOffset()),
4052 TrustedImm32(StringType),
4053 result.gpr());
4054 JITCompiler::Jump done = m_jit.jump();
4055
4056 isNotCell.link(&m_jit);
4057 m_jit.move(TrustedImm32(0), result.gpr());
4058
4059 done.link(&m_jit);
4060 booleanResult(result.gpr(), node);
4061 break;
4062 }
4063
4064 case IsObject: {
4065 JSValueOperand value(this, node->child1());
4066 GPRReg valueTagGPR = value.tagGPR();
4067 GPRReg valuePayloadGPR = value.payloadGPR();
4068 GPRResult result(this);
4069 GPRReg resultGPR = result.gpr();
4070 flushRegisters();
4071 callOperation(operationIsObject, resultGPR, valueTagGPR, valuePayloadGPR);
4072 booleanResult(result.gpr(), node);
4073 break;
4074 }
4075
4076 case IsFunction: {
4077 JSValueOperand value(this, node->child1());
4078 GPRReg valueTagGPR = value.tagGPR();
4079 GPRReg valuePayloadGPR = value.payloadGPR();
4080 GPRResult result(this);
4081 GPRReg resultGPR = result.gpr();
4082 flushRegisters();
4083 callOperation(operationIsFunction, resultGPR, valueTagGPR, valuePayloadGPR);
4084 booleanResult(result.gpr(), node);
4085 break;
4086 }
4087 case TypeOf: {
4088 JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
4089 GPRReg tagGPR = value.tagGPR();
4090 GPRReg payloadGPR = value.payloadGPR();
4091 GPRTemporary temp(this);
4092 GPRReg tempGPR = temp.gpr();
4093 GPRResult result(this);
4094 GPRReg resultGPR = result.gpr();
4095 JITCompiler::JumpList doneJumps;
4096
4097 flushRegisters();
4098
4099 ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == CellUse || node->child1().useKind() == StringUse);
4100
4101 JITCompiler::Jump isNotCell = branchNotCell(value.jsValueRegs());
4102 if (node->child1().useKind() != UntypedUse)
4103 DFG_TYPE_CHECK(JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecCell, isNotCell);
4104
4105 if (!node->child1()->shouldSpeculateObject() || node->child1().useKind() == StringUse) {
4106 JITCompiler::Jump notString = m_jit.branch8(
4107 JITCompiler::NotEqual,
4108 JITCompiler::Address(payloadGPR, JSCell::typeInfoTypeOffset()),
4109 TrustedImm32(StringType));
4110 if (node->child1().useKind() == StringUse)
4111 DFG_TYPE_CHECK(JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecString, notString);
4112 m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.stringString()), resultGPR);
4113 doneJumps.append(m_jit.jump());
4114 if (node->child1().useKind() != StringUse) {
4115 notString.link(&m_jit);
4116 callOperation(operationTypeOf, resultGPR, payloadGPR);
4117 doneJumps.append(m_jit.jump());
4118 }
4119 } else {
4120 callOperation(operationTypeOf, resultGPR, payloadGPR);
4121 doneJumps.append(m_jit.jump());
4122 }
4123
4124 if (node->child1().useKind() == UntypedUse) {
4125 isNotCell.link(&m_jit);
4126
4127 m_jit.add32(TrustedImm32(1), tagGPR, tempGPR);
4128 JITCompiler::Jump notNumber = m_jit.branch32(JITCompiler::AboveOrEqual, tempGPR, JITCompiler::TrustedImm32(JSValue::LowestTag + 1));
4129 m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.numberString()), resultGPR);
4130 doneJumps.append(m_jit.jump());
4131 notNumber.link(&m_jit);
4132
4133 JITCompiler::Jump notUndefined = m_jit.branch32(JITCompiler::NotEqual, tagGPR, TrustedImm32(JSValue::UndefinedTag));
4134 m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.undefinedString()), resultGPR);
4135 doneJumps.append(m_jit.jump());
4136 notUndefined.link(&m_jit);
4137
4138 JITCompiler::Jump notNull = m_jit.branch32(JITCompiler::NotEqual, tagGPR, TrustedImm32(JSValue::NullTag));
4139 m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.objectString()), resultGPR);
4140 doneJumps.append(m_jit.jump());
4141 notNull.link(&m_jit);
4142
4143 // Only boolean left
4144 m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.booleanString()), resultGPR);
4145 }
4146 doneJumps.link(&m_jit);
4147 cellResult(resultGPR, node);
4148 break;
4149 }
4150
4151 case Flush:
4152 break;
4153
4154 case Call:
4155 case Construct:
4156 emitCall(node);
4157 break;
4158
4159 case CreateActivation: {
4160 JSValueOperand value(this, node->child1());
4161 GPRTemporary result(this, Reuse, value, PayloadWord);
4162
4163 GPRReg valueTagGPR = value.tagGPR();
4164 GPRReg valuePayloadGPR = value.payloadGPR();
4165 GPRReg resultGPR = result.gpr();
4166
4167 m_jit.move(valuePayloadGPR, resultGPR);
4168
4169 JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
4170
4171 addSlowPathGenerator(
4172 slowPathCall(
4173 notCreated, this, operationCreateActivation, resultGPR,
4174 framePointerOffsetToGetActivationRegisters()));
4175
4176 cellResult(resultGPR, node);
4177 break;
4178 }
4179
4180 case FunctionReentryWatchpoint: {
4181 noResult(node);
4182 break;
4183 }
4184
4185 case CreateArguments: {
4186 JSValueOperand value(this, node->child1());
4187 GPRTemporary scratch1(this);
4188 GPRTemporary scratch2(this);
4189 GPRTemporary result(this, Reuse, value, PayloadWord);
4190
4191 GPRReg valueTagGPR = value.tagGPR();
4192 GPRReg valuePayloadGPR = value.payloadGPR();
4193 GPRReg scratch1GPR = scratch1.gpr();
4194 GPRReg scratch2GPR = scratch2.gpr();
4195 GPRReg resultGPR = result.gpr();
4196
4197 m_jit.move(valuePayloadGPR, resultGPR);
4198
4199 if (node->origin.semantic.inlineCallFrame) {
4200 JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
4201 addSlowPathGenerator(
4202 slowPathCall(
4203 notCreated, this, operationCreateInlinedArguments, resultGPR,
4204 node->origin.semantic.inlineCallFrame));
4205 cellResult(resultGPR, node);
4206 break;
4207 }
4208
4209 FunctionExecutable* executable = jsCast<FunctionExecutable*>(m_jit.graph().executableFor(node->origin.semantic));
4210 if (m_jit.codeBlock()->hasSlowArguments()
4211 || executable->isStrictMode()
4212 || !executable->parameterCount()) {
4213 JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
4214 addSlowPathGenerator(
4215 slowPathCall(notCreated, this, operationCreateArguments, resultGPR));
4216 cellResult(resultGPR, node);
4217 break;
4218 }
4219
4220 JITCompiler::Jump alreadyCreated = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
4221
4222 MacroAssembler::JumpList slowPaths;
4223 emitAllocateArguments(resultGPR, scratch1GPR, scratch2GPR, slowPaths);
4224 addSlowPathGenerator(
4225 slowPathCall(slowPaths, this, operationCreateArguments, resultGPR));
4226
4227 alreadyCreated.link(&m_jit);
4228 cellResult(resultGPR, node);
4229 break;
4230 }
4231
4232 case TearOffActivation: {
4233 JSValueOperand activationValue(this, node->child1());
4234 GPRTemporary scratch(this);
4235
4236 GPRReg activationValueTagGPR = activationValue.tagGPR();
4237 GPRReg activationValuePayloadGPR = activationValue.payloadGPR();
4238 GPRReg scratchGPR = scratch.gpr();
4239
4240 JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, activationValueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
4241
4242 SymbolTable* symbolTable = m_jit.symbolTableFor(node->origin.semantic);
4243 int registersOffset = JSActivation::registersOffset(symbolTable);
4244
4245 int bytecodeCaptureStart = symbolTable->captureStart();
4246 int machineCaptureStart = m_jit.graph().m_machineCaptureStart;
4247 for (int i = symbolTable->captureCount(); i--;) {
4248 m_jit.loadPtr(
4249 JITCompiler::Address(
4250 GPRInfo::callFrameRegister, (machineCaptureStart - i) * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
4251 scratchGPR);
4252 m_jit.storePtr(
4253 scratchGPR, JITCompiler::Address(
4254 activationValuePayloadGPR, registersOffset + (bytecodeCaptureStart - i) * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
4255 m_jit.loadPtr(
4256 JITCompiler::Address(
4257 GPRInfo::callFrameRegister, (machineCaptureStart - i) * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
4258 scratchGPR);
4259 m_jit.storePtr(
4260 scratchGPR, JITCompiler::Address(
4261 activationValuePayloadGPR, registersOffset + (bytecodeCaptureStart - i) * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
4262 }
4263 m_jit.addPtr(TrustedImm32(registersOffset), activationValuePayloadGPR, scratchGPR);
4264 m_jit.storePtr(scratchGPR, JITCompiler::Address(activationValuePayloadGPR, JSActivation::offsetOfRegisters()));
4265
4266 notCreated.link(&m_jit);
4267 noResult(node);
4268 break;
4269 }
4270
4271 case TearOffArguments: {
4272 JSValueOperand unmodifiedArgumentsValue(this, node->child1());
4273 JSValueOperand activationValue(this, node->child2());
4274 GPRReg unmodifiedArgumentsValuePayloadGPR = unmodifiedArgumentsValue.payloadGPR();
4275 GPRReg activationValuePayloadGPR = activationValue.payloadGPR();
4276
4277 JITCompiler::Jump created = m_jit.branchTest32(
4278 JITCompiler::NonZero, unmodifiedArgumentsValuePayloadGPR);
4279
4280 if (node->origin.semantic.inlineCallFrame) {
4281 addSlowPathGenerator(
4282 slowPathCall(
4283 created, this, operationTearOffInlinedArguments, NoResult,
4284 unmodifiedArgumentsValuePayloadGPR, activationValuePayloadGPR, node->origin.semantic.inlineCallFrame));
4285 } else {
4286 addSlowPathGenerator(
4287 slowPathCall(
4288 created, this, operationTearOffArguments, NoResult,
4289 unmodifiedArgumentsValuePayloadGPR, activationValuePayloadGPR));
4290 }
4291
4292 noResult(node);
4293 break;
4294 }
4295
4296 case CheckArgumentsNotCreated: {
4297 ASSERT(!isEmptySpeculation(
4298 m_state.variables().operand(
4299 m_jit.graph().argumentsRegisterFor(node->origin.semantic)).m_type));
4300 speculationCheck(
4301 Uncountable, JSValueRegs(), 0,
4302 m_jit.branch32(
4303 JITCompiler::NotEqual,
4304 JITCompiler::tagFor(m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)),
4305 TrustedImm32(JSValue::EmptyValueTag)));
4306 noResult(node);
4307 break;
4308 }
4309
4310 case GetMyArgumentsLength: {
4311 GPRTemporary result(this);
4312 GPRReg resultGPR = result.gpr();
4313
4314 if (!isEmptySpeculation(
4315 m_state.variables().operand(
4316 m_jit.graph().argumentsRegisterFor(node->origin.semantic)).m_type)) {
4317 speculationCheck(
4318 ArgumentsEscaped, JSValueRegs(), 0,
4319 m_jit.branch32(
4320 JITCompiler::NotEqual,
4321 JITCompiler::tagFor(m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)),
4322 TrustedImm32(JSValue::EmptyValueTag)));
4323 }
4324
4325 ASSERT(!node->origin.semantic.inlineCallFrame);
4326 m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), resultGPR);
4327 m_jit.sub32(TrustedImm32(1), resultGPR);
4328 int32Result(resultGPR, node);
4329 break;
4330 }
4331
4332 case GetMyArgumentsLengthSafe: {
4333 GPRTemporary resultPayload(this);
4334 GPRTemporary resultTag(this);
4335 GPRReg resultPayloadGPR = resultPayload.gpr();
4336 GPRReg resultTagGPR = resultTag.gpr();
4337
4338 JITCompiler::Jump created = m_jit.branch32(
4339 JITCompiler::NotEqual,
4340 JITCompiler::tagFor(m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)),
4341 TrustedImm32(JSValue::EmptyValueTag));
4342
4343 if (node->origin.semantic.inlineCallFrame) {
4344 m_jit.move(
4345 Imm32(node->origin.semantic.inlineCallFrame->arguments.size() - 1),
4346 resultPayloadGPR);
4347 } else {
4348 m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), resultPayloadGPR);
4349 m_jit.sub32(TrustedImm32(1), resultPayloadGPR);
4350 }
4351 m_jit.move(TrustedImm32(JSValue::Int32Tag), resultTagGPR);
4352
4353 // FIXME: the slow path generator should perform a forward speculation that the
4354 // result is an integer. For now we postpone the speculation by having this return
4355 // a JSValue.
4356
4357 addSlowPathGenerator(
4358 slowPathCall(
4359 created, this, operationGetArgumentsLength,
4360 JSValueRegs(resultTagGPR, resultPayloadGPR),
4361 m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic).offset()));
4362
4363 jsValueResult(resultTagGPR, resultPayloadGPR, node);
4364 break;
4365 }
4366
4367 case GetMyArgumentByVal: {
4368 SpeculateStrictInt32Operand index(this, node->child1());
4369 GPRTemporary resultPayload(this);
4370 GPRTemporary resultTag(this);
4371 GPRReg indexGPR = index.gpr();
4372 GPRReg resultPayloadGPR = resultPayload.gpr();
4373 GPRReg resultTagGPR = resultTag.gpr();
4374
4375 if (!isEmptySpeculation(
4376 m_state.variables().operand(
4377 m_jit.graph().argumentsRegisterFor(node->origin.semantic)).m_type)) {
4378 speculationCheck(
4379 ArgumentsEscaped, JSValueRegs(), 0,
4380 m_jit.branch32(
4381 JITCompiler::NotEqual,
4382 JITCompiler::tagFor(m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)),
4383 TrustedImm32(JSValue::EmptyValueTag)));
4384 }
4385
4386 m_jit.add32(TrustedImm32(1), indexGPR, resultPayloadGPR);
4387
4388 if (node->origin.semantic.inlineCallFrame) {
4389 speculationCheck(
4390 Uncountable, JSValueRegs(), 0,
4391 m_jit.branch32(
4392 JITCompiler::AboveOrEqual,
4393 resultPayloadGPR,
4394 Imm32(node->origin.semantic.inlineCallFrame->arguments.size())));
4395 } else {
4396 speculationCheck(
4397 Uncountable, JSValueRegs(), 0,
4398 m_jit.branch32(
4399 JITCompiler::AboveOrEqual,
4400 resultPayloadGPR,
4401 JITCompiler::payloadFor(JSStack::ArgumentCount)));
4402 }
4403
4404 JITCompiler::JumpList slowArgument;
4405 JITCompiler::JumpList slowArgumentOutOfBounds;
4406 if (m_jit.symbolTableFor(node->origin.semantic)->slowArguments()) {
4407 RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame);
4408 const SlowArgument* slowArguments = m_jit.graph().m_slowArguments.get();
4409 slowArgumentOutOfBounds.append(
4410 m_jit.branch32(
4411 JITCompiler::AboveOrEqual, indexGPR,
4412 Imm32(m_jit.symbolTableFor(node->origin.semantic)->parameterCount())));
4413
4414 COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes);
4415 m_jit.move(ImmPtr(slowArguments), resultPayloadGPR);
4416 m_jit.load32(
4417 JITCompiler::BaseIndex(
4418 resultPayloadGPR, indexGPR, JITCompiler::TimesEight,
4419 OBJECT_OFFSETOF(SlowArgument, index)),
4420 resultPayloadGPR);
4421
4422 m_jit.load32(
4423 JITCompiler::BaseIndex(
4424 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
4425 OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
4426 resultTagGPR);
4427 m_jit.load32(
4428 JITCompiler::BaseIndex(
4429 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
4430 OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
4431 resultPayloadGPR);
4432 slowArgument.append(m_jit.jump());
4433 }
4434 slowArgumentOutOfBounds.link(&m_jit);
4435
4436 m_jit.load32(
4437 JITCompiler::BaseIndex(
4438 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
4439 m_jit.offsetOfArgumentsIncludingThis(node->origin.semantic) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
4440 resultTagGPR);
4441 m_jit.load32(
4442 JITCompiler::BaseIndex(
4443 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
4444 m_jit.offsetOfArgumentsIncludingThis(node->origin.semantic) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
4445 resultPayloadGPR);
4446
4447 slowArgument.link(&m_jit);
4448 jsValueResult(resultTagGPR, resultPayloadGPR, node);
4449 break;
4450 }
4451 case GetMyArgumentByValSafe: {
4452 SpeculateStrictInt32Operand index(this, node->child1());
4453 GPRTemporary resultPayload(this);
4454 GPRTemporary resultTag(this);
4455 GPRReg indexGPR = index.gpr();
4456 GPRReg resultPayloadGPR = resultPayload.gpr();
4457 GPRReg resultTagGPR = resultTag.gpr();
4458
4459 JITCompiler::JumpList slowPath;
4460 slowPath.append(
4461 m_jit.branch32(
4462 JITCompiler::NotEqual,
4463 JITCompiler::tagFor(m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)),
4464 TrustedImm32(JSValue::EmptyValueTag)));
4465
4466 m_jit.add32(TrustedImm32(1), indexGPR, resultPayloadGPR);
4467 if (node->origin.semantic.inlineCallFrame) {
4468 slowPath.append(
4469 m_jit.branch32(
4470 JITCompiler::AboveOrEqual,
4471 resultPayloadGPR,
4472 Imm32(node->origin.semantic.inlineCallFrame->arguments.size())));
4473 } else {
4474 slowPath.append(
4475 m_jit.branch32(
4476 JITCompiler::AboveOrEqual,
4477 resultPayloadGPR,
4478 JITCompiler::payloadFor(JSStack::ArgumentCount)));
4479 }
4480
4481 JITCompiler::JumpList slowArgument;
4482 JITCompiler::JumpList slowArgumentOutOfBounds;
4483 if (m_jit.symbolTableFor(node->origin.semantic)->slowArguments()) {
4484 RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame);
4485 const SlowArgument* slowArguments = m_jit.graph().m_slowArguments.get();
4486 slowArgumentOutOfBounds.append(
4487 m_jit.branch32(
4488 JITCompiler::AboveOrEqual, indexGPR,
4489 Imm32(m_jit.symbolTableFor(node->origin.semantic)->parameterCount())));
4490
4491 COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes);
4492 m_jit.move(ImmPtr(slowArguments), resultPayloadGPR);
4493 m_jit.load32(
4494 JITCompiler::BaseIndex(
4495 resultPayloadGPR, indexGPR, JITCompiler::TimesEight,
4496 OBJECT_OFFSETOF(SlowArgument, index)),
4497 resultPayloadGPR);
4498 m_jit.load32(
4499 JITCompiler::BaseIndex(
4500 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
4501 OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
4502 resultTagGPR);
4503 m_jit.load32(
4504 JITCompiler::BaseIndex(
4505 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
4506 OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
4507 resultPayloadGPR);
4508 slowArgument.append(m_jit.jump());
4509 }
4510 slowArgumentOutOfBounds.link(&m_jit);
4511
4512 m_jit.load32(
4513 JITCompiler::BaseIndex(
4514 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
4515 m_jit.offsetOfArgumentsIncludingThis(node->origin.semantic) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
4516 resultTagGPR);
4517 m_jit.load32(
4518 JITCompiler::BaseIndex(
4519 GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
4520 m_jit.offsetOfArgumentsIncludingThis(node->origin.semantic) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
4521 resultPayloadGPR);
4522
4523 if (node->origin.semantic.inlineCallFrame) {
4524 addSlowPathGenerator(
4525 slowPathCall(
4526 slowPath, this, operationGetInlinedArgumentByVal,
4527 JSValueRegs(resultTagGPR, resultPayloadGPR),
4528 m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic).offset(),
4529 node->origin.semantic.inlineCallFrame, indexGPR));
4530 } else {
4531 addSlowPathGenerator(
4532 slowPathCall(
4533 slowPath, this, operationGetArgumentByVal,
4534 JSValueRegs(resultTagGPR, resultPayloadGPR),
4535 m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic).offset(),
4536 indexGPR));
4537 }
4538
4539 slowArgument.link(&m_jit);
4540 jsValueResult(resultTagGPR, resultPayloadGPR, node);
4541 break;
4542 }
4543
4544 case NewFunctionNoCheck:
4545 compileNewFunctionNoCheck(node);
4546 break;
4547
4548 case NewFunction: {
4549 JSValueOperand value(this, node->child1());
4550 GPRTemporary resultTag(this, Reuse, value, TagWord);
4551 GPRTemporary resultPayload(this, Reuse, value, PayloadWord);
4552
4553 GPRReg valueTagGPR = value.tagGPR();
4554 GPRReg valuePayloadGPR = value.payloadGPR();
4555 GPRReg resultTagGPR = resultTag.gpr();
4556 GPRReg resultPayloadGPR = resultPayload.gpr();
4557
4558 m_jit.move(valuePayloadGPR, resultPayloadGPR);
4559 m_jit.move(valueTagGPR, resultTagGPR);
4560
4561 JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
4562
4563 addSlowPathGenerator(
4564 slowPathCall(
4565 notCreated, this, operationNewFunction, JSValueRegs(resultTagGPR, resultPayloadGPR),
4566 m_jit.codeBlock()->functionDecl(node->functionDeclIndex())));
4567
4568 jsValueResult(resultTagGPR, resultPayloadGPR, node);
4569 break;
4570 }
4571
4572 case NewFunctionExpression:
4573 compileNewFunctionExpression(node);
4574 break;
4575
4576 case In:
4577 compileIn(node);
4578 break;
4579
4580 case StoreBarrier:
4581 case StoreBarrierWithNullCheck: {
4582 compileStoreBarrier(node);
4583 break;
4584 }
4585
4586 case ForceOSRExit: {
4587 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
4588 break;
4589 }
4590
4591 case InvalidationPoint:
4592 emitInvalidationPoint(node);
4593 break;
4594
4595 case CheckWatchdogTimer:
4596 ASSERT(m_jit.vm()->watchdog);
4597 speculationCheck(
4598 WatchdogTimerFired, JSValueRegs(), 0,
4599 m_jit.branchTest8(
4600 JITCompiler::NonZero,
4601 JITCompiler::AbsoluteAddress(m_jit.vm()->watchdog->timerDidFireAddress())));
4602 break;
4603
4604 case CountExecution:
4605 m_jit.add64(TrustedImm32(1), MacroAssembler::AbsoluteAddress(node->executionCounter()->address()));
4606 break;
4607
4608 case Phantom:
4609 case HardPhantom:
4610 DFG_NODE_DO_TO_CHILDREN(m_jit.graph(), node, speculate);
4611 noResult(node);
4612 break;
4613
4614 case Breakpoint:
4615 case ProfileWillCall:
4616 case ProfileDidCall:
4617 case PhantomLocal:
4618 case LoopHint:
4619 // This is a no-op.
4620 noResult(node);
4621 break;
4622
4623 case Unreachable:
4624 RELEASE_ASSERT_NOT_REACHED();
4625 break;
4626
4627 case LastNodeType:
4628 case Phi:
4629 case Upsilon:
4630 case GetArgument:
4631 case ExtractOSREntryLocal:
4632 case CheckTierUpInLoop:
4633 case CheckTierUpAtReturn:
4634 case CheckTierUpAndOSREnter:
4635 case Int52Rep:
4636 case FiatInt52:
4637 case Int52Constant:
4638 case CheckInBounds:
4639 case ArithIMul:
4640 case MultiGetByOffset:
4641 case MultiPutByOffset:
4642 RELEASE_ASSERT_NOT_REACHED();
4643 break;
4644 }
4645
4646 if (!m_compileOkay)
4647 return;
4648
4649 if (node->hasResult() && node->mustGenerate())
4650 use(node);
4651 }
4652
4653 #if ENABLE(GGC)
4654 void SpeculativeJIT::writeBarrier(GPRReg ownerGPR, GPRReg valueTagGPR, Edge valueUse, GPRReg scratch1, GPRReg scratch2)
4655 {
4656 JITCompiler::Jump isNotCell;
4657 if (!isKnownCell(valueUse.node()))
4658 isNotCell = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, JITCompiler::TrustedImm32(JSValue::CellTag));
4659
4660 JITCompiler::Jump ownerNotMarkedOrAlreadyRemembered = m_jit.checkMarkByte(ownerGPR);
4661 storeToWriteBarrierBuffer(ownerGPR, scratch1, scratch2);
4662 ownerNotMarkedOrAlreadyRemembered.link(&m_jit);
4663
4664 if (!isKnownCell(valueUse.node()))
4665 isNotCell.link(&m_jit);
4666 }
4667
4668 void SpeculativeJIT::writeBarrier(JSCell* owner, GPRReg valueTagGPR, Edge valueUse, GPRReg scratch1, GPRReg scratch2)
4669 {
4670 JITCompiler::Jump isNotCell;
4671 if (!isKnownCell(valueUse.node()))
4672 isNotCell = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, JITCompiler::TrustedImm32(JSValue::CellTag));
4673
4674 JITCompiler::Jump ownerNotMarkedOrAlreadyRemembered = m_jit.checkMarkByte(owner);
4675 storeToWriteBarrierBuffer(owner, scratch1, scratch2);
4676 ownerNotMarkedOrAlreadyRemembered.link(&m_jit);
4677
4678 if (!isKnownCell(valueUse.node()))
4679 isNotCell.link(&m_jit);
4680 }
4681 #endif // ENABLE(GGC)
4682
4683 JITCompiler::Jump SpeculativeJIT::branchIsCell(JSValueRegs regs)
4684 {
4685 return m_jit.branch32(MacroAssembler::Equal, regs.tagGPR(), TrustedImm32(JSValue::CellTag));
4686 }
4687
4688 JITCompiler::Jump SpeculativeJIT::branchNotCell(JSValueRegs regs)
4689 {
4690 return m_jit.branch32(MacroAssembler::NotEqual, regs.tagGPR(), TrustedImm32(JSValue::CellTag));
4691 }
4692
4693 JITCompiler::Jump SpeculativeJIT::branchIsOther(JSValueRegs regs, GPRReg tempGPR)
4694 {
4695 m_jit.move(regs.tagGPR(), tempGPR);
4696 m_jit.or32(TrustedImm32(1), tempGPR);
4697 return m_jit.branch32(
4698 MacroAssembler::Equal, tempGPR,
4699 MacroAssembler::TrustedImm32(JSValue::NullTag));
4700 }
4701
4702 JITCompiler::Jump SpeculativeJIT::branchNotOther(JSValueRegs regs, GPRReg tempGPR)
4703 {
4704 m_jit.move(regs.tagGPR(), tempGPR);
4705 m_jit.or32(TrustedImm32(1), tempGPR);
4706 return m_jit.branch32(
4707 MacroAssembler::NotEqual, tempGPR,
4708 MacroAssembler::TrustedImm32(JSValue::NullTag));
4709 }
4710
4711 void SpeculativeJIT::moveTrueTo(GPRReg gpr)
4712 {
4713 m_jit.move(TrustedImm32(1), gpr);
4714 }
4715
4716 void SpeculativeJIT::moveFalseTo(GPRReg gpr)
4717 {
4718 m_jit.move(TrustedImm32(0), gpr);
4719 }
4720
4721 void SpeculativeJIT::blessBoolean(GPRReg)
4722 {
4723 }
4724
4725 #endif
4726
4727 } } // namespace JSC::DFG
4728
4729 #endif