2 * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved.
3 * Copyright (C) 2011 Intel Corporation. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
28 #include "DFGSpeculativeJIT.h"
32 #include "ArrayPrototype.h"
33 #include "DFGAbstractInterpreterInlines.h"
34 #include "DFGCallArrayAllocatorSlowPathGenerator.h"
35 #include "DFGOperations.h"
36 #include "DFGSlowPathGenerator.h"
38 #include "GetterSetter.h"
39 #include "JSLexicalEnvironment.h"
40 #include "JSPropertyNameEnumerator.h"
41 #include "ObjectPrototype.h"
42 #include "JSCInlines.h"
44 namespace JSC { namespace DFG {
48 bool SpeculativeJIT::fillJSValue(Edge edge, GPRReg& tagGPR, GPRReg& payloadGPR, FPRReg& fpr)
50 // FIXME: For double we could fill with a FPR.
53 VirtualRegister virtualRegister = edge->virtualRegister();
54 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
56 switch (info.registerFormat()) {
57 case DataFormatNone: {
59 if (edge->hasConstant()) {
61 payloadGPR = allocate();
62 JSValue value = edge->asJSValue();
63 m_jit.move(Imm32(value.tag()), tagGPR);
64 m_jit.move(Imm32(value.payload()), payloadGPR);
65 m_gprs.retain(tagGPR, virtualRegister, SpillOrderConstant);
66 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderConstant);
67 info.fillJSValue(*m_stream, tagGPR, payloadGPR, DataFormatJS);
69 DataFormat spillFormat = info.spillFormat();
70 ASSERT(spillFormat != DataFormatNone && spillFormat != DataFormatStorage);
72 payloadGPR = allocate();
73 switch (spillFormat) {
75 m_jit.move(TrustedImm32(JSValue::Int32Tag), tagGPR);
76 spillFormat = DataFormatJSInt32; // This will be used as the new register format.
79 m_jit.move(TrustedImm32(JSValue::CellTag), tagGPR);
80 spillFormat = DataFormatJSCell; // This will be used as the new register format.
82 case DataFormatBoolean:
83 m_jit.move(TrustedImm32(JSValue::BooleanTag), tagGPR);
84 spillFormat = DataFormatJSBoolean; // This will be used as the new register format.
87 m_jit.load32(JITCompiler::tagFor(virtualRegister), tagGPR);
90 m_jit.load32(JITCompiler::payloadFor(virtualRegister), payloadGPR);
91 m_gprs.retain(tagGPR, virtualRegister, SpillOrderSpilled);
92 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderSpilled);
93 info.fillJSValue(*m_stream, tagGPR, payloadGPR, spillFormat == DataFormatJSDouble ? DataFormatJS : spillFormat);
101 case DataFormatBoolean: {
102 GPRReg gpr = info.gpr();
103 // If the register has already been locked we need to take a copy.
104 if (m_gprs.isLocked(gpr)) {
105 payloadGPR = allocate();
106 m_jit.move(gpr, payloadGPR);
112 uint32_t tag = JSValue::EmptyValueTag;
113 DataFormat fillFormat = DataFormatJS;
114 switch (info.registerFormat()) {
115 case DataFormatInt32:
116 tag = JSValue::Int32Tag;
117 fillFormat = DataFormatJSInt32;
120 tag = JSValue::CellTag;
121 fillFormat = DataFormatJSCell;
123 case DataFormatBoolean:
124 tag = JSValue::BooleanTag;
125 fillFormat = DataFormatJSBoolean;
128 RELEASE_ASSERT_NOT_REACHED();
131 m_jit.move(TrustedImm32(tag), tagGPR);
133 m_gprs.retain(tagGPR, virtualRegister, SpillOrderJS);
134 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderJS);
135 info.fillJSValue(*m_stream, tagGPR, payloadGPR, fillFormat);
139 case DataFormatJSDouble:
141 case DataFormatJSInt32:
142 case DataFormatJSCell:
143 case DataFormatJSBoolean: {
144 tagGPR = info.tagGPR();
145 payloadGPR = info.payloadGPR();
147 m_gprs.lock(payloadGPR);
151 case DataFormatStorage:
152 case DataFormatDouble:
153 // this type currently never occurs
154 RELEASE_ASSERT_NOT_REACHED();
157 RELEASE_ASSERT_NOT_REACHED();
162 void SpeculativeJIT::cachedGetById(
163 CodeOrigin codeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR,
164 unsigned identifierNumber, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
166 // This is a hacky fix for when the register allocator decides to alias the base payload with the result tag. This only happens
167 // in the case of GetByIdFlush, which has a relatively expensive register allocation story already so we probably don't need to
168 // trip over one move instruction.
169 if (basePayloadGPR == resultTagGPR) {
170 RELEASE_ASSERT(basePayloadGPR != resultPayloadGPR);
172 if (baseTagGPROrNone == resultPayloadGPR) {
173 m_jit.swap(basePayloadGPR, baseTagGPROrNone);
174 baseTagGPROrNone = resultTagGPR;
176 m_jit.move(basePayloadGPR, resultPayloadGPR);
177 basePayloadGPR = resultPayloadGPR;
180 JITGetByIdGenerator gen(
181 m_jit.codeBlock(), codeOrigin, usedRegisters(),
182 JSValueRegs(baseTagGPROrNone, basePayloadGPR),
183 JSValueRegs(resultTagGPR, resultPayloadGPR), spillMode);
185 gen.generateFastPath(m_jit);
187 JITCompiler::JumpList slowCases;
188 if (slowPathTarget.isSet())
189 slowCases.append(slowPathTarget);
190 slowCases.append(gen.slowPathJump());
192 OwnPtr<SlowPathGenerator> slowPath;
193 if (baseTagGPROrNone == InvalidGPRReg) {
194 slowPath = slowPathCall(
195 slowCases, this, operationGetByIdOptimize,
196 JSValueRegs(resultTagGPR, resultPayloadGPR), gen.stubInfo(),
197 static_cast<int32_t>(JSValue::CellTag), basePayloadGPR,
198 identifierUID(identifierNumber));
200 slowPath = slowPathCall(
201 slowCases, this, operationGetByIdOptimize,
202 JSValueRegs(resultTagGPR, resultPayloadGPR), gen.stubInfo(), baseTagGPROrNone,
203 basePayloadGPR, identifierUID(identifierNumber));
206 m_jit.addGetById(gen, slowPath.get());
207 addSlowPathGenerator(slowPath.release());
210 void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
212 JITPutByIdGenerator gen(
213 m_jit.codeBlock(), codeOrigin, usedRegisters(),
214 JSValueRegs::payloadOnly(basePayloadGPR), JSValueRegs(valueTagGPR, valuePayloadGPR),
215 scratchGPR, spillMode, m_jit.ecmaModeFor(codeOrigin), putKind);
217 gen.generateFastPath(m_jit);
219 JITCompiler::JumpList slowCases;
220 if (slowPathTarget.isSet())
221 slowCases.append(slowPathTarget);
222 slowCases.append(gen.slowPathJump());
224 OwnPtr<SlowPathGenerator> slowPath = slowPathCall(
225 slowCases, this, gen.slowPathFunction(), NoResult, gen.stubInfo(), valueTagGPR,
226 valuePayloadGPR, basePayloadGPR, identifierUID(identifierNumber));
228 m_jit.addPutById(gen, slowPath.get());
229 addSlowPathGenerator(slowPath.release());
232 void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool invert)
234 JSValueOperand arg(this, operand);
235 GPRReg argTagGPR = arg.tagGPR();
236 GPRReg argPayloadGPR = arg.payloadGPR();
238 GPRTemporary resultPayload(this, Reuse, arg, PayloadWord);
239 GPRReg resultPayloadGPR = resultPayload.gpr();
241 JITCompiler::Jump notCell;
242 JITCompiler::Jump notMasqueradesAsUndefined;
243 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
244 if (!isKnownCell(operand.node()))
245 notCell = branchNotCell(arg.jsValueRegs());
247 m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR);
248 notMasqueradesAsUndefined = m_jit.jump();
250 GPRTemporary localGlobalObject(this);
251 GPRTemporary remoteGlobalObject(this);
253 if (!isKnownCell(operand.node()))
254 notCell = branchNotCell(arg.jsValueRegs());
256 JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8(
257 JITCompiler::NonZero,
258 JITCompiler::Address(argPayloadGPR, JSCell::typeInfoFlagsOffset()),
259 JITCompiler::TrustedImm32(MasqueradesAsUndefined));
261 m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR);
262 notMasqueradesAsUndefined = m_jit.jump();
264 isMasqueradesAsUndefined.link(&m_jit);
265 GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
266 GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
267 m_jit.move(JITCompiler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode->origin.semantic)), localGlobalObjectGPR);
268 m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureIDOffset()), resultPayloadGPR);
269 m_jit.loadPtr(JITCompiler::Address(resultPayloadGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
270 m_jit.compare32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, resultPayloadGPR);
273 if (!isKnownCell(operand.node())) {
274 JITCompiler::Jump done = m_jit.jump();
276 notCell.link(&m_jit);
277 // null or undefined?
278 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
279 m_jit.or32(TrustedImm32(1), argTagGPR, resultPayloadGPR);
280 m_jit.compare32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultPayloadGPR, TrustedImm32(JSValue::NullTag), resultPayloadGPR);
285 notMasqueradesAsUndefined.link(&m_jit);
287 booleanResult(resultPayloadGPR, m_currentNode);
290 void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branchNode, bool invert)
292 BasicBlock* taken = branchNode->branchData()->taken.block;
293 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
295 if (taken == nextBlock()) {
297 BasicBlock* tmp = taken;
302 JSValueOperand arg(this, operand);
303 GPRReg argTagGPR = arg.tagGPR();
304 GPRReg argPayloadGPR = arg.payloadGPR();
306 GPRTemporary result(this, Reuse, arg, TagWord);
307 GPRReg resultGPR = result.gpr();
309 JITCompiler::Jump notCell;
311 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
312 if (!isKnownCell(operand.node()))
313 notCell = branchNotCell(arg.jsValueRegs());
315 jump(invert ? taken : notTaken, ForceJump);
317 GPRTemporary localGlobalObject(this);
318 GPRTemporary remoteGlobalObject(this);
320 if (!isKnownCell(operand.node()))
321 notCell = branchNotCell(arg.jsValueRegs());
323 branchTest8(JITCompiler::Zero,
324 JITCompiler::Address(argPayloadGPR, JSCell::typeInfoFlagsOffset()),
325 JITCompiler::TrustedImm32(MasqueradesAsUndefined),
326 invert ? taken : notTaken);
328 GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
329 GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
330 m_jit.move(TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode->origin.semantic)), localGlobalObjectGPR);
331 m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureIDOffset()), resultGPR);
332 m_jit.loadPtr(JITCompiler::Address(resultGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
333 branchPtr(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, invert ? notTaken : taken);
336 if (!isKnownCell(operand.node())) {
337 jump(notTaken, ForceJump);
339 notCell.link(&m_jit);
340 // null or undefined?
341 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
342 m_jit.or32(TrustedImm32(1), argTagGPR, resultGPR);
343 branch32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultGPR, JITCompiler::TrustedImm32(JSValue::NullTag), taken);
349 bool SpeculativeJIT::nonSpeculativeCompareNull(Node* node, Edge operand, bool invert)
351 unsigned branchIndexInBlock = detectPeepHoleBranch();
352 if (branchIndexInBlock != UINT_MAX) {
353 Node* branchNode = m_block->at(branchIndexInBlock);
355 ASSERT(node->adjustedRefCount() == 1);
357 nonSpeculativePeepholeBranchNull(operand, branchNode, invert);
361 m_indexInBlock = branchIndexInBlock;
362 m_currentNode = branchNode;
367 nonSpeculativeNonPeepholeCompareNull(operand, invert);
372 void SpeculativeJIT::nonSpeculativePeepholeBranch(Node* node, Node* branchNode, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
374 BasicBlock* taken = branchNode->branchData()->taken.block;
375 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
377 JITCompiler::ResultCondition callResultCondition = JITCompiler::NonZero;
379 // The branch instruction will branch to the taken block.
380 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
381 if (taken == nextBlock()) {
382 cond = JITCompiler::invert(cond);
383 callResultCondition = JITCompiler::Zero;
384 BasicBlock* tmp = taken;
389 JSValueOperand arg1(this, node->child1());
390 JSValueOperand arg2(this, node->child2());
391 GPRReg arg1TagGPR = arg1.tagGPR();
392 GPRReg arg1PayloadGPR = arg1.payloadGPR();
393 GPRReg arg2TagGPR = arg2.tagGPR();
394 GPRReg arg2PayloadGPR = arg2.payloadGPR();
396 JITCompiler::JumpList slowPath;
398 if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) {
399 GPRResult result(this);
400 GPRReg resultGPR = result.gpr();
406 callOperation(helperFunction, resultGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
408 branchTest32(callResultCondition, resultGPR, taken);
410 GPRTemporary result(this);
411 GPRReg resultGPR = result.gpr();
416 if (!isKnownInteger(node->child1().node()))
417 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg1TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
418 if (!isKnownInteger(node->child2().node()))
419 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg2TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
421 branch32(cond, arg1PayloadGPR, arg2PayloadGPR, taken);
423 if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node())) {
424 jump(notTaken, ForceJump);
426 slowPath.link(&m_jit);
428 silentSpillAllRegisters(resultGPR);
429 callOperation(helperFunction, resultGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
430 silentFillAllRegisters(resultGPR);
432 branchTest32(callResultCondition, resultGPR, taken);
438 m_indexInBlock = m_block->size() - 1;
439 m_currentNode = branchNode;
442 template<typename JumpType>
443 class CompareAndBoxBooleanSlowPathGenerator
444 : public CallSlowPathGenerator<JumpType, S_JITOperation_EJJ, GPRReg> {
446 CompareAndBoxBooleanSlowPathGenerator(
447 JumpType from, SpeculativeJIT* jit,
448 S_JITOperation_EJJ function, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload,
449 GPRReg arg2Tag, GPRReg arg2Payload)
450 : CallSlowPathGenerator<JumpType, S_JITOperation_EJJ, GPRReg>(
451 from, jit, function, NeedToSpill, result)
453 , m_arg1Payload(arg1Payload)
455 , m_arg2Payload(arg2Payload)
460 virtual void generateInternal(SpeculativeJIT* jit)
465 this->m_function, this->m_result, m_arg1Tag, m_arg1Payload, m_arg2Tag,
467 jit->m_jit.and32(JITCompiler::TrustedImm32(1), this->m_result);
473 GPRReg m_arg1Payload;
475 GPRReg m_arg2Payload;
478 void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node* node, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
480 JSValueOperand arg1(this, node->child1());
481 JSValueOperand arg2(this, node->child2());
482 GPRReg arg1TagGPR = arg1.tagGPR();
483 GPRReg arg1PayloadGPR = arg1.payloadGPR();
484 GPRReg arg2TagGPR = arg2.tagGPR();
485 GPRReg arg2PayloadGPR = arg2.payloadGPR();
487 JITCompiler::JumpList slowPath;
489 if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) {
490 GPRResult result(this);
491 GPRReg resultPayloadGPR = result.gpr();
497 callOperation(helperFunction, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
499 booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
501 GPRTemporary resultPayload(this, Reuse, arg1, PayloadWord);
502 GPRReg resultPayloadGPR = resultPayload.gpr();
507 if (!isKnownInteger(node->child1().node()))
508 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg1TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
509 if (!isKnownInteger(node->child2().node()))
510 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg2TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
512 m_jit.compare32(cond, arg1PayloadGPR, arg2PayloadGPR, resultPayloadGPR);
514 if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node())) {
515 addSlowPathGenerator(adoptPtr(
516 new CompareAndBoxBooleanSlowPathGenerator<JITCompiler::JumpList>(
517 slowPath, this, helperFunction, resultPayloadGPR, arg1TagGPR,
518 arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR)));
521 booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
525 void SpeculativeJIT::nonSpeculativePeepholeStrictEq(Node* node, Node* branchNode, bool invert)
527 BasicBlock* taken = branchNode->branchData()->taken.block;
528 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
530 // The branch instruction will branch to the taken block.
531 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
532 if (taken == nextBlock()) {
534 BasicBlock* tmp = taken;
539 JSValueOperand arg1(this, node->child1());
540 JSValueOperand arg2(this, node->child2());
541 GPRReg arg1TagGPR = arg1.tagGPR();
542 GPRReg arg1PayloadGPR = arg1.payloadGPR();
543 GPRReg arg2TagGPR = arg2.tagGPR();
544 GPRReg arg2PayloadGPR = arg2.payloadGPR();
546 GPRTemporary resultPayload(this, Reuse, arg1, PayloadWord);
547 GPRReg resultPayloadGPR = resultPayload.gpr();
552 if (isKnownCell(node->child1().node()) && isKnownCell(node->child2().node())) {
553 // see if we get lucky: if the arguments are cells and they reference the same
554 // cell, then they must be strictly equal.
555 branchPtr(JITCompiler::Equal, arg1PayloadGPR, arg2PayloadGPR, invert ? notTaken : taken);
557 silentSpillAllRegisters(resultPayloadGPR);
558 callOperation(operationCompareStrictEqCell, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
559 silentFillAllRegisters(resultPayloadGPR);
561 branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, resultPayloadGPR, taken);
563 // FIXME: Add fast paths for twoCells, number etc.
565 silentSpillAllRegisters(resultPayloadGPR);
566 callOperation(operationCompareStrictEq, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
567 silentFillAllRegisters(resultPayloadGPR);
569 branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, resultPayloadGPR, taken);
575 void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node* node, bool invert)
577 JSValueOperand arg1(this, node->child1());
578 JSValueOperand arg2(this, node->child2());
579 GPRReg arg1TagGPR = arg1.tagGPR();
580 GPRReg arg1PayloadGPR = arg1.payloadGPR();
581 GPRReg arg2TagGPR = arg2.tagGPR();
582 GPRReg arg2PayloadGPR = arg2.payloadGPR();
584 GPRTemporary resultPayload(this, Reuse, arg1, PayloadWord);
585 GPRReg resultPayloadGPR = resultPayload.gpr();
590 if (isKnownCell(node->child1().node()) && isKnownCell(node->child2().node())) {
591 // see if we get lucky: if the arguments are cells and they reference the same
592 // cell, then they must be strictly equal.
593 // FIXME: this should flush registers instead of silent spill/fill.
594 JITCompiler::Jump notEqualCase = m_jit.branchPtr(JITCompiler::NotEqual, arg1PayloadGPR, arg2PayloadGPR);
596 m_jit.move(JITCompiler::TrustedImm32(!invert), resultPayloadGPR);
597 JITCompiler::Jump done = m_jit.jump();
599 notEqualCase.link(&m_jit);
601 silentSpillAllRegisters(resultPayloadGPR);
602 callOperation(operationCompareStrictEqCell, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
603 silentFillAllRegisters(resultPayloadGPR);
605 m_jit.andPtr(JITCompiler::TrustedImm32(1), resultPayloadGPR);
609 // FIXME: Add fast paths.
611 silentSpillAllRegisters(resultPayloadGPR);
612 callOperation(operationCompareStrictEq, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
613 silentFillAllRegisters(resultPayloadGPR);
615 m_jit.andPtr(JITCompiler::TrustedImm32(1), resultPayloadGPR);
618 booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
621 void SpeculativeJIT::compileMiscStrictEq(Node* node)
623 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
624 JSValueOperand op2(this, node->child2(), ManualOperandSpeculation);
625 GPRTemporary result(this);
627 if (node->child1().useKind() == MiscUse)
628 speculateMisc(node->child1(), op1.jsValueRegs());
629 if (node->child2().useKind() == MiscUse)
630 speculateMisc(node->child2(), op2.jsValueRegs());
632 m_jit.move(TrustedImm32(0), result.gpr());
633 JITCompiler::Jump notEqual = m_jit.branch32(JITCompiler::NotEqual, op1.tagGPR(), op2.tagGPR());
634 m_jit.compare32(JITCompiler::Equal, op1.payloadGPR(), op2.payloadGPR(), result.gpr());
635 notEqual.link(&m_jit);
636 booleanResult(result.gpr(), node);
639 void SpeculativeJIT::emitCall(Node* node)
641 bool isCall = node->op() == Call || node->op() == ProfiledCall;
643 ASSERT(node->op() == Construct || node->op() == ProfiledConstruct);
645 // For constructors, the this argument is not passed but we have to make space
647 int dummyThisArgument = isCall ? 0 : 1;
649 CallLinkInfo::CallType callType = isCall ? CallLinkInfo::Call : CallLinkInfo::Construct;
651 Edge calleeEdge = m_jit.graph().m_varArgChildren[node->firstChild()];
652 JSValueOperand callee(this, calleeEdge);
653 GPRReg calleeTagGPR = callee.tagGPR();
654 GPRReg calleePayloadGPR = callee.payloadGPR();
657 // The call instruction's first child is either the function (normal call) or the
658 // receiver (method call). subsequent children are the arguments.
659 int numPassedArgs = node->numChildren() - 1;
661 int numArgs = numPassedArgs + dummyThisArgument;
663 m_jit.store32(MacroAssembler::TrustedImm32(numArgs), calleeFramePayloadSlot(JSStack::ArgumentCount));
664 m_jit.store32(calleePayloadGPR, calleeFramePayloadSlot(JSStack::Callee));
665 m_jit.store32(calleeTagGPR, calleeFrameTagSlot(JSStack::Callee));
667 for (int i = 0; i < numPassedArgs; i++) {
668 Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
669 JSValueOperand arg(this, argEdge);
670 GPRReg argTagGPR = arg.tagGPR();
671 GPRReg argPayloadGPR = arg.payloadGPR();
674 m_jit.store32(argTagGPR, calleeArgumentTagSlot(i + dummyThisArgument));
675 m_jit.store32(argPayloadGPR, calleeArgumentPayloadSlot(i + dummyThisArgument));
680 GPRResult resultPayload(this);
681 GPRResult2 resultTag(this);
682 GPRReg resultPayloadGPR = resultPayload.gpr();
683 GPRReg resultTagGPR = resultTag.gpr();
685 JITCompiler::DataLabelPtr targetToCheck;
686 JITCompiler::JumpList slowPath;
688 m_jit.emitStoreCodeOrigin(node->origin.semantic);
690 CallLinkInfo* info = m_jit.codeBlock()->addCallLinkInfo();
692 if (node->op() == ProfiledCall || node->op() == ProfiledConstruct) {
693 m_jit.vm()->callEdgeLog->emitLogCode(
694 m_jit, info->callEdgeProfile, callee.jsValueRegs());
697 slowPath.append(branchNotCell(callee.jsValueRegs()));
698 slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
699 m_jit.loadPtr(MacroAssembler::Address(calleePayloadGPR, OBJECT_OFFSETOF(JSFunction, m_scope)), resultPayloadGPR);
700 m_jit.storePtr(resultPayloadGPR, calleeFramePayloadSlot(JSStack::ScopeChain));
701 m_jit.storePtr(MacroAssembler::TrustedImm32(JSValue::CellTag), calleeFrameTagSlot(JSStack::ScopeChain));
703 JITCompiler::Call fastCall = m_jit.nearCall();
705 JITCompiler::Jump done = m_jit.jump();
707 slowPath.link(&m_jit);
709 // Callee payload needs to be in regT0, tag in regT1
710 if (calleeTagGPR == GPRInfo::regT0) {
711 if (calleePayloadGPR == GPRInfo::regT1)
712 m_jit.swap(GPRInfo::regT1, GPRInfo::regT0);
714 m_jit.move(calleeTagGPR, GPRInfo::regT1);
715 m_jit.move(calleePayloadGPR, GPRInfo::regT0);
718 m_jit.move(calleePayloadGPR, GPRInfo::regT0);
719 m_jit.move(calleeTagGPR, GPRInfo::regT1);
721 m_jit.move(MacroAssembler::TrustedImmPtr(info), GPRInfo::regT2);
722 JITCompiler::Call slowCall = m_jit.nearCall();
726 m_jit.setupResults(resultPayloadGPR, resultTagGPR);
728 jsValueResult(resultTagGPR, resultPayloadGPR, node, DataFormatJS, UseChildrenCalledExplicitly);
730 info->callType = callType;
731 info->codeOrigin = node->origin.semantic;
732 info->calleeGPR = calleePayloadGPR;
733 m_jit.addJSCall(fastCall, slowCall, targetToCheck, info);
736 template<bool strict>
737 GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnFormat)
739 AbstractValue& value = m_state.forNode(edge);
740 SpeculatedType type = value.m_type;
741 ASSERT(edge.useKind() != KnownInt32Use || !(value.m_type & ~SpecInt32));
742 m_interpreter.filter(value, SpecInt32);
743 VirtualRegister virtualRegister = edge->virtualRegister();
744 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
746 if (edge->hasConstant() && !edge->isInt32Constant()) {
747 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
748 returnFormat = DataFormatInt32;
752 switch (info.registerFormat()) {
753 case DataFormatNone: {
754 if (edge->hasConstant()) {
755 ASSERT(edge->isInt32Constant());
756 GPRReg gpr = allocate();
757 m_jit.move(MacroAssembler::Imm32(edge->asInt32()), gpr);
758 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
759 info.fillInt32(*m_stream, gpr);
760 returnFormat = DataFormatInt32;
764 DataFormat spillFormat = info.spillFormat();
765 ASSERT_UNUSED(spillFormat, (spillFormat & DataFormatJS) || spillFormat == DataFormatInt32);
767 // If we know this was spilled as an integer we can fill without checking.
768 if (type & ~SpecInt32)
769 speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), edge, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)));
771 GPRReg gpr = allocate();
772 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
773 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
774 info.fillInt32(*m_stream, gpr);
775 returnFormat = DataFormatInt32;
779 case DataFormatJSInt32:
781 // Check the value is an integer.
782 GPRReg tagGPR = info.tagGPR();
783 GPRReg payloadGPR = info.payloadGPR();
785 m_gprs.lock(payloadGPR);
786 if (type & ~SpecInt32)
787 speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), edge, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::Int32Tag)));
788 m_gprs.unlock(tagGPR);
789 m_gprs.release(tagGPR);
790 m_gprs.release(payloadGPR);
791 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderInteger);
792 info.fillInt32(*m_stream, payloadGPR);
793 // If !strict we're done, return.
794 returnFormat = DataFormatInt32;
798 case DataFormatInt32: {
799 GPRReg gpr = info.gpr();
801 returnFormat = DataFormatInt32;
806 case DataFormatBoolean:
807 case DataFormatJSDouble:
808 case DataFormatJSCell:
809 case DataFormatJSBoolean:
810 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
811 returnFormat = DataFormatInt32;
814 case DataFormatDouble:
815 case DataFormatStorage:
817 RELEASE_ASSERT_NOT_REACHED();
818 return InvalidGPRReg;
822 GPRReg SpeculativeJIT::fillSpeculateInt32(Edge edge, DataFormat& returnFormat)
824 return fillSpeculateInt32Internal<false>(edge, returnFormat);
827 GPRReg SpeculativeJIT::fillSpeculateInt32Strict(Edge edge)
829 DataFormat mustBeDataFormatInt32;
830 GPRReg result = fillSpeculateInt32Internal<true>(edge, mustBeDataFormatInt32);
831 ASSERT(mustBeDataFormatInt32 == DataFormatInt32);
835 FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge)
837 ASSERT(isDouble(edge.useKind()));
838 ASSERT(edge->hasDoubleResult());
839 VirtualRegister virtualRegister = edge->virtualRegister();
840 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
842 if (info.registerFormat() == DataFormatNone) {
844 if (edge->hasConstant()) {
845 RELEASE_ASSERT(edge->isNumberConstant());
846 FPRReg fpr = fprAllocate();
847 m_jit.loadDouble(TrustedImmPtr(m_jit.addressOfDoubleConstant(edge.node())), fpr);
848 m_fprs.retain(fpr, virtualRegister, SpillOrderConstant);
849 info.fillDouble(*m_stream, fpr);
853 RELEASE_ASSERT(info.spillFormat() == DataFormatDouble);
854 FPRReg fpr = fprAllocate();
855 m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
856 m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
857 info.fillDouble(*m_stream, fpr);
861 RELEASE_ASSERT(info.registerFormat() == DataFormatDouble);
862 FPRReg fpr = info.fpr();
867 GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge)
869 AbstractValue& value = m_state.forNode(edge);
870 SpeculatedType type = value.m_type;
871 ASSERT((edge.useKind() != KnownCellUse && edge.useKind() != KnownStringUse) || !(value.m_type & ~SpecCell));
872 m_interpreter.filter(value, SpecCell);
873 VirtualRegister virtualRegister = edge->virtualRegister();
874 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
876 if (edge->hasConstant() && !edge->isCellConstant()) {
877 // Protect the silent spill/fill logic by failing early. If we "speculate" on
878 // the constant then the silent filler may think that we have a cell and a
879 // constant, so it will try to fill this as an cell constant. Bad things will
881 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
885 switch (info.registerFormat()) {
886 case DataFormatNone: {
887 if (info.spillFormat() == DataFormatInt32) {
888 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
892 if (edge->hasConstant()) {
893 JSValue jsValue = edge->asJSValue();
894 GPRReg gpr = allocate();
895 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
896 m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr);
897 info.fillCell(*m_stream, gpr);
901 ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatCell);
902 if (type & ~SpecCell) {
905 JSValueSource(JITCompiler::addressFor(virtualRegister)),
908 MacroAssembler::NotEqual,
909 JITCompiler::tagFor(virtualRegister),
910 TrustedImm32(JSValue::CellTag)));
912 GPRReg gpr = allocate();
913 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
914 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
915 info.fillCell(*m_stream, gpr);
919 case DataFormatCell: {
920 GPRReg gpr = info.gpr();
925 case DataFormatJSCell:
927 GPRReg tagGPR = info.tagGPR();
928 GPRReg payloadGPR = info.payloadGPR();
930 m_gprs.lock(payloadGPR);
931 if (type & ~SpecCell) {
933 BadType, JSValueRegs(tagGPR, payloadGPR), edge,
934 branchNotCell(info.jsValueRegs()));
936 m_gprs.unlock(tagGPR);
937 m_gprs.release(tagGPR);
938 m_gprs.release(payloadGPR);
939 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderCell);
940 info.fillCell(*m_stream, payloadGPR);
944 case DataFormatJSInt32:
945 case DataFormatInt32:
946 case DataFormatJSDouble:
947 case DataFormatJSBoolean:
948 case DataFormatBoolean:
949 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
952 case DataFormatDouble:
953 case DataFormatStorage:
954 RELEASE_ASSERT_NOT_REACHED();
957 RELEASE_ASSERT_NOT_REACHED();
958 return InvalidGPRReg;
962 GPRReg SpeculativeJIT::fillSpeculateBoolean(Edge edge)
964 AbstractValue& value = m_state.forNode(edge);
965 SpeculatedType type = value.m_type;
966 m_interpreter.filter(value, SpecBoolean);
967 VirtualRegister virtualRegister = edge->virtualRegister();
968 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
970 switch (info.registerFormat()) {
971 case DataFormatNone: {
972 if (info.spillFormat() == DataFormatInt32) {
973 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
977 if (edge->hasConstant()) {
978 JSValue jsValue = edge->asJSValue();
979 GPRReg gpr = allocate();
980 if (jsValue.isBoolean()) {
981 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
982 m_jit.move(MacroAssembler::TrustedImm32(jsValue.asBoolean()), gpr);
983 info.fillBoolean(*m_stream, gpr);
986 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
990 ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatBoolean);
992 if (type & ~SpecBoolean)
993 speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), edge, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)));
995 GPRReg gpr = allocate();
996 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
997 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
998 info.fillBoolean(*m_stream, gpr);
1002 case DataFormatBoolean: {
1003 GPRReg gpr = info.gpr();
1008 case DataFormatJSBoolean:
1009 case DataFormatJS: {
1010 GPRReg tagGPR = info.tagGPR();
1011 GPRReg payloadGPR = info.payloadGPR();
1012 m_gprs.lock(tagGPR);
1013 m_gprs.lock(payloadGPR);
1014 if (type & ~SpecBoolean)
1015 speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), edge, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::BooleanTag)));
1017 m_gprs.unlock(tagGPR);
1018 m_gprs.release(tagGPR);
1019 m_gprs.release(payloadGPR);
1020 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderBoolean);
1021 info.fillBoolean(*m_stream, payloadGPR);
1025 case DataFormatJSInt32:
1026 case DataFormatInt32:
1027 case DataFormatJSDouble:
1028 case DataFormatJSCell:
1029 case DataFormatCell:
1030 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
1033 case DataFormatDouble:
1034 case DataFormatStorage:
1035 RELEASE_ASSERT_NOT_REACHED();
1038 RELEASE_ASSERT_NOT_REACHED();
1039 return InvalidGPRReg;
1043 void SpeculativeJIT::compileBaseValueStoreBarrier(Edge& baseEdge, Edge& valueEdge)
1046 ASSERT(!isKnownNotCell(valueEdge.node()));
1048 SpeculateCellOperand base(this, baseEdge);
1049 JSValueOperand value(this, valueEdge);
1050 GPRTemporary scratch1(this);
1051 GPRTemporary scratch2(this);
1053 writeBarrier(base.gpr(), value.tagGPR(), valueEdge, scratch1.gpr(), scratch2.gpr());
1055 UNUSED_PARAM(baseEdge);
1056 UNUSED_PARAM(valueEdge);
1060 void SpeculativeJIT::compileObjectEquality(Node* node)
1062 SpeculateCellOperand op1(this, node->child1());
1063 SpeculateCellOperand op2(this, node->child2());
1064 GPRReg op1GPR = op1.gpr();
1065 GPRReg op2GPR = op2.gpr();
1067 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
1069 JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
1070 MacroAssembler::Equal,
1071 MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
1072 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1074 JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchPtr(
1075 MacroAssembler::Equal,
1076 MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()),
1077 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1080 JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
1081 MacroAssembler::Equal,
1082 MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
1083 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1084 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
1086 MacroAssembler::NonZero,
1087 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
1088 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1091 JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchPtr(
1092 MacroAssembler::Equal,
1093 MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()),
1094 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1095 speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
1097 MacroAssembler::NonZero,
1098 MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()),
1099 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1102 GPRTemporary resultPayload(this, Reuse, op2);
1103 GPRReg resultPayloadGPR = resultPayload.gpr();
1105 MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2GPR);
1106 m_jit.move(TrustedImm32(1), resultPayloadGPR);
1107 MacroAssembler::Jump done = m_jit.jump();
1108 falseCase.link(&m_jit);
1109 m_jit.move(TrustedImm32(0), resultPayloadGPR);
1112 booleanResult(resultPayloadGPR, node);
1115 void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild)
1117 SpeculateCellOperand op1(this, leftChild);
1118 JSValueOperand op2(this, rightChild, ManualOperandSpeculation);
1119 GPRTemporary result(this);
1121 GPRReg op1GPR = op1.gpr();
1122 GPRReg op2TagGPR = op2.tagGPR();
1123 GPRReg op2PayloadGPR = op2.payloadGPR();
1124 GPRReg resultGPR = result.gpr();
1126 bool masqueradesAsUndefinedWatchpointValid =
1127 masqueradesAsUndefinedWatchpointIsStillValid();
1129 if (masqueradesAsUndefinedWatchpointValid) {
1131 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
1132 MacroAssembler::Equal,
1133 MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
1134 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1137 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
1138 MacroAssembler::Equal,
1139 MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
1140 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1141 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
1143 MacroAssembler::NonZero,
1144 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
1145 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1149 // It seems that most of the time when programs do a == b where b may be either null/undefined
1150 // or an object, b is usually an object. Balance the branches to make that case fast.
1151 MacroAssembler::Jump rightNotCell = branchNotCell(op2.jsValueRegs());
1153 // We know that within this branch, rightChild must be a cell.
1154 if (masqueradesAsUndefinedWatchpointValid) {
1156 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
1158 MacroAssembler::Equal,
1159 MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()),
1160 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1163 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
1165 MacroAssembler::Equal,
1166 MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()),
1167 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1168 speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
1170 MacroAssembler::NonZero,
1171 MacroAssembler::Address(op2PayloadGPR, JSCell::typeInfoFlagsOffset()),
1172 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1175 // At this point we know that we can perform a straight-forward equality comparison on pointer
1176 // values because both left and right are pointers to objects that have no special equality
1178 MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2PayloadGPR);
1179 MacroAssembler::Jump trueCase = m_jit.jump();
1181 rightNotCell.link(&m_jit);
1183 // We know that within this branch, rightChild must not be a cell. Check if that is enough to
1184 // prove that it is either null or undefined.
1185 if (needsTypeCheck(rightChild, SpecCell | SpecOther)) {
1186 m_jit.or32(TrustedImm32(1), op2TagGPR, resultGPR);
1189 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, SpecCell | SpecOther,
1191 MacroAssembler::NotEqual, resultGPR,
1192 MacroAssembler::TrustedImm32(JSValue::NullTag)));
1195 falseCase.link(&m_jit);
1196 m_jit.move(TrustedImm32(0), resultGPR);
1197 MacroAssembler::Jump done = m_jit.jump();
1198 trueCase.link(&m_jit);
1199 m_jit.move(TrustedImm32(1), resultGPR);
1202 booleanResult(resultGPR, m_currentNode);
1205 void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild, Node* branchNode)
1207 BasicBlock* taken = branchNode->branchData()->taken.block;
1208 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1210 SpeculateCellOperand op1(this, leftChild);
1211 JSValueOperand op2(this, rightChild, ManualOperandSpeculation);
1212 GPRTemporary result(this);
1214 GPRReg op1GPR = op1.gpr();
1215 GPRReg op2TagGPR = op2.tagGPR();
1216 GPRReg op2PayloadGPR = op2.payloadGPR();
1217 GPRReg resultGPR = result.gpr();
1219 bool masqueradesAsUndefinedWatchpointValid =
1220 masqueradesAsUndefinedWatchpointIsStillValid();
1222 if (masqueradesAsUndefinedWatchpointValid) {
1224 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
1225 MacroAssembler::Equal,
1226 MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
1227 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1230 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
1231 MacroAssembler::Equal,
1232 MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
1233 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1234 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
1236 MacroAssembler::NonZero,
1237 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
1238 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1241 // It seems that most of the time when programs do a == b where b may be either null/undefined
1242 // or an object, b is usually an object. Balance the branches to make that case fast.
1243 MacroAssembler::Jump rightNotCell = branchNotCell(op2.jsValueRegs());
1245 // We know that within this branch, rightChild must be a cell.
1246 if (masqueradesAsUndefinedWatchpointValid) {
1248 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
1250 MacroAssembler::Equal,
1251 MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()),
1252 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1255 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
1257 MacroAssembler::Equal,
1258 MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()),
1259 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1260 speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
1262 MacroAssembler::NonZero,
1263 MacroAssembler::Address(op2PayloadGPR, JSCell::typeInfoFlagsOffset()),
1264 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1267 // At this point we know that we can perform a straight-forward equality comparison on pointer
1268 // values because both left and right are pointers to objects that have no special equality
1270 branch32(MacroAssembler::Equal, op1GPR, op2PayloadGPR, taken);
1272 // We know that within this branch, rightChild must not be a cell. Check if that is enough to
1273 // prove that it is either null or undefined.
1274 if (!needsTypeCheck(rightChild, SpecCell | SpecOther))
1275 rightNotCell.link(&m_jit);
1277 jump(notTaken, ForceJump);
1279 rightNotCell.link(&m_jit);
1280 m_jit.or32(TrustedImm32(1), op2TagGPR, resultGPR);
1283 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, SpecCell | SpecOther,
1285 MacroAssembler::NotEqual, resultGPR,
1286 MacroAssembler::TrustedImm32(JSValue::NullTag)));
1292 void SpeculativeJIT::compileInt32Compare(Node* node, MacroAssembler::RelationalCondition condition)
1294 SpeculateInt32Operand op1(this, node->child1());
1295 SpeculateInt32Operand op2(this, node->child2());
1296 GPRTemporary resultPayload(this);
1298 m_jit.compare32(condition, op1.gpr(), op2.gpr(), resultPayload.gpr());
1300 // If we add a DataFormatBool, we should use it here.
1301 booleanResult(resultPayload.gpr(), node);
1304 void SpeculativeJIT::compileDoubleCompare(Node* node, MacroAssembler::DoubleCondition condition)
1306 SpeculateDoubleOperand op1(this, node->child1());
1307 SpeculateDoubleOperand op2(this, node->child2());
1308 GPRTemporary resultPayload(this);
1310 m_jit.move(TrustedImm32(1), resultPayload.gpr());
1311 MacroAssembler::Jump trueCase = m_jit.branchDouble(condition, op1.fpr(), op2.fpr());
1312 m_jit.move(TrustedImm32(0), resultPayload.gpr());
1313 trueCase.link(&m_jit);
1315 booleanResult(resultPayload.gpr(), node);
1318 void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
1320 JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
1321 GPRTemporary resultPayload(this);
1322 GPRReg valueTagGPR = value.tagGPR();
1323 GPRReg valuePayloadGPR = value.payloadGPR();
1324 GPRReg resultPayloadGPR = resultPayload.gpr();
1325 GPRTemporary structure;
1326 GPRReg structureGPR = InvalidGPRReg;
1328 bool masqueradesAsUndefinedWatchpointValid =
1329 masqueradesAsUndefinedWatchpointIsStillValid();
1331 if (!masqueradesAsUndefinedWatchpointValid) {
1332 // The masquerades as undefined case will use the structure register, so allocate it here.
1333 // Do this at the top of the function to avoid branching around a register allocation.
1334 GPRTemporary realStructure(this);
1335 structure.adopt(realStructure);
1336 structureGPR = structure.gpr();
1339 MacroAssembler::Jump notCell = branchNotCell(value.jsValueRegs());
1340 if (masqueradesAsUndefinedWatchpointValid) {
1342 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
1344 MacroAssembler::Equal,
1345 MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()),
1346 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1348 m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), structureGPR);
1351 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
1353 MacroAssembler::Equal,
1355 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1357 MacroAssembler::Jump isNotMasqueradesAsUndefined =
1359 MacroAssembler::Zero,
1360 MacroAssembler::Address(valuePayloadGPR, JSCell::typeInfoFlagsOffset()),
1361 MacroAssembler::TrustedImm32(MasqueradesAsUndefined));
1363 speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
1365 MacroAssembler::Equal,
1366 MacroAssembler::Address(structureGPR, Structure::globalObjectOffset()),
1367 MacroAssembler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode->origin.semantic))));
1369 isNotMasqueradesAsUndefined.link(&m_jit);
1371 m_jit.move(TrustedImm32(0), resultPayloadGPR);
1372 MacroAssembler::Jump done = m_jit.jump();
1374 notCell.link(&m_jit);
1376 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
1377 if (needsTypeCheck(nodeUse, SpecCell | SpecOther)) {
1378 m_jit.or32(TrustedImm32(1), valueTagGPR, resultPayloadGPR);
1380 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, SpecCell | SpecOther,
1382 MacroAssembler::NotEqual,
1384 TrustedImm32(JSValue::NullTag)));
1386 m_jit.move(TrustedImm32(1), resultPayloadGPR);
1390 booleanResult(resultPayloadGPR, m_currentNode);
1393 void SpeculativeJIT::compileLogicalNot(Node* node)
1395 switch (node->child1().useKind()) {
1397 SpeculateBooleanOperand value(this, node->child1());
1398 GPRTemporary result(this, Reuse, value);
1399 m_jit.xor32(TrustedImm32(1), value.gpr(), result.gpr());
1400 booleanResult(result.gpr(), node);
1404 case ObjectOrOtherUse: {
1405 compileObjectOrOtherLogicalNot(node->child1());
1410 SpeculateInt32Operand value(this, node->child1());
1411 GPRTemporary resultPayload(this, Reuse, value);
1412 m_jit.compare32(MacroAssembler::Equal, value.gpr(), MacroAssembler::TrustedImm32(0), resultPayload.gpr());
1413 booleanResult(resultPayload.gpr(), node);
1417 case DoubleRepUse: {
1418 SpeculateDoubleOperand value(this, node->child1());
1419 FPRTemporary scratch(this);
1420 GPRTemporary resultPayload(this);
1421 m_jit.move(TrustedImm32(0), resultPayload.gpr());
1422 MacroAssembler::Jump nonZero = m_jit.branchDoubleNonZero(value.fpr(), scratch.fpr());
1423 m_jit.move(TrustedImm32(1), resultPayload.gpr());
1424 nonZero.link(&m_jit);
1425 booleanResult(resultPayload.gpr(), node);
1430 JSValueOperand arg1(this, node->child1());
1431 GPRTemporary resultPayload(this, Reuse, arg1, PayloadWord);
1432 GPRReg arg1TagGPR = arg1.tagGPR();
1433 GPRReg arg1PayloadGPR = arg1.payloadGPR();
1434 GPRReg resultPayloadGPR = resultPayload.gpr();
1438 JITCompiler::Jump slowCase = m_jit.branch32(JITCompiler::NotEqual, arg1TagGPR, TrustedImm32(JSValue::BooleanTag));
1440 m_jit.move(arg1PayloadGPR, resultPayloadGPR);
1442 addSlowPathGenerator(
1444 slowCase, this, operationConvertJSValueToBoolean, resultPayloadGPR, arg1TagGPR,
1447 m_jit.xor32(TrustedImm32(1), resultPayloadGPR);
1448 booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
1452 return compileStringZeroLength(node);
1455 RELEASE_ASSERT_NOT_REACHED();
1460 void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BasicBlock* taken, BasicBlock* notTaken)
1462 JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
1463 GPRTemporary scratch(this);
1464 GPRReg valueTagGPR = value.tagGPR();
1465 GPRReg valuePayloadGPR = value.payloadGPR();
1466 GPRReg scratchGPR = scratch.gpr();
1468 MacroAssembler::Jump notCell = branchNotCell(value.jsValueRegs());
1469 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
1471 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
1473 MacroAssembler::Equal,
1474 MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()),
1475 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1477 m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), scratchGPR);
1480 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
1482 MacroAssembler::Equal,
1484 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
1486 JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8(
1488 MacroAssembler::Address(valuePayloadGPR, JSCell::typeInfoFlagsOffset()),
1489 TrustedImm32(MasqueradesAsUndefined));
1491 speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
1493 MacroAssembler::Equal,
1494 MacroAssembler::Address(scratchGPR, Structure::globalObjectOffset()),
1495 MacroAssembler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode->origin.semantic))));
1497 isNotMasqueradesAsUndefined.link(&m_jit);
1499 jump(taken, ForceJump);
1501 notCell.link(&m_jit);
1503 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
1504 if (needsTypeCheck(nodeUse, SpecCell | SpecOther)) {
1505 m_jit.or32(TrustedImm32(1), valueTagGPR, scratchGPR);
1507 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, SpecCell | SpecOther,
1508 m_jit.branch32(MacroAssembler::NotEqual, scratchGPR, TrustedImm32(JSValue::NullTag)));
1513 noResult(m_currentNode);
1516 void SpeculativeJIT::emitBranch(Node* node)
1518 BasicBlock* taken = node->branchData()->taken.block;
1519 BasicBlock* notTaken = node->branchData()->notTaken.block;
1521 switch (node->child1().useKind()) {
1523 SpeculateBooleanOperand value(this, node->child1());
1524 MacroAssembler::ResultCondition condition = MacroAssembler::NonZero;
1526 if (taken == nextBlock()) {
1527 condition = MacroAssembler::Zero;
1528 BasicBlock* tmp = taken;
1533 branchTest32(condition, value.gpr(), TrustedImm32(1), taken);
1540 case ObjectOrOtherUse: {
1541 emitObjectOrOtherBranch(node->child1(), taken, notTaken);
1547 if (node->child1().useKind() == Int32Use) {
1548 bool invert = false;
1550 if (taken == nextBlock()) {
1552 BasicBlock* tmp = taken;
1557 SpeculateInt32Operand value(this, node->child1());
1558 branchTest32(invert ? MacroAssembler::Zero : MacroAssembler::NonZero, value.gpr(), taken);
1560 SpeculateDoubleOperand value(this, node->child1());
1561 FPRTemporary scratch(this);
1562 branchDoubleNonZero(value.fpr(), scratch.fpr(), taken);
1572 JSValueOperand value(this, node->child1());
1574 GPRReg valueTagGPR = value.tagGPR();
1575 GPRReg valuePayloadGPR = value.payloadGPR();
1577 GPRTemporary result(this);
1578 GPRReg resultGPR = result.gpr();
1580 use(node->child1());
1582 JITCompiler::Jump fastPath = m_jit.branch32(JITCompiler::Equal, valueTagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag));
1583 JITCompiler::Jump slowPath = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, JITCompiler::TrustedImm32(JSValue::BooleanTag));
1585 fastPath.link(&m_jit);
1586 branchTest32(JITCompiler::Zero, valuePayloadGPR, notTaken);
1587 jump(taken, ForceJump);
1589 slowPath.link(&m_jit);
1590 silentSpillAllRegisters(resultGPR);
1591 callOperation(operationConvertJSValueToBoolean, resultGPR, valueTagGPR, valuePayloadGPR);
1592 silentFillAllRegisters(resultGPR);
1594 branchTest32(JITCompiler::NonZero, resultGPR, taken);
1597 noResult(node, UseChildrenCalledExplicitly);
1602 RELEASE_ASSERT_NOT_REACHED();
1607 template<typename BaseOperandType, typename PropertyOperandType, typename ValueOperandType, typename TagType>
1608 void SpeculativeJIT::compileContiguousPutByVal(Node* node, BaseOperandType& base, PropertyOperandType& property, ValueOperandType& value, GPRReg valuePayloadReg, TagType valueTag)
1610 Edge child4 = m_jit.graph().varArgChild(node, 3);
1612 ArrayMode arrayMode = node->arrayMode();
1614 GPRReg baseReg = base.gpr();
1615 GPRReg propertyReg = property.gpr();
1617 StorageOperand storage(this, child4);
1618 GPRReg storageReg = storage.gpr();
1620 if (node->op() == PutByValAlias) {
1621 // Store the value to the array.
1622 GPRReg propertyReg = property.gpr();
1623 m_jit.store32(valueTag, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
1624 m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
1630 MacroAssembler::Jump slowCase;
1632 if (arrayMode.isInBounds()) {
1634 OutOfBounds, JSValueRegs(), 0,
1635 m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
1637 MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
1639 slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength()));
1641 if (!arrayMode.isOutOfBounds())
1642 speculationCheck(OutOfBounds, JSValueRegs(), 0, slowCase);
1644 m_jit.add32(TrustedImm32(1), propertyReg);
1645 m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
1646 m_jit.sub32(TrustedImm32(1), propertyReg);
1648 inBounds.link(&m_jit);
1651 m_jit.store32(valueTag, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
1652 m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
1659 if (arrayMode.isOutOfBounds()) {
1660 if (node->op() == PutByValDirect) {
1661 addSlowPathGenerator(slowPathCall(
1663 m_jit.codeBlock()->isStrictMode() ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValDirectBeyondArrayBoundsNonStrict,
1664 NoResult, baseReg, propertyReg, valueTag, valuePayloadReg));
1666 addSlowPathGenerator(slowPathCall(
1668 m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
1669 NoResult, baseReg, propertyReg, valueTag, valuePayloadReg));
1673 noResult(node, UseChildrenCalledExplicitly);
1676 void SpeculativeJIT::compile(Node* node)
1678 NodeType op = node->op();
1680 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
1681 m_jit.clearRegisterAllocationOffsets();
1686 case DoubleConstant:
1687 initConstantInfo(node);
1690 case PhantomArguments:
1691 initConstantInfo(node);
1695 RELEASE_ASSERT_NOT_REACHED();
1700 AbstractValue& value = m_state.variables().operand(node->local());
1702 // If the CFA is tracking this variable and it found that the variable
1703 // cannot have been assigned, then don't attempt to proceed.
1704 if (value.isClear()) {
1705 m_compileOkay = false;
1709 switch (node->variableAccessData()->flushFormat()) {
1710 case FlushedDouble: {
1711 FPRTemporary result(this);
1712 m_jit.loadDouble(JITCompiler::addressFor(node->machineLocal()), result.fpr());
1713 VirtualRegister virtualRegister = node->virtualRegister();
1714 m_fprs.retain(result.fpr(), virtualRegister, SpillOrderDouble);
1715 generationInfoFromVirtualRegister(virtualRegister).initDouble(node, node->refCount(), result.fpr());
1719 case FlushedInt32: {
1720 GPRTemporary result(this);
1721 m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr());
1723 // Like int32Result, but don't useChildren - our children are phi nodes,
1724 // and don't represent values within this dataflow with virtual registers.
1725 VirtualRegister virtualRegister = node->virtualRegister();
1726 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderInteger);
1727 generationInfoFromVirtualRegister(virtualRegister).initInt32(node, node->refCount(), result.gpr());
1732 GPRTemporary result(this);
1733 m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr());
1735 // Like cellResult, but don't useChildren - our children are phi nodes,
1736 // and don't represent values within this dataflow with virtual registers.
1737 VirtualRegister virtualRegister = node->virtualRegister();
1738 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderCell);
1739 generationInfoFromVirtualRegister(virtualRegister).initCell(node, node->refCount(), result.gpr());
1743 case FlushedBoolean: {
1744 GPRTemporary result(this);
1745 m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr());
1747 // Like booleanResult, but don't useChildren - our children are phi nodes,
1748 // and don't represent values within this dataflow with virtual registers.
1749 VirtualRegister virtualRegister = node->virtualRegister();
1750 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderBoolean);
1751 generationInfoFromVirtualRegister(virtualRegister).initBoolean(node, node->refCount(), result.gpr());
1755 case FlushedJSValue:
1756 case FlushedArguments: {
1757 GPRTemporary result(this);
1758 GPRTemporary tag(this);
1759 m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr());
1760 m_jit.load32(JITCompiler::tagFor(node->machineLocal()), tag.gpr());
1762 // Like jsValueResult, but don't useChildren - our children are phi nodes,
1763 // and don't represent values within this dataflow with virtual registers.
1764 VirtualRegister virtualRegister = node->virtualRegister();
1765 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
1766 m_gprs.retain(tag.gpr(), virtualRegister, SpillOrderJS);
1768 generationInfoFromVirtualRegister(virtualRegister).initJSValue(node, node->refCount(), tag.gpr(), result.gpr(), DataFormatJS);
1773 RELEASE_ASSERT_NOT_REACHED();
1778 case GetLocalUnlinked: {
1779 GPRTemporary payload(this);
1780 GPRTemporary tag(this);
1781 m_jit.load32(JITCompiler::payloadFor(node->unlinkedMachineLocal()), payload.gpr());
1782 m_jit.load32(JITCompiler::tagFor(node->unlinkedMachineLocal()), tag.gpr());
1783 jsValueResult(tag.gpr(), payload.gpr(), node);
1789 RELEASE_ASSERT_NOT_REACHED();
1794 switch (node->variableAccessData()->flushFormat()) {
1795 case FlushedDouble: {
1796 SpeculateDoubleOperand value(this, node->child1());
1797 m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node->machineLocal()));
1799 // Indicate that it's no longer necessary to retrieve the value of
1800 // this bytecode variable from registers or other locations in the stack,
1801 // but that it is stored as a double.
1802 recordSetLocal(DataFormatDouble);
1806 case FlushedInt32: {
1807 SpeculateInt32Operand value(this, node->child1());
1808 m_jit.store32(value.gpr(), JITCompiler::payloadFor(node->machineLocal()));
1810 recordSetLocal(DataFormatInt32);
1815 SpeculateCellOperand cell(this, node->child1());
1816 GPRReg cellGPR = cell.gpr();
1817 m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node->machineLocal()));
1819 recordSetLocal(DataFormatCell);
1823 case FlushedBoolean: {
1824 SpeculateBooleanOperand value(this, node->child1());
1825 m_jit.store32(value.gpr(), JITCompiler::payloadFor(node->machineLocal()));
1827 recordSetLocal(DataFormatBoolean);
1831 case FlushedJSValue:
1832 case FlushedArguments: {
1833 JSValueOperand value(this, node->child1());
1834 m_jit.store32(value.payloadGPR(), JITCompiler::payloadFor(node->machineLocal()));
1835 m_jit.store32(value.tagGPR(), JITCompiler::tagFor(node->machineLocal()));
1837 recordSetLocal(dataFormatFor(node->variableAccessData()->flushFormat()));
1842 RELEASE_ASSERT_NOT_REACHED();
1849 // This is a no-op; it just marks the fact that the argument is being used.
1850 // But it may be profitable to use this as a hook to run speculation checks
1851 // on arguments, thereby allowing us to trivially eliminate such checks if
1852 // the argument is not used.
1853 recordSetLocal(dataFormatFor(node->variableAccessData()->flushFormat()));
1859 if (node->child1()->isInt32Constant()) {
1860 SpeculateInt32Operand op2(this, node->child2());
1861 GPRTemporary result(this, Reuse, op2);
1863 bitOp(op, node->child1()->asInt32(), op2.gpr(), result.gpr());
1865 int32Result(result.gpr(), node);
1866 } else if (node->child2()->isInt32Constant()) {
1867 SpeculateInt32Operand op1(this, node->child1());
1868 GPRTemporary result(this, Reuse, op1);
1870 bitOp(op, node->child2()->asInt32(), op1.gpr(), result.gpr());
1872 int32Result(result.gpr(), node);
1874 SpeculateInt32Operand op1(this, node->child1());
1875 SpeculateInt32Operand op2(this, node->child2());
1876 GPRTemporary result(this, Reuse, op1, op2);
1878 GPRReg reg1 = op1.gpr();
1879 GPRReg reg2 = op2.gpr();
1880 bitOp(op, reg1, reg2, result.gpr());
1882 int32Result(result.gpr(), node);
1889 if (node->child2()->isInt32Constant()) {
1890 SpeculateInt32Operand op1(this, node->child1());
1891 GPRTemporary result(this, Reuse, op1);
1893 shiftOp(op, op1.gpr(), node->child2()->asInt32() & 0x1f, result.gpr());
1895 int32Result(result.gpr(), node);
1897 // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.
1898 SpeculateInt32Operand op1(this, node->child1());
1899 SpeculateInt32Operand op2(this, node->child2());
1900 GPRTemporary result(this, Reuse, op1);
1902 GPRReg reg1 = op1.gpr();
1903 GPRReg reg2 = op2.gpr();
1904 shiftOp(op, reg1, reg2, result.gpr());
1906 int32Result(result.gpr(), node);
1910 case UInt32ToNumber: {
1911 compileUInt32ToNumber(node);
1915 case DoubleAsInt32: {
1916 compileDoubleAsInt32(node);
1920 case ValueToInt32: {
1921 compileValueToInt32(node);
1926 compileDoubleRep(node);
1931 compileValueRep(node);
1936 JSValueOperand op1(this, node->child1());
1937 JSValueOperand op2(this, node->child2());
1939 GPRReg op1TagGPR = op1.tagGPR();
1940 GPRReg op1PayloadGPR = op1.payloadGPR();
1941 GPRReg op2TagGPR = op2.tagGPR();
1942 GPRReg op2PayloadGPR = op2.payloadGPR();
1946 GPRResult2 resultTag(this);
1947 GPRResult resultPayload(this);
1948 if (isKnownNotNumber(node->child1().node()) || isKnownNotNumber(node->child2().node()))
1949 callOperation(operationValueAddNotNumber, resultTag.gpr(), resultPayload.gpr(), op1TagGPR, op1PayloadGPR, op2TagGPR, op2PayloadGPR);
1951 callOperation(operationValueAdd, resultTag.gpr(), resultPayload.gpr(), op1TagGPR, op1PayloadGPR, op2TagGPR, op2PayloadGPR);
1953 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
1962 compileMakeRope(node);
1966 compileArithSub(node);
1970 compileArithNegate(node);
1974 compileArithMul(node);
1978 compileArithDiv(node);
1983 compileArithMod(node);
1988 switch (node->child1().useKind()) {
1990 SpeculateStrictInt32Operand op1(this, node->child1());
1991 GPRTemporary result(this, Reuse, op1);
1992 GPRTemporary scratch(this);
1994 m_jit.move(op1.gpr(), result.gpr());
1995 m_jit.rshift32(result.gpr(), MacroAssembler::TrustedImm32(31), scratch.gpr());
1996 m_jit.add32(scratch.gpr(), result.gpr());
1997 m_jit.xor32(scratch.gpr(), result.gpr());
1998 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Equal, result.gpr(), MacroAssembler::TrustedImm32(1 << 31)));
1999 int32Result(result.gpr(), node);
2004 case DoubleRepUse: {
2005 SpeculateDoubleOperand op1(this, node->child1());
2006 FPRTemporary result(this);
2008 m_jit.absDouble(op1.fpr(), result.fpr());
2009 doubleResult(result.fpr(), node);
2014 RELEASE_ASSERT_NOT_REACHED();
2022 switch (node->binaryUseKind()) {
2024 SpeculateStrictInt32Operand op1(this, node->child1());
2025 SpeculateStrictInt32Operand op2(this, node->child2());
2026 GPRTemporary result(this, Reuse, op1);
2028 GPRReg op1GPR = op1.gpr();
2029 GPRReg op2GPR = op2.gpr();
2030 GPRReg resultGPR = result.gpr();
2032 MacroAssembler::Jump op1Less = m_jit.branch32(op == ArithMin ? MacroAssembler::LessThan : MacroAssembler::GreaterThan, op1GPR, op2GPR);
2033 m_jit.move(op2GPR, resultGPR);
2034 if (op1GPR != resultGPR) {
2035 MacroAssembler::Jump done = m_jit.jump();
2036 op1Less.link(&m_jit);
2037 m_jit.move(op1GPR, resultGPR);
2040 op1Less.link(&m_jit);
2042 int32Result(resultGPR, node);
2046 case DoubleRepUse: {
2047 SpeculateDoubleOperand op1(this, node->child1());
2048 SpeculateDoubleOperand op2(this, node->child2());
2049 FPRTemporary result(this, op1);
2051 FPRReg op1FPR = op1.fpr();
2052 FPRReg op2FPR = op2.fpr();
2053 FPRReg resultFPR = result.fpr();
2055 MacroAssembler::JumpList done;
2057 MacroAssembler::Jump op1Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleLessThan : MacroAssembler::DoubleGreaterThan, op1FPR, op2FPR);
2059 // op2 is eather the lesser one or one of then is NaN
2060 MacroAssembler::Jump op2Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleGreaterThanOrEqual : MacroAssembler::DoubleLessThanOrEqual, op1FPR, op2FPR);
2062 // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding
2063 // op1 + op2 and putting it into result.
2064 m_jit.addDouble(op1FPR, op2FPR, resultFPR);
2065 done.append(m_jit.jump());
2067 op2Less.link(&m_jit);
2068 m_jit.moveDouble(op2FPR, resultFPR);
2070 if (op1FPR != resultFPR) {
2071 done.append(m_jit.jump());
2073 op1Less.link(&m_jit);
2074 m_jit.moveDouble(op1FPR, resultFPR);
2076 op1Less.link(&m_jit);
2080 doubleResult(resultFPR, node);
2085 RELEASE_ASSERT_NOT_REACHED();
2092 SpeculateDoubleOperand op1(this, node->child1());
2093 FPRTemporary result(this, op1);
2095 m_jit.sqrtDouble(op1.fpr(), result.fpr());
2097 doubleResult(result.fpr(), node);
2102 SpeculateDoubleOperand op1(this, node->child1());
2103 FPRTemporary result(this, op1);
2105 m_jit.convertDoubleToFloat(op1.fpr(), result.fpr());
2106 m_jit.convertFloatToDouble(result.fpr(), result.fpr());
2108 doubleResult(result.fpr(), node);
2113 SpeculateDoubleOperand op1(this, node->child1());
2114 FPRReg op1FPR = op1.fpr();
2118 FPRResult result(this);
2119 callOperation(sin, result.fpr(), op1FPR);
2120 doubleResult(result.fpr(), node);
2125 SpeculateDoubleOperand op1(this, node->child1());
2126 FPRReg op1FPR = op1.fpr();
2130 FPRResult result(this);
2131 callOperation(cos, result.fpr(), op1FPR);
2132 doubleResult(result.fpr(), node);
2137 compileLogicalNot(node);
2141 if (compare(node, JITCompiler::LessThan, JITCompiler::DoubleLessThan, operationCompareLess))
2146 if (compare(node, JITCompiler::LessThanOrEqual, JITCompiler::DoubleLessThanOrEqual, operationCompareLessEq))
2150 case CompareGreater:
2151 if (compare(node, JITCompiler::GreaterThan, JITCompiler::DoubleGreaterThan, operationCompareGreater))
2155 case CompareGreaterEq:
2156 if (compare(node, JITCompiler::GreaterThanOrEqual, JITCompiler::DoubleGreaterThanOrEqual, operationCompareGreaterEq))
2160 case CompareEqConstant:
2161 ASSERT(node->child2()->asJSValue().isNull());
2162 if (nonSpeculativeCompareNull(node, node->child1()))
2167 if (compare(node, JITCompiler::Equal, JITCompiler::DoubleEqual, operationCompareEq))
2171 case CompareStrictEq:
2172 if (compileStrictEq(node))
2176 case StringCharCodeAt: {
2177 compileGetCharCodeAt(node);
2181 case StringCharAt: {
2182 // Relies on StringCharAt node having same basic layout as GetByVal
2183 compileGetByValOnString(node);
2187 case StringFromCharCode: {
2188 compileFromCharCode(node);
2198 case ArrayifyToStructure: {
2204 switch (node->arrayMode().type()) {
2205 case Array::SelectUsingPredictions:
2206 case Array::ForceExit:
2207 RELEASE_ASSERT_NOT_REACHED();
2208 #if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
2209 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
2212 case Array::Generic: {
2213 SpeculateCellOperand base(this, node->child1()); // Save a register, speculate cell. We'll probably be right.
2214 JSValueOperand property(this, node->child2());
2215 GPRReg baseGPR = base.gpr();
2216 GPRReg propertyTagGPR = property.tagGPR();
2217 GPRReg propertyPayloadGPR = property.payloadGPR();
2220 GPRResult2 resultTag(this);
2221 GPRResult resultPayload(this);
2222 callOperation(operationGetByValCell, resultTag.gpr(), resultPayload.gpr(), baseGPR, propertyTagGPR, propertyPayloadGPR);
2224 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
2228 case Array::Contiguous: {
2229 if (node->arrayMode().isInBounds()) {
2230 SpeculateStrictInt32Operand property(this, node->child2());
2231 StorageOperand storage(this, node->child3());
2233 GPRReg propertyReg = property.gpr();
2234 GPRReg storageReg = storage.gpr();
2239 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2241 GPRTemporary resultPayload(this);
2242 if (node->arrayMode().type() == Array::Int32) {
2244 OutOfBounds, JSValueRegs(), 0,
2246 MacroAssembler::Equal,
2247 MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)),
2248 TrustedImm32(JSValue::EmptyValueTag)));
2249 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
2250 int32Result(resultPayload.gpr(), node);
2254 GPRTemporary resultTag(this);
2255 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr());
2256 speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag)));
2257 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
2258 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
2262 SpeculateCellOperand base(this, node->child1());
2263 SpeculateStrictInt32Operand property(this, node->child2());
2264 StorageOperand storage(this, node->child3());
2266 GPRReg baseReg = base.gpr();
2267 GPRReg propertyReg = property.gpr();
2268 GPRReg storageReg = storage.gpr();
2273 GPRTemporary resultTag(this);
2274 GPRTemporary resultPayload(this);
2275 GPRReg resultTagReg = resultTag.gpr();
2276 GPRReg resultPayloadReg = resultPayload.gpr();
2278 MacroAssembler::JumpList slowCases;
2280 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2282 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagReg);
2283 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayloadReg);
2284 slowCases.append(m_jit.branch32(MacroAssembler::Equal, resultTagReg, TrustedImm32(JSValue::EmptyValueTag)));
2286 addSlowPathGenerator(
2288 slowCases, this, operationGetByValArrayInt,
2289 JSValueRegs(resultTagReg, resultPayloadReg), baseReg, propertyReg));
2291 jsValueResult(resultTagReg, resultPayloadReg, node);
2294 case Array::Double: {
2295 if (node->arrayMode().isInBounds()) {
2296 SpeculateStrictInt32Operand property(this, node->child2());
2297 StorageOperand storage(this, node->child3());
2299 GPRReg propertyReg = property.gpr();
2300 GPRReg storageReg = storage.gpr();
2305 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2307 FPRTemporary result(this);
2308 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr());
2309 if (!node->arrayMode().isSaneChain())
2310 speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr()));
2311 doubleResult(result.fpr(), node);
2315 SpeculateCellOperand base(this, node->child1());
2316 SpeculateStrictInt32Operand property(this, node->child2());
2317 StorageOperand storage(this, node->child3());
2319 GPRReg baseReg = base.gpr();
2320 GPRReg propertyReg = property.gpr();
2321 GPRReg storageReg = storage.gpr();
2326 GPRTemporary resultTag(this);
2327 GPRTemporary resultPayload(this);
2328 FPRTemporary temp(this);
2329 GPRReg resultTagReg = resultTag.gpr();
2330 GPRReg resultPayloadReg = resultPayload.gpr();
2331 FPRReg tempReg = temp.fpr();
2333 MacroAssembler::JumpList slowCases;
2335 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2337 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
2338 slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempReg, tempReg));
2339 boxDouble(tempReg, resultTagReg, resultPayloadReg);
2341 addSlowPathGenerator(
2343 slowCases, this, operationGetByValArrayInt,
2344 JSValueRegs(resultTagReg, resultPayloadReg), baseReg, propertyReg));
2346 jsValueResult(resultTagReg, resultPayloadReg, node);
2349 case Array::ArrayStorage:
2350 case Array::SlowPutArrayStorage: {
2351 if (node->arrayMode().isInBounds()) {
2352 SpeculateStrictInt32Operand property(this, node->child2());
2353 StorageOperand storage(this, node->child3());
2354 GPRReg propertyReg = property.gpr();
2355 GPRReg storageReg = storage.gpr();
2360 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())));
2362 GPRTemporary resultTag(this);
2363 GPRTemporary resultPayload(this);
2365 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr());
2366 speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag)));
2367 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
2369 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
2373 SpeculateCellOperand base(this, node->child1());
2374 SpeculateStrictInt32Operand property(this, node->child2());
2375 StorageOperand storage(this, node->child3());
2376 GPRReg propertyReg = property.gpr();
2377 GPRReg storageReg = storage.gpr();
2378 GPRReg baseReg = base.gpr();
2383 GPRTemporary resultTag(this);
2384 GPRTemporary resultPayload(this);
2385 GPRReg resultTagReg = resultTag.gpr();
2386 GPRReg resultPayloadReg = resultPayload.gpr();
2388 JITCompiler::Jump outOfBounds = m_jit.branch32(
2389 MacroAssembler::AboveOrEqual, propertyReg,
2390 MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset()));
2392 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagReg);
2393 JITCompiler::Jump hole = m_jit.branch32(
2394 MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag));
2395 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayloadReg);
2397 JITCompiler::JumpList slowCases;
2398 slowCases.append(outOfBounds);
2399 slowCases.append(hole);
2400 addSlowPathGenerator(
2402 slowCases, this, operationGetByValArrayInt,
2403 JSValueRegs(resultTagReg, resultPayloadReg),
2404 baseReg, propertyReg));
2406 jsValueResult(resultTagReg, resultPayloadReg, node);
2410 compileGetByValOnString(node);
2412 case Array::Arguments:
2413 compileGetByValOnArguments(node);
2416 TypedArrayType type = node->arrayMode().typedArrayType();
2418 compileGetByValOnIntTypedArray(node, type);
2420 compileGetByValOnFloatTypedArray(node, type);
2425 case PutByValDirect:
2427 case PutByValAlias: {
2428 Edge child1 = m_jit.graph().varArgChild(node, 0);
2429 Edge child2 = m_jit.graph().varArgChild(node, 1);
2430 Edge child3 = m_jit.graph().varArgChild(node, 2);
2431 Edge child4 = m_jit.graph().varArgChild(node, 3);
2433 ArrayMode arrayMode = node->arrayMode().modeForPut();
2434 bool alreadyHandled = false;
2436 switch (arrayMode.type()) {
2437 case Array::SelectUsingPredictions:
2438 case Array::ForceExit:
2439 RELEASE_ASSERT_NOT_REACHED();
2440 #if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
2441 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
2442 alreadyHandled = true;
2445 case Array::Generic: {
2446 ASSERT(node->op() == PutByVal || node->op() == PutByValDirect);
2448 SpeculateCellOperand base(this, child1); // Save a register, speculate cell. We'll probably be right.
2449 JSValueOperand property(this, child2);
2450 JSValueOperand value(this, child3);
2451 GPRReg baseGPR = base.gpr();
2452 GPRReg propertyTagGPR = property.tagGPR();
2453 GPRReg propertyPayloadGPR = property.payloadGPR();
2454 GPRReg valueTagGPR = value.tagGPR();
2455 GPRReg valuePayloadGPR = value.payloadGPR();
2458 if (node->op() == PutByValDirect)
2459 callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValDirectCellStrict : operationPutByValDirectCellNonStrict, baseGPR, propertyTagGPR, propertyPayloadGPR, valueTagGPR, valuePayloadGPR);
2461 callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValCellStrict : operationPutByValCellNonStrict, baseGPR, propertyTagGPR, propertyPayloadGPR, valueTagGPR, valuePayloadGPR);
2464 alreadyHandled = true;
2474 SpeculateCellOperand base(this, child1);
2475 SpeculateStrictInt32Operand property(this, child2);
2477 GPRReg baseReg = base.gpr();
2478 GPRReg propertyReg = property.gpr();
2480 switch (arrayMode.type()) {
2481 case Array::Int32: {
2482 SpeculateInt32Operand value(this, child3);
2484 GPRReg valuePayloadReg = value.gpr();
2489 compileContiguousPutByVal(node, base, property, value, valuePayloadReg, TrustedImm32(JSValue::Int32Tag));
2492 case Array::Contiguous: {
2493 JSValueOperand value(this, child3);
2495 GPRReg valueTagReg = value.tagGPR();
2496 GPRReg valuePayloadReg = value.payloadGPR();
2501 compileContiguousPutByVal(node, base, property, value, valuePayloadReg, valueTagReg);
2504 case Array::Double: {
2505 compileDoublePutByVal(node, base, property);
2508 case Array::ArrayStorage:
2509 case Array::SlowPutArrayStorage: {
2510 JSValueOperand value(this, child3);
2512 GPRReg valueTagReg = value.tagGPR();
2513 GPRReg valuePayloadReg = value.payloadGPR();
2518 StorageOperand storage(this, child4);
2519 GPRReg storageReg = storage.gpr();
2521 if (node->op() == PutByValAlias) {
2522 // Store the value to the array.
2523 GPRReg propertyReg = property.gpr();
2524 m_jit.store32(value.tagGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2525 m_jit.store32(value.payloadGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2531 MacroAssembler::JumpList slowCases;
2533 MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset()));
2534 if (!arrayMode.isOutOfBounds())
2535 speculationCheck(OutOfBounds, JSValueRegs(), 0, beyondArrayBounds);
2537 slowCases.append(beyondArrayBounds);
2539 // Check if we're writing to a hole; if so increment m_numValuesInVector.
2540 if (arrayMode.isInBounds()) {
2542 StoreToHole, JSValueRegs(), 0,
2543 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)));
2545 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));
2546 if (arrayMode.isSlowPut()) {
2547 // This is sort of strange. If we wanted to optimize this code path, we would invert
2548 // the above branch. But it's simply not worth it since this only happens if we're
2549 // already having a bad time.
2550 slowCases.append(m_jit.jump());
2552 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, ArrayStorage::numValuesInVectorOffset()));
2554 // If we're writing to a hole we might be growing the array;
2555 MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
2556 m_jit.add32(TrustedImm32(1), propertyReg);
2557 m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
2558 m_jit.sub32(TrustedImm32(1), propertyReg);
2560 lengthDoesNotNeedUpdate.link(&m_jit);
2562 notHoleValue.link(&m_jit);
2565 // Store the value to the array.
2566 m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2567 m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2574 if (!slowCases.empty()) {
2575 if (node->op() == PutByValDirect) {
2576 addSlowPathGenerator(slowPathCall(
2578 m_jit.codeBlock()->isStrictMode() ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValDirectBeyondArrayBoundsNonStrict,
2579 NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg));
2581 addSlowPathGenerator(slowPathCall(
2583 m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
2584 NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg));
2588 noResult(node, UseChildrenCalledExplicitly);
2592 case Array::Arguments:
2593 // FIXME: we could at some point make this work. Right now we're assuming that the register
2594 // pressure would be too great.
2595 RELEASE_ASSERT_NOT_REACHED();
2599 TypedArrayType type = arrayMode.typedArrayType();
2601 compilePutByValForIntTypedArray(base.gpr(), property.gpr(), node, type);
2603 compilePutByValForFloatTypedArray(base.gpr(), property.gpr(), node, type);
2609 if (compileRegExpExec(node))
2612 if (!node->adjustedRefCount()) {
2613 SpeculateCellOperand base(this, node->child1());
2614 SpeculateCellOperand argument(this, node->child2());
2615 GPRReg baseGPR = base.gpr();
2616 GPRReg argumentGPR = argument.gpr();
2619 GPRResult result(this);
2620 callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
2622 // Must use jsValueResult because otherwise we screw up register
2623 // allocation, which thinks that this node has a result.
2624 booleanResult(result.gpr(), node);
2628 SpeculateCellOperand base(this, node->child1());
2629 SpeculateCellOperand argument(this, node->child2());
2630 GPRReg baseGPR = base.gpr();
2631 GPRReg argumentGPR = argument.gpr();
2634 GPRResult2 resultTag(this);
2635 GPRResult resultPayload(this);
2636 callOperation(operationRegExpExec, resultTag.gpr(), resultPayload.gpr(), baseGPR, argumentGPR);
2638 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
2643 SpeculateCellOperand base(this, node->child1());
2644 SpeculateCellOperand argument(this, node->child2());
2645 GPRReg baseGPR = base.gpr();
2646 GPRReg argumentGPR = argument.gpr();
2649 GPRResult result(this);
2650 callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
2652 // If we add a DataFormatBool, we should use it here.
2653 booleanResult(result.gpr(), node);
2658 ASSERT(node->arrayMode().isJSArray());
2660 SpeculateCellOperand base(this, node->child1());
2661 GPRTemporary storageLength(this);
2663 GPRReg baseGPR = base.gpr();
2664 GPRReg storageLengthGPR = storageLength.gpr();
2666 StorageOperand storage(this, node->child3());
2667 GPRReg storageGPR = storage.gpr();
2669 switch (node->arrayMode().type()) {
2670 case Array::Int32: {
2671 SpeculateInt32Operand value(this, node->child2());
2672 GPRReg valuePayloadGPR = value.gpr();
2674 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
2675 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
2676 m_jit.store32(TrustedImm32(JSValue::Int32Tag), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2677 m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2678 m_jit.add32(TrustedImm32(1), storageLengthGPR);
2679 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
2680 m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
2682 addSlowPathGenerator(
2684 slowPath, this, operationArrayPush,
2685 JSValueRegs(storageGPR, storageLengthGPR),
2686 TrustedImm32(JSValue::Int32Tag), valuePayloadGPR, baseGPR));
2688 jsValueResult(storageGPR, storageLengthGPR, node);
2692 case Array::Contiguous: {
2693 JSValueOperand value(this, node->child2());
2694 GPRReg valueTagGPR = value.tagGPR();
2695 GPRReg valuePayloadGPR = value.payloadGPR();
2697 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
2698 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
2699 m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2700 m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2701 m_jit.add32(TrustedImm32(1), storageLengthGPR);
2702 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
2703 m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
2705 addSlowPathGenerator(
2707 slowPath, this, operationArrayPush,
2708 JSValueRegs(storageGPR, storageLengthGPR),
2709 valueTagGPR, valuePayloadGPR, baseGPR));
2711 jsValueResult(storageGPR, storageLengthGPR, node);
2715 case Array::Double: {
2716 SpeculateDoubleOperand value(this, node->child2());
2717 FPRReg valueFPR = value.fpr();
2720 JSValueRegs(), node->child2(), SpecDoubleReal,
2721 m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
2723 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
2724 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
2725 m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
2726 m_jit.add32(TrustedImm32(1), storageLengthGPR);
2727 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
2728 m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
2730 addSlowPathGenerator(
2732 slowPath, this, operationArrayPushDouble,
2733 JSValueRegs(storageGPR, storageLengthGPR),
2734 valueFPR, baseGPR));
2736 jsValueResult(storageGPR, storageLengthGPR, node);
2740 case Array::ArrayStorage: {
2741 JSValueOperand value(this, node->child2());
2742 GPRReg valueTagGPR = value.tagGPR();
2743 GPRReg valuePayloadGPR = value.payloadGPR();
2745 m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
2747 // Refuse to handle bizarre lengths.
2748 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(0x7ffffffe)));
2750 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
2752 m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2753 m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2755 m_jit.add32(TrustedImm32(1), storageLengthGPR);
2756 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
2757 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
2758 m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
2760 addSlowPathGenerator(slowPathCall(slowPath, this, operationArrayPush, JSValueRegs(storageGPR, storageLengthGPR), valueTagGPR, valuePayloadGPR, baseGPR));
2762 jsValueResult(storageGPR, storageLengthGPR, node);
2774 ASSERT(node->arrayMode().isJSArray());
2776 SpeculateCellOperand base(this, node->child1());
2777 StorageOperand storage(this, node->child2());
2778 GPRTemporary valueTag(this);
2779 GPRTemporary valuePayload(this);
2781 GPRReg baseGPR = base.gpr();
2782 GPRReg valueTagGPR = valueTag.gpr();
2783 GPRReg valuePayloadGPR = valuePayload.gpr();
2784 GPRReg storageGPR = storage.gpr();
2786 switch (node->arrayMode().type()) {
2788 case Array::Contiguous: {
2790 MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), valuePayloadGPR);
2791 MacroAssembler::Jump undefinedCase =
2792 m_jit.branchTest32(MacroAssembler::Zero, valuePayloadGPR);
2793 m_jit.sub32(TrustedImm32(1), valuePayloadGPR);
2795 valuePayloadGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
2797 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)),
2799 MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
2801 MacroAssembler::TrustedImm32(JSValue::EmptyValueTag),
2802 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2804 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)),
2807 addSlowPathGenerator(
2809 undefinedCase, this,
2810 MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR,
2811 MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR));
2812 addSlowPathGenerator(
2814 slowCase, this, operationArrayPopAndRecoverLength,
2815 JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR));
2817 jsValueResult(valueTagGPR, valuePayloadGPR, node);
2821 case Array::Double: {
2822 FPRTemporary temp(this);
2823 FPRReg tempFPR = temp.fpr();
2826 MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), valuePayloadGPR);
2827 MacroAssembler::Jump undefinedCase =
2828 m_jit.branchTest32(MacroAssembler::Zero, valuePayloadGPR);
2829 m_jit.sub32(TrustedImm32(1), valuePayloadGPR);
2831 valuePayloadGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
2833 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight),
2835 MacroAssembler::Jump slowCase = m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempFPR, tempFPR);
2836 JSValue nan = JSValue(JSValue::EncodeAsDouble, PNaN);
2838 MacroAssembler::TrustedImm32(nan.u.asBits.tag),
2839 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2841 MacroAssembler::TrustedImm32(nan.u.asBits.payload),
2842 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2843 boxDouble(tempFPR, valueTagGPR, valuePayloadGPR);
2845 addSlowPathGenerator(
2847 undefinedCase, this,
2848 MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR,
2849 MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR));
2850 addSlowPathGenerator(
2852 slowCase, this, operationArrayPopAndRecoverLength,
2853 JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR));
2855 jsValueResult(valueTagGPR, valuePayloadGPR, node);
2859 case Array::ArrayStorage: {
2860 GPRTemporary storageLength(this);
2861 GPRReg storageLengthGPR = storageLength.gpr();
2863 m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
2865 JITCompiler::JumpList setUndefinedCases;
2866 setUndefinedCases.append(m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR));
2868 m_jit.sub32(TrustedImm32(1), storageLengthGPR);
2870 MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
2872 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), valueTagGPR);
2873 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), valuePayloadGPR);
2875 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
2877 setUndefinedCases.append(m_jit.branch32(MacroAssembler::Equal, TrustedImm32(JSValue::EmptyValueTag), valueTagGPR));
2879 m_jit.store32(TrustedImm32(JSValue::EmptyValueTag), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2881 m_jit.sub32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
2883 addSlowPathGenerator(
2885 setUndefinedCases, this,
2886 MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR,
2887 MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR));
2889 addSlowPathGenerator(
2891 slowCase, this, operationArrayPop,
2892 JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR));
2894 jsValueResult(valueTagGPR, valuePayloadGPR, node);
2906 jump(node->targetBlock());
2920 ASSERT(GPRInfo::callFrameRegister != GPRInfo::regT2);
2921 ASSERT(GPRInfo::regT1 != GPRInfo::returnValueGPR);
2922 ASSERT(GPRInfo::returnValueGPR != GPRInfo::callFrameRegister);
2924 // Return the result in returnValueGPR.
2925 JSValueOperand op1(this, node->child1());
2928 boxDouble(op1.fpr(), GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
2930 if (op1.payloadGPR() == GPRInfo::returnValueGPR2 && op1.tagGPR() == GPRInfo::returnValueGPR)
2931 m_jit.swap(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2);
2932 else if (op1.payloadGPR() == GPRInfo::returnValueGPR2) {
2933 m_jit.move(op1.payloadGPR(), GPRInfo::returnValueGPR);
2934 m_jit.move(op1.tagGPR(), GPRInfo::returnValueGPR2);
2936 m_jit.move(op1.tagGPR(), GPRInfo::returnValueGPR2);
2937 m_jit.move(op1.payloadGPR(), GPRInfo::returnValueGPR);
2941 m_jit.emitFunctionEpilogue();
2949 case ThrowReferenceError: {
2950 // We expect that throw statements are rare and are intended to exit the code block
2951 // anyway, so we just OSR back to the old JIT for now.
2952 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
2956 case BooleanToNumber: {
2957 switch (node->child1().useKind()) {
2959 SpeculateBooleanOperand value(this, node->child1());
2960 GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).
2962 m_jit.move(value.gpr(), result.gpr());
2964 int32Result(result.gpr(), node);
2969 JSValueOperand value(this, node->child1());
2970 GPRTemporary resultTag(this);
2971 GPRTemporary resultPayload(this);
2973 GPRReg valueTagGPR = value.tagGPR();
2974 GPRReg valuePayloadGPR = value.payloadGPR();
2975 GPRReg resultTagGPR = resultTag.gpr();
2976 GPRReg resultPayloadGPR = resultPayload.gpr();
2978 m_jit.move(valuePayloadGPR, resultPayloadGPR);
2979 JITCompiler::Jump isBoolean = m_jit.branch32(
2980 JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::BooleanTag));
2981 m_jit.move(valueTagGPR, resultTagGPR);
2982 JITCompiler::Jump done = m_jit.jump();
2983 isBoolean.link(&m_jit);
2984 m_jit.move(TrustedImm32(JSValue::Int32Tag), resultTagGPR);
2987 jsValueResult(resultTagGPR, resultPayloadGPR, node);
2992 RELEASE_ASSERT_NOT_REACHED();
2999 RELEASE_ASSERT(node->child1().useKind() == UntypedUse);
3000 JSValueOperand op1(this, node->child1());
3001 GPRTemporary resultTag(this, Reuse, op1, TagWord);
3002 GPRTemporary resultPayload(this, Reuse, op1, PayloadWord);
3004 GPRReg op1TagGPR = op1.tagGPR();
3005 GPRReg op1PayloadGPR = op1.payloadGPR();
3006 GPRReg resultTagGPR = resultTag.gpr();
3007 GPRReg resultPayloadGPR = resultPayload.gpr();
3011 if (!(m_state.forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean))) {
3012 m_jit.move(op1TagGPR, resultTagGPR);
3013 m_jit.move(op1PayloadGPR, resultPayloadGPR);
3015 MacroAssembler::Jump alreadyPrimitive = branchNotCell(op1.jsValueRegs());
3016 MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1PayloadGPR, JSCell::structureIDOffset()), MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()));
3018 alreadyPrimitive.link(&m_jit);
3019 m_jit.move(op1TagGPR, resultTagGPR);
3020 m_jit.move(op1PayloadGPR, resultPayloadGPR);
3022 addSlowPathGenerator(
3024 notPrimitive, this, operationToPrimitive,
3025 JSValueRegs(resultTagGPR, resultPayloadGPR), op1TagGPR, op1PayloadGPR));
3028 jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
3033 if (node->child1().useKind() == UntypedUse) {
3034 JSValueOperand op1(this, node->child1());
3035 GPRReg op1PayloadGPR = op1.payloadGPR();
3036 GPRReg op1TagGPR = op1.tagGPR();
3038 GPRResult result(this);
3039 GPRReg resultGPR = result.gpr();
3043 JITCompiler::Jump done;
3044 if (node->child1()->prediction() & SpecString) {
3045 JITCompiler::Jump slowPath1 = branchNotCell(op1.jsValueRegs());
3046 JITCompiler::Jump slowPath2 = m_jit.branchPtr(
3047 JITCompiler::NotEqual,
3048 JITCompiler::Address(op1PayloadGPR, JSCell::structureIDOffset()),
3049 TrustedImmPtr(m_jit.vm()->stringStructure.get()));
3050 m_jit.move(op1PayloadGPR, resultGPR);
3051 done = m_jit.jump();
3052 slowPath1.link(&m_jit);
3053 slowPath2.link(&m_jit);
3055 callOperation(operationToString, resultGPR, op1TagGPR, op1PayloadGPR);
3058 cellResult(resultGPR, node);
3062 compileToStringOnCell(node);
3066 case NewStringObject: {
3067 compileNewStringObject(node);
3072 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
3073 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(node->indexingType())) {
3074 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType());
3075 ASSERT(structure->indexingType() == node->indexingType());
3077 hasUndecided(structure->indexingType())
3078 || hasInt32(structure->indexingType())
3079 || hasDouble(structure->indexingType())
3080 || hasContiguous(structure->indexingType()));
3082 unsigned numElements = node->numChildren();
3084 GPRTemporary result(this);
3085 GPRTemporary storage(this);
3087 GPRReg resultGPR = result.gpr();
3088 GPRReg storageGPR = storage.gpr();
3090 emitAllocateJSArray(resultGPR, structure, storageGPR, numElements);
3092 // At this point, one way or another, resultGPR and storageGPR have pointers to
3093 // the JSArray and the Butterfly, respectively.
3095 ASSERT(!hasUndecided(structure->indexingType()) || !node->numChildren());
3097 for (unsigned operandIdx = 0; operandIdx < node->numChildren(); ++operandIdx) {
3098 Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + operandIdx];
3099 switch (node->indexingType()) {
3100 case ALL_BLANK_INDEXING_TYPES:
3101 case ALL_UNDECIDED_INDEXING_TYPES:
3104 case ALL_DOUBLE_INDEXING_TYPES: {
3105 SpeculateDoubleOperand operand(this, use);
3106 FPRReg opFPR = operand.fpr();
3108 JSValueRegs(), use, SpecDoubleReal,
3109 m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
3111 m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx));
3114 case ALL_INT32_INDEXING_TYPES: {
3115 SpeculateInt32Operand operand(this, use);
3116 m_jit.store32(TrustedImm32(JSValue::Int32Tag), MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
3117 m_jit.store32(operand.gpr(), MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
3120 case ALL_CONTIGUOUS_INDEXING_TYPES: {
3121 JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node->firstChild() + operandIdx]);
3122 GPRReg opTagGPR = operand.tagGPR();
3123 GPRReg opPayloadGPR = operand.payloadGPR();
3124 m_jit.store32(opTagGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
3125 m_jit.store32(opPayloadGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));