2 * Copyright (C) 2011-2016 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 "CallFrameShuffler.h"
34 #include "DFGAbstractInterpreterInlines.h"
35 #include "DFGCallArrayAllocatorSlowPathGenerator.h"
36 #include "DFGOperations.h"
37 #include "DFGSlowPathGenerator.h"
39 #include "DirectArguments.h"
40 #include "GetterSetter.h"
41 #include "JSEnvironmentRecord.h"
42 #include "JSLexicalEnvironment.h"
43 #include "JSPropertyNameEnumerator.h"
44 #include "ObjectPrototype.h"
45 #include "JSCInlines.h"
46 #include "SetupVarargsFrame.h"
47 #include "TypeProfilerLog.h"
50 namespace JSC { namespace DFG {
54 bool SpeculativeJIT::fillJSValue(Edge edge, GPRReg& tagGPR, GPRReg& payloadGPR, FPRReg& fpr)
56 // FIXME: For double we could fill with a FPR.
59 VirtualRegister virtualRegister = edge->virtualRegister();
60 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
62 switch (info.registerFormat()) {
63 case DataFormatNone: {
65 if (edge->hasConstant()) {
67 payloadGPR = allocate();
68 JSValue value = edge->asJSValue();
69 m_jit.move(Imm32(value.tag()), tagGPR);
70 m_jit.move(Imm32(value.payload()), payloadGPR);
71 m_gprs.retain(tagGPR, virtualRegister, SpillOrderConstant);
72 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderConstant);
73 info.fillJSValue(*m_stream, tagGPR, payloadGPR, DataFormatJS);
75 DataFormat spillFormat = info.spillFormat();
76 ASSERT(spillFormat != DataFormatNone && spillFormat != DataFormatStorage);
78 payloadGPR = allocate();
79 switch (spillFormat) {
81 m_jit.move(TrustedImm32(JSValue::Int32Tag), tagGPR);
82 spillFormat = DataFormatJSInt32; // This will be used as the new register format.
85 m_jit.move(TrustedImm32(JSValue::CellTag), tagGPR);
86 spillFormat = DataFormatJSCell; // This will be used as the new register format.
88 case DataFormatBoolean:
89 m_jit.move(TrustedImm32(JSValue::BooleanTag), tagGPR);
90 spillFormat = DataFormatJSBoolean; // This will be used as the new register format.
93 m_jit.load32(JITCompiler::tagFor(virtualRegister), tagGPR);
96 m_jit.load32(JITCompiler::payloadFor(virtualRegister), payloadGPR);
97 m_gprs.retain(tagGPR, virtualRegister, SpillOrderSpilled);
98 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderSpilled);
99 info.fillJSValue(*m_stream, tagGPR, payloadGPR, spillFormat == DataFormatJSDouble ? DataFormatJS : spillFormat);
105 case DataFormatInt32:
107 case DataFormatBoolean: {
108 GPRReg gpr = info.gpr();
109 // If the register has already been locked we need to take a copy.
110 if (m_gprs.isLocked(gpr)) {
111 payloadGPR = allocate();
112 m_jit.move(gpr, payloadGPR);
118 int32_t tag = JSValue::EmptyValueTag;
119 DataFormat fillFormat = DataFormatJS;
120 switch (info.registerFormat()) {
121 case DataFormatInt32:
122 tag = JSValue::Int32Tag;
123 fillFormat = DataFormatJSInt32;
126 tag = JSValue::CellTag;
127 fillFormat = DataFormatJSCell;
129 case DataFormatBoolean:
130 tag = JSValue::BooleanTag;
131 fillFormat = DataFormatJSBoolean;
134 RELEASE_ASSERT_NOT_REACHED();
137 m_jit.move(TrustedImm32(tag), tagGPR);
139 m_gprs.retain(tagGPR, virtualRegister, SpillOrderJS);
140 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderJS);
141 info.fillJSValue(*m_stream, tagGPR, payloadGPR, fillFormat);
145 case DataFormatJSDouble:
147 case DataFormatJSInt32:
148 case DataFormatJSCell:
149 case DataFormatJSBoolean: {
150 tagGPR = info.tagGPR();
151 payloadGPR = info.payloadGPR();
153 m_gprs.lock(payloadGPR);
157 case DataFormatStorage:
158 case DataFormatDouble:
159 // this type currently never occurs
160 RELEASE_ASSERT_NOT_REACHED();
163 RELEASE_ASSERT_NOT_REACHED();
168 void SpeculativeJIT::cachedGetById(CodeOrigin origin, JSValueRegs base, JSValueRegs result, unsigned identifierNumber, JITCompiler::Jump slowPathTarget , SpillRegistersMode mode, AccessType type)
170 cachedGetById(origin, base.tagGPR(), base.payloadGPR(), result.tagGPR(), result.payloadGPR(), identifierNumber, slowPathTarget, mode, type);
173 void SpeculativeJIT::cachedGetById(
174 CodeOrigin codeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR,
175 unsigned identifierNumber, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode, AccessType type)
177 // This is a hacky fix for when the register allocator decides to alias the base payload with the result tag. This only happens
178 // in the case of GetByIdFlush, which has a relatively expensive register allocation story already so we probably don't need to
179 // trip over one move instruction.
180 if (basePayloadGPR == resultTagGPR) {
181 RELEASE_ASSERT(basePayloadGPR != resultPayloadGPR);
183 if (baseTagGPROrNone == resultPayloadGPR) {
184 m_jit.swap(basePayloadGPR, baseTagGPROrNone);
185 baseTagGPROrNone = resultTagGPR;
187 m_jit.move(basePayloadGPR, resultPayloadGPR);
188 basePayloadGPR = resultPayloadGPR;
191 RegisterSet usedRegisters = this->usedRegisters();
192 if (spillMode == DontSpill) {
193 // We've already flushed registers to the stack, we don't need to spill these.
194 usedRegisters.set(JSValueRegs(baseTagGPROrNone, basePayloadGPR), false);
195 usedRegisters.set(JSValueRegs(resultTagGPR, resultPayloadGPR), false);
198 CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
199 JITGetByIdGenerator gen(
200 m_jit.codeBlock(), codeOrigin, callSite, usedRegisters, identifierUID(identifierNumber),
201 JSValueRegs(baseTagGPROrNone, basePayloadGPR), JSValueRegs(resultTagGPR, resultPayloadGPR), type);
203 gen.generateFastPath(m_jit);
205 JITCompiler::JumpList slowCases;
206 if (slowPathTarget.isSet())
207 slowCases.append(slowPathTarget);
208 slowCases.append(gen.slowPathJump());
210 J_JITOperation_ESsiJI getByIdFunction;
211 if (type == AccessType::Get)
212 getByIdFunction = operationGetByIdOptimize;
214 getByIdFunction = operationTryGetByIdOptimize;
216 std::unique_ptr<SlowPathGenerator> slowPath;
217 if (baseTagGPROrNone == InvalidGPRReg) {
218 slowPath = slowPathCall(
219 slowCases, this, getByIdFunction,
220 JSValueRegs(resultTagGPR, resultPayloadGPR), gen.stubInfo(),
221 static_cast<int32_t>(JSValue::CellTag), basePayloadGPR,
222 identifierUID(identifierNumber));
224 slowPath = slowPathCall(
225 slowCases, this, getByIdFunction,
226 JSValueRegs(resultTagGPR, resultPayloadGPR), gen.stubInfo(), baseTagGPROrNone,
227 basePayloadGPR, identifierUID(identifierNumber));
230 m_jit.addGetById(gen, slowPath.get());
231 addSlowPathGenerator(WTFMove(slowPath));
234 void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
236 RegisterSet usedRegisters = this->usedRegisters();
237 if (spillMode == DontSpill) {
238 // We've already flushed registers to the stack, we don't need to spill these.
239 usedRegisters.set(basePayloadGPR, false);
240 usedRegisters.set(JSValueRegs(valueTagGPR, valuePayloadGPR), false);
242 CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
243 JITPutByIdGenerator gen(
244 m_jit.codeBlock(), codeOrigin, callSite, usedRegisters,
245 JSValueRegs::payloadOnly(basePayloadGPR), JSValueRegs(valueTagGPR, valuePayloadGPR),
246 scratchGPR, m_jit.ecmaModeFor(codeOrigin), putKind);
248 gen.generateFastPath(m_jit);
250 JITCompiler::JumpList slowCases;
251 if (slowPathTarget.isSet())
252 slowCases.append(slowPathTarget);
253 slowCases.append(gen.slowPathJump());
255 auto slowPath = slowPathCall(
256 slowCases, this, gen.slowPathFunction(), NoResult, gen.stubInfo(), valueTagGPR,
257 valuePayloadGPR, basePayloadGPR, identifierUID(identifierNumber));
259 m_jit.addPutById(gen, slowPath.get());
260 addSlowPathGenerator(WTFMove(slowPath));
263 void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNullOrUndefined(Edge operand)
265 JSValueOperand arg(this, operand, ManualOperandSpeculation);
266 GPRReg argTagGPR = arg.tagGPR();
267 GPRReg argPayloadGPR = arg.payloadGPR();
269 GPRTemporary resultPayload(this, Reuse, arg, PayloadWord);
270 GPRReg resultPayloadGPR = resultPayload.gpr();
272 JITCompiler::Jump notCell;
273 JITCompiler::Jump notMasqueradesAsUndefined;
274 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
275 if (!isKnownCell(operand.node()))
276 notCell = m_jit.branchIfNotCell(arg.jsValueRegs());
278 m_jit.move(TrustedImm32(0), resultPayloadGPR);
279 notMasqueradesAsUndefined = m_jit.jump();
281 GPRTemporary localGlobalObject(this);
282 GPRTemporary remoteGlobalObject(this);
284 if (!isKnownCell(operand.node()))
285 notCell = m_jit.branchIfNotCell(arg.jsValueRegs());
287 JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8(
288 JITCompiler::NonZero,
289 JITCompiler::Address(argPayloadGPR, JSCell::typeInfoFlagsOffset()),
290 JITCompiler::TrustedImm32(MasqueradesAsUndefined));
292 m_jit.move(TrustedImm32(0), resultPayloadGPR);
293 notMasqueradesAsUndefined = m_jit.jump();
295 isMasqueradesAsUndefined.link(&m_jit);
296 GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
297 GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
298 m_jit.move(JITCompiler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode->origin.semantic)), localGlobalObjectGPR);
299 m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureIDOffset()), resultPayloadGPR);
300 m_jit.loadPtr(JITCompiler::Address(resultPayloadGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
301 m_jit.compare32(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, resultPayloadGPR);
304 if (!isKnownCell(operand.node())) {
305 JITCompiler::Jump done = m_jit.jump();
307 notCell.link(&m_jit);
308 // null or undefined?
309 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
310 m_jit.or32(TrustedImm32(1), argTagGPR, resultPayloadGPR);
311 m_jit.compare32(JITCompiler::Equal, resultPayloadGPR, TrustedImm32(JSValue::NullTag), resultPayloadGPR);
316 notMasqueradesAsUndefined.link(&m_jit);
318 booleanResult(resultPayloadGPR, m_currentNode);
321 void SpeculativeJIT::nonSpeculativePeepholeBranchNullOrUndefined(Edge operand, Node* branchNode)
323 BasicBlock* taken = branchNode->branchData()->taken.block;
324 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
327 if (taken == nextBlock()) {
329 BasicBlock* tmp = taken;
334 JSValueOperand arg(this, operand, ManualOperandSpeculation);
335 GPRReg argTagGPR = arg.tagGPR();
336 GPRReg argPayloadGPR = arg.payloadGPR();
338 GPRTemporary result(this, Reuse, arg, TagWord);
339 GPRReg resultGPR = result.gpr();
341 JITCompiler::Jump notCell;
343 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
344 if (!isKnownCell(operand.node()))
345 notCell = m_jit.branchIfNotCell(arg.jsValueRegs());
347 jump(invert ? taken : notTaken, ForceJump);
349 GPRTemporary localGlobalObject(this);
350 GPRTemporary remoteGlobalObject(this);
352 if (!isKnownCell(operand.node()))
353 notCell = m_jit.branchIfNotCell(arg.jsValueRegs());
355 branchTest8(JITCompiler::Zero,
356 JITCompiler::Address(argPayloadGPR, JSCell::typeInfoFlagsOffset()),
357 JITCompiler::TrustedImm32(MasqueradesAsUndefined),
358 invert ? taken : notTaken);
360 GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
361 GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
362 m_jit.move(TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode->origin.semantic)), localGlobalObjectGPR);
363 m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureIDOffset()), resultGPR);
364 m_jit.loadPtr(JITCompiler::Address(resultGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
365 branchPtr(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, invert ? notTaken : taken);
368 if (!isKnownCell(operand.node())) {
369 jump(notTaken, ForceJump);
371 notCell.link(&m_jit);
372 // null or undefined?
373 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
374 m_jit.or32(TrustedImm32(1), argTagGPR, resultGPR);
375 branch32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultGPR, JITCompiler::TrustedImm32(JSValue::NullTag), taken);
381 void SpeculativeJIT::nonSpeculativePeepholeBranch(Node* node, Node* branchNode, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
383 BasicBlock* taken = branchNode->branchData()->taken.block;
384 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
386 JITCompiler::ResultCondition callResultCondition = JITCompiler::NonZero;
388 // The branch instruction will branch to the taken block.
389 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
390 if (taken == nextBlock()) {
391 cond = JITCompiler::invert(cond);
392 callResultCondition = JITCompiler::Zero;
393 BasicBlock* tmp = taken;
398 JSValueOperand arg1(this, node->child1());
399 JSValueOperand arg2(this, node->child2());
400 GPRReg arg1TagGPR = arg1.tagGPR();
401 GPRReg arg1PayloadGPR = arg1.payloadGPR();
402 GPRReg arg2TagGPR = arg2.tagGPR();
403 GPRReg arg2PayloadGPR = arg2.payloadGPR();
405 JITCompiler::JumpList slowPath;
407 if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) {
408 GPRFlushedCallResult result(this);
409 GPRReg resultGPR = result.gpr();
415 callOperation(helperFunction, resultGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
416 m_jit.exceptionCheck();
418 branchTest32(callResultCondition, resultGPR, taken);
420 GPRTemporary result(this);
421 GPRReg resultGPR = result.gpr();
426 if (!isKnownInteger(node->child1().node()))
427 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg1TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
428 if (!isKnownInteger(node->child2().node()))
429 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg2TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
431 branch32(cond, arg1PayloadGPR, arg2PayloadGPR, taken);
433 if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node())) {
434 jump(notTaken, ForceJump);
436 slowPath.link(&m_jit);
438 silentSpillAllRegisters(resultGPR);
439 callOperation(helperFunction, resultGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
440 m_jit.exceptionCheck();
441 silentFillAllRegisters(resultGPR);
443 branchTest32(callResultCondition, resultGPR, taken);
449 m_indexInBlock = m_block->size() - 1;
450 m_currentNode = branchNode;
453 template<typename JumpType>
454 class CompareAndBoxBooleanSlowPathGenerator
455 : public CallSlowPathGenerator<JumpType, S_JITOperation_EJJ, GPRReg> {
457 CompareAndBoxBooleanSlowPathGenerator(
458 JumpType from, SpeculativeJIT* jit,
459 S_JITOperation_EJJ function, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload,
460 GPRReg arg2Tag, GPRReg arg2Payload)
461 : CallSlowPathGenerator<JumpType, S_JITOperation_EJJ, GPRReg>(
462 from, jit, function, NeedToSpill, ExceptionCheckRequirement::CheckNeeded, result)
464 , m_arg1Payload(arg1Payload)
466 , m_arg2Payload(arg2Payload)
471 virtual void generateInternal(SpeculativeJIT* jit)
476 this->m_function, this->m_result, m_arg1Tag, m_arg1Payload, m_arg2Tag,
478 jit->m_jit.and32(JITCompiler::TrustedImm32(1), this->m_result);
484 GPRReg m_arg1Payload;
486 GPRReg m_arg2Payload;
489 void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node* node, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
491 JSValueOperand arg1(this, node->child1());
492 JSValueOperand arg2(this, node->child2());
493 GPRReg arg1TagGPR = arg1.tagGPR();
494 GPRReg arg1PayloadGPR = arg1.payloadGPR();
495 GPRReg arg2TagGPR = arg2.tagGPR();
496 GPRReg arg2PayloadGPR = arg2.payloadGPR();
498 JITCompiler::JumpList slowPath;
500 if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) {
501 GPRFlushedCallResult result(this);
502 GPRReg resultPayloadGPR = result.gpr();
508 callOperation(helperFunction, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
509 m_jit.exceptionCheck();
511 booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
513 GPRTemporary resultPayload(this, Reuse, arg1, PayloadWord);
514 GPRReg resultPayloadGPR = resultPayload.gpr();
519 if (!isKnownInteger(node->child1().node()))
520 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg1TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
521 if (!isKnownInteger(node->child2().node()))
522 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg2TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
524 m_jit.compare32(cond, arg1PayloadGPR, arg2PayloadGPR, resultPayloadGPR);
526 if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node())) {
527 addSlowPathGenerator(std::make_unique<CompareAndBoxBooleanSlowPathGenerator<JITCompiler::JumpList>>(
528 slowPath, this, helperFunction, resultPayloadGPR, arg1TagGPR,
529 arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR));
532 booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
536 void SpeculativeJIT::nonSpeculativePeepholeStrictEq(Node* node, Node* branchNode, bool invert)
538 BasicBlock* taken = branchNode->branchData()->taken.block;
539 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
541 // The branch instruction will branch to the taken block.
542 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
543 if (taken == nextBlock()) {
545 BasicBlock* tmp = taken;
550 JSValueOperand arg1(this, node->child1());
551 JSValueOperand arg2(this, node->child2());
552 GPRReg arg1TagGPR = arg1.tagGPR();
553 GPRReg arg1PayloadGPR = arg1.payloadGPR();
554 GPRReg arg2TagGPR = arg2.tagGPR();
555 GPRReg arg2PayloadGPR = arg2.payloadGPR();
557 GPRTemporary resultPayload(this, Reuse, arg1, PayloadWord);
558 GPRReg resultPayloadGPR = resultPayload.gpr();
563 if (isKnownCell(node->child1().node()) && isKnownCell(node->child2().node())) {
564 // see if we get lucky: if the arguments are cells and they reference the same
565 // cell, then they must be strictly equal.
566 branchPtr(JITCompiler::Equal, arg1PayloadGPR, arg2PayloadGPR, invert ? notTaken : taken);
568 silentSpillAllRegisters(resultPayloadGPR);
569 callOperation(operationCompareStrictEqCell, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
570 m_jit.exceptionCheck();
571 silentFillAllRegisters(resultPayloadGPR);
573 branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, resultPayloadGPR, taken);
575 // FIXME: Add fast paths for twoCells, number etc.
577 silentSpillAllRegisters(resultPayloadGPR);
578 callOperation(operationCompareStrictEq, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
579 m_jit.exceptionCheck();
580 silentFillAllRegisters(resultPayloadGPR);
582 branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, resultPayloadGPR, taken);
588 void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node* node, bool invert)
590 JSValueOperand arg1(this, node->child1());
591 JSValueOperand arg2(this, node->child2());
592 GPRReg arg1TagGPR = arg1.tagGPR();
593 GPRReg arg1PayloadGPR = arg1.payloadGPR();
594 GPRReg arg2TagGPR = arg2.tagGPR();
595 GPRReg arg2PayloadGPR = arg2.payloadGPR();
597 GPRTemporary resultPayload(this, Reuse, arg1, PayloadWord);
598 GPRReg resultPayloadGPR = resultPayload.gpr();
603 if (isKnownCell(node->child1().node()) && isKnownCell(node->child2().node())) {
604 // see if we get lucky: if the arguments are cells and they reference the same
605 // cell, then they must be strictly equal.
606 // FIXME: this should flush registers instead of silent spill/fill.
607 JITCompiler::Jump notEqualCase = m_jit.branchPtr(JITCompiler::NotEqual, arg1PayloadGPR, arg2PayloadGPR);
609 m_jit.move(JITCompiler::TrustedImm32(!invert), resultPayloadGPR);
610 JITCompiler::Jump done = m_jit.jump();
612 notEqualCase.link(&m_jit);
614 silentSpillAllRegisters(resultPayloadGPR);
615 callOperation(operationCompareStrictEqCell, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
616 m_jit.exceptionCheck();
617 silentFillAllRegisters(resultPayloadGPR);
619 m_jit.andPtr(JITCompiler::TrustedImm32(1), resultPayloadGPR);
623 // FIXME: Add fast paths.
625 silentSpillAllRegisters(resultPayloadGPR);
626 callOperation(operationCompareStrictEq, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
627 silentFillAllRegisters(resultPayloadGPR);
628 m_jit.exceptionCheck();
630 m_jit.andPtr(JITCompiler::TrustedImm32(1), resultPayloadGPR);
633 booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
636 void SpeculativeJIT::compileMiscStrictEq(Node* node)
638 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
639 JSValueOperand op2(this, node->child2(), ManualOperandSpeculation);
640 GPRTemporary result(this);
642 if (node->child1().useKind() == MiscUse)
643 speculateMisc(node->child1(), op1.jsValueRegs());
644 if (node->child2().useKind() == MiscUse)
645 speculateMisc(node->child2(), op2.jsValueRegs());
647 m_jit.move(TrustedImm32(0), result.gpr());
648 JITCompiler::Jump notEqual = m_jit.branch32(JITCompiler::NotEqual, op1.tagGPR(), op2.tagGPR());
649 m_jit.compare32(JITCompiler::Equal, op1.payloadGPR(), op2.payloadGPR(), result.gpr());
650 notEqual.link(&m_jit);
651 booleanResult(result.gpr(), node);
654 void SpeculativeJIT::emitCall(Node* node)
656 CallLinkInfo::CallType callType;
657 bool isVarargs = false;
658 bool isForwardVarargs = false;
660 bool isEmulatedTail = false;
661 switch (node->op()) {
664 callType = CallLinkInfo::Call;
667 callType = CallLinkInfo::TailCall;
670 case TailCallInlinedCaller:
671 callType = CallLinkInfo::Call;
672 isEmulatedTail = true;
675 callType = CallLinkInfo::Construct;
678 callType = CallLinkInfo::CallVarargs;
681 case TailCallVarargs:
682 callType = CallLinkInfo::TailCallVarargs;
686 case TailCallVarargsInlinedCaller:
687 callType = CallLinkInfo::CallVarargs;
689 isEmulatedTail = true;
691 case ConstructVarargs:
692 callType = CallLinkInfo::ConstructVarargs;
695 case CallForwardVarargs:
696 callType = CallLinkInfo::CallVarargs;
697 isForwardVarargs = true;
699 case TailCallForwardVarargs:
700 callType = CallLinkInfo::TailCallVarargs;
702 isForwardVarargs = true;
704 case TailCallForwardVarargsInlinedCaller:
705 callType = CallLinkInfo::CallVarargs;
706 isEmulatedTail = true;
707 isForwardVarargs = true;
709 case ConstructForwardVarargs:
710 callType = CallLinkInfo::ConstructVarargs;
711 isForwardVarargs = true;
714 DFG_CRASH(m_jit.graph(), node, "bad node type");
718 Edge calleeEdge = m_jit.graph().child(node, 0);
719 GPRReg calleeTagGPR = InvalidGPRReg;
720 GPRReg calleePayloadGPR = InvalidGPRReg;
721 CallFrameShuffleData shuffleData;
723 // Gotta load the arguments somehow. Varargs is trickier.
724 if (isVarargs || isForwardVarargs) {
725 CallVarargsData* data = node->callVarargsData();
728 unsigned numUsedStackSlots = m_jit.graph().m_nextMachineLocal;
730 if (isForwardVarargs) {
739 scratchGPR1 = JITCompiler::selectScratchGPR();
740 scratchGPR2 = JITCompiler::selectScratchGPR(scratchGPR1);
741 scratchGPR3 = JITCompiler::selectScratchGPR(scratchGPR1, scratchGPR2);
743 m_jit.move(TrustedImm32(numUsedStackSlots), scratchGPR2);
744 JITCompiler::JumpList slowCase;
745 InlineCallFrame* inlineCallFrame;
747 inlineCallFrame = node->child3()->origin.semantic.inlineCallFrame;
749 inlineCallFrame = node->origin.semantic.inlineCallFrame;
750 emitSetupVarargsFrameFastCase(m_jit, scratchGPR2, scratchGPR1, scratchGPR2, scratchGPR3, inlineCallFrame, data->firstVarArgOffset, slowCase);
751 JITCompiler::Jump done = m_jit.jump();
752 slowCase.link(&m_jit);
753 callOperation(operationThrowStackOverflowForVarargs);
754 m_jit.exceptionCheck();
755 m_jit.abortWithReason(DFGVarargsThrowingPathDidNotThrow);
757 resultGPR = scratchGPR2;
759 GPRReg argumentsPayloadGPR;
760 GPRReg argumentsTagGPR;
765 auto loadArgumentsGPR = [&] (GPRReg reservedGPR) {
766 if (reservedGPR != InvalidGPRReg)
768 JSValueOperand arguments(this, node->child3());
769 argumentsTagGPR = arguments.tagGPR();
770 argumentsPayloadGPR = arguments.payloadGPR();
771 if (reservedGPR != InvalidGPRReg)
775 scratchGPR1 = JITCompiler::selectScratchGPR(argumentsPayloadGPR, argumentsTagGPR, reservedGPR);
776 scratchGPR2 = JITCompiler::selectScratchGPR(argumentsPayloadGPR, argumentsTagGPR, scratchGPR1, reservedGPR);
777 scratchGPR3 = JITCompiler::selectScratchGPR(argumentsPayloadGPR, argumentsTagGPR, scratchGPR1, scratchGPR2, reservedGPR);
780 loadArgumentsGPR(InvalidGPRReg);
782 DFG_ASSERT(m_jit.graph(), node, isFlushed());
784 // Right now, arguments is in argumentsTagGPR/argumentsPayloadGPR and the register file is
786 callOperation(operationSizeFrameForVarargs, GPRInfo::returnValueGPR, argumentsTagGPR, argumentsPayloadGPR, numUsedStackSlots, data->firstVarArgOffset);
787 m_jit.exceptionCheck();
789 // Now we have the argument count of the callee frame, but we've lost the arguments operand.
790 // Reconstruct the arguments operand while preserving the callee frame.
791 loadArgumentsGPR(GPRInfo::returnValueGPR);
792 m_jit.move(TrustedImm32(numUsedStackSlots), scratchGPR1);
793 emitSetVarargsFrame(m_jit, GPRInfo::returnValueGPR, false, scratchGPR1, scratchGPR1);
794 m_jit.addPtr(TrustedImm32(-(sizeof(CallerFrameAndPC) + WTF::roundUpToMultipleOf(stackAlignmentBytes(), 6 * sizeof(void*)))), scratchGPR1, JITCompiler::stackPointerRegister);
796 callOperation(operationSetupVarargsFrame, GPRInfo::returnValueGPR, scratchGPR1, argumentsTagGPR, argumentsPayloadGPR, data->firstVarArgOffset, GPRInfo::returnValueGPR);
797 m_jit.exceptionCheck();
798 resultGPR = GPRInfo::returnValueGPR;
801 m_jit.addPtr(TrustedImm32(sizeof(CallerFrameAndPC)), resultGPR, JITCompiler::stackPointerRegister);
803 DFG_ASSERT(m_jit.graph(), node, isFlushed());
805 // We don't need the arguments array anymore.
809 // Now set up the "this" argument.
810 JSValueOperand thisArgument(this, node->child2());
811 GPRReg thisArgumentTagGPR = thisArgument.tagGPR();
812 GPRReg thisArgumentPayloadGPR = thisArgument.payloadGPR();
815 m_jit.store32(thisArgumentTagGPR, JITCompiler::calleeArgumentTagSlot(0));
816 m_jit.store32(thisArgumentPayloadGPR, JITCompiler::calleeArgumentPayloadSlot(0));
818 // The call instruction's first child is either the function (normal call) or the
819 // receiver (method call). subsequent children are the arguments.
820 int numPassedArgs = node->numChildren() - 1;
822 if (node->op() == TailCall) {
823 JSValueOperand callee(this, calleeEdge);
824 calleeTagGPR = callee.tagGPR();
825 calleePayloadGPR = callee.payloadGPR();
828 shuffleData.numLocals = m_jit.graph().frameRegisterCount();
829 shuffleData.callee = ValueRecovery::inPair(calleeTagGPR, calleePayloadGPR);
830 shuffleData.args.resize(numPassedArgs);
832 for (int i = 0; i < numPassedArgs; ++i) {
833 Edge argEdge = m_jit.graph().varArgChild(node, i + 1);
834 GenerationInfo& info = generationInfo(argEdge.node());
836 shuffleData.args[i] = info.recovery(argEdge->virtualRegister());
839 m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), m_jit.calleeFramePayloadSlot(CallFrameSlot::argumentCount));
841 for (int i = 0; i < numPassedArgs; i++) {
842 Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
843 JSValueOperand arg(this, argEdge);
844 GPRReg argTagGPR = arg.tagGPR();
845 GPRReg argPayloadGPR = arg.payloadGPR();
848 m_jit.store32(argTagGPR, m_jit.calleeArgumentTagSlot(i));
849 m_jit.store32(argPayloadGPR, m_jit.calleeArgumentPayloadSlot(i));
854 if (node->op() != TailCall) {
855 JSValueOperand callee(this, calleeEdge);
856 calleeTagGPR = callee.tagGPR();
857 calleePayloadGPR = callee.payloadGPR();
859 m_jit.store32(calleePayloadGPR, m_jit.calleeFramePayloadSlot(CallFrameSlot::callee));
860 m_jit.store32(calleeTagGPR, m_jit.calleeFrameTagSlot(CallFrameSlot::callee));
866 GPRFlushedCallResult resultPayload(this);
867 GPRFlushedCallResult2 resultTag(this);
868 GPRReg resultPayloadGPR = resultPayload.gpr();
869 GPRReg resultTagGPR = resultTag.gpr();
871 JITCompiler::DataLabelPtr targetToCheck;
872 JITCompiler::JumpList slowPath;
874 CodeOrigin staticOrigin = node->origin.semantic;
875 ASSERT(!isTail || !staticOrigin.inlineCallFrame || !staticOrigin.inlineCallFrame->getCallerSkippingTailCalls());
876 ASSERT(!isEmulatedTail || (staticOrigin.inlineCallFrame && staticOrigin.inlineCallFrame->getCallerSkippingTailCalls()));
877 CodeOrigin dynamicOrigin =
878 isEmulatedTail ? *staticOrigin.inlineCallFrame->getCallerSkippingTailCalls() : staticOrigin;
879 CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(dynamicOrigin, m_stream->size());
880 m_jit.emitStoreCallSiteIndex(callSite);
882 CallLinkInfo* info = m_jit.codeBlock()->addCallLinkInfo();
883 info->setUpCall(callType, node->origin.semantic, calleePayloadGPR);
885 auto setResultAndResetStack = [&] () {
886 m_jit.setupResults(resultPayloadGPR, resultTagGPR);
888 jsValueResult(resultTagGPR, resultPayloadGPR, node, DataFormatJS, UseChildrenCalledExplicitly);
889 // After the calls are done, we need to reestablish our stack
890 // pointer. We rely on this for varargs calls, calls with arity
891 // mismatch (the callframe is slided) and tail calls.
892 m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister);
895 if (node->op() == CallEval) {
896 // We want to call operationCallEval but we don't want to overwrite the parameter area in
897 // which we have created a prototypical eval call frame. This means that we have to
898 // subtract stack to make room for the call. Lucky for us, at this point we have the whole
899 // register file to ourselves.
901 m_jit.addPtr(TrustedImm32(-static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC))), JITCompiler::stackPointerRegister, GPRInfo::regT0);
902 m_jit.storePtr(GPRInfo::callFrameRegister, JITCompiler::Address(GPRInfo::regT0, CallFrame::callerFrameOffset()));
904 // Now we need to make room for:
905 // - The caller frame and PC of a call to operationCallEval.
906 // - Potentially two arguments on the stack.
907 unsigned requiredBytes = sizeof(CallerFrameAndPC) + sizeof(ExecState*) * 2;
908 requiredBytes = WTF::roundUpToMultipleOf(stackAlignmentBytes(), requiredBytes);
909 m_jit.subPtr(TrustedImm32(requiredBytes), JITCompiler::stackPointerRegister);
910 m_jit.setupArgumentsWithExecState(GPRInfo::regT0);
911 prepareForExternalCall();
912 m_jit.appendCall(operationCallEval);
913 m_jit.exceptionCheck();
914 JITCompiler::Jump done = m_jit.branch32(JITCompiler::NotEqual, GPRInfo::returnValueGPR2, TrustedImm32(JSValue::EmptyValueTag));
916 // This is the part where we meant to make a normal call. Oops.
917 m_jit.addPtr(TrustedImm32(requiredBytes), JITCompiler::stackPointerRegister);
918 m_jit.load32(JITCompiler::calleeFrameSlot(CallFrameSlot::callee).withOffset(PayloadOffset), GPRInfo::regT0);
919 m_jit.load32(JITCompiler::calleeFrameSlot(CallFrameSlot::callee).withOffset(TagOffset), GPRInfo::regT1);
920 m_jit.emitDumbVirtualCall(info);
923 setResultAndResetStack();
927 slowPath.append(m_jit.branchIfNotCell(JSValueRegs(calleeTagGPR, calleePayloadGPR)));
928 slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
931 if (node->op() == TailCall) {
932 info->setFrameShuffleData(shuffleData);
933 CallFrameShuffler(m_jit, shuffleData).prepareForTailCall();
935 m_jit.emitRestoreCalleeSaves();
936 m_jit.prepareForTailCallSlow();
940 JITCompiler::Call fastCall = isTail ? m_jit.nearTailCall() : m_jit.nearCall();
942 JITCompiler::Jump done = m_jit.jump();
944 slowPath.link(&m_jit);
946 if (node->op() == TailCall) {
947 CallFrameShuffler callFrameShuffler(m_jit, shuffleData);
948 callFrameShuffler.setCalleeJSValueRegs(JSValueRegs(
949 GPRInfo::regT1, GPRInfo::regT0));
950 callFrameShuffler.prepareForSlowPath();
952 // Callee payload needs to be in regT0, tag in regT1
953 if (calleeTagGPR == GPRInfo::regT0) {
954 if (calleePayloadGPR == GPRInfo::regT1)
955 m_jit.swap(GPRInfo::regT1, GPRInfo::regT0);
957 m_jit.move(calleeTagGPR, GPRInfo::regT1);
958 m_jit.move(calleePayloadGPR, GPRInfo::regT0);
961 m_jit.move(calleePayloadGPR, GPRInfo::regT0);
962 m_jit.move(calleeTagGPR, GPRInfo::regT1);
966 m_jit.emitRestoreCalleeSaves();
969 m_jit.move(MacroAssembler::TrustedImmPtr(info), GPRInfo::regT2);
970 JITCompiler::Call slowCall = m_jit.nearCall();
975 m_jit.abortWithReason(JITDidReturnFromTailCall);
977 setResultAndResetStack();
979 m_jit.addJSCall(fastCall, slowCall, targetToCheck, info);
982 template<bool strict>
983 GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnFormat)
985 AbstractValue& value = m_state.forNode(edge);
986 SpeculatedType type = value.m_type;
987 ASSERT(edge.useKind() != KnownInt32Use || !(value.m_type & ~SpecInt32Only));
989 m_interpreter.filter(value, SpecInt32Only);
990 if (value.isClear()) {
991 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
992 returnFormat = DataFormatInt32;
996 VirtualRegister virtualRegister = edge->virtualRegister();
997 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
999 switch (info.registerFormat()) {
1000 case DataFormatNone: {
1001 if (edge->hasConstant()) {
1002 ASSERT(edge->isInt32Constant());
1003 GPRReg gpr = allocate();
1004 m_jit.move(MacroAssembler::Imm32(edge->asInt32()), gpr);
1005 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1006 info.fillInt32(*m_stream, gpr);
1007 returnFormat = DataFormatInt32;
1011 DataFormat spillFormat = info.spillFormat();
1013 ASSERT_UNUSED(spillFormat, (spillFormat & DataFormatJS) || spillFormat == DataFormatInt32);
1015 // If we know this was spilled as an integer we can fill without checking.
1016 if (type & ~SpecInt32Only)
1017 speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), edge, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)));
1019 GPRReg gpr = allocate();
1020 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
1021 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
1022 info.fillInt32(*m_stream, gpr);
1023 returnFormat = DataFormatInt32;
1027 case DataFormatJSInt32:
1028 case DataFormatJS: {
1029 // Check the value is an integer.
1030 GPRReg tagGPR = info.tagGPR();
1031 GPRReg payloadGPR = info.payloadGPR();
1032 m_gprs.lock(tagGPR);
1033 m_gprs.lock(payloadGPR);
1034 if (type & ~SpecInt32Only)
1035 speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), edge, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::Int32Tag)));
1036 m_gprs.unlock(tagGPR);
1037 m_gprs.release(tagGPR);
1038 m_gprs.release(payloadGPR);
1039 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderInteger);
1040 info.fillInt32(*m_stream, payloadGPR);
1041 // If !strict we're done, return.
1042 returnFormat = DataFormatInt32;
1046 case DataFormatInt32: {
1047 GPRReg gpr = info.gpr();
1049 returnFormat = DataFormatInt32;
1053 case DataFormatCell:
1054 case DataFormatBoolean:
1055 case DataFormatJSDouble:
1056 case DataFormatJSCell:
1057 case DataFormatJSBoolean:
1058 case DataFormatDouble:
1059 case DataFormatStorage:
1061 RELEASE_ASSERT_NOT_REACHED();
1062 return InvalidGPRReg;
1066 GPRReg SpeculativeJIT::fillSpeculateInt32(Edge edge, DataFormat& returnFormat)
1068 return fillSpeculateInt32Internal<false>(edge, returnFormat);
1071 GPRReg SpeculativeJIT::fillSpeculateInt32Strict(Edge edge)
1073 DataFormat mustBeDataFormatInt32;
1074 GPRReg result = fillSpeculateInt32Internal<true>(edge, mustBeDataFormatInt32);
1075 ASSERT(mustBeDataFormatInt32 == DataFormatInt32);
1079 FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge)
1081 ASSERT(isDouble(edge.useKind()));
1082 ASSERT(edge->hasDoubleResult());
1083 VirtualRegister virtualRegister = edge->virtualRegister();
1084 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
1086 if (info.registerFormat() == DataFormatNone) {
1088 if (edge->hasConstant()) {
1089 RELEASE_ASSERT(edge->isNumberConstant());
1090 FPRReg fpr = fprAllocate();
1091 m_jit.loadDouble(TrustedImmPtr(m_jit.addressOfDoubleConstant(edge.node())), fpr);
1092 m_fprs.retain(fpr, virtualRegister, SpillOrderConstant);
1093 info.fillDouble(*m_stream, fpr);
1097 RELEASE_ASSERT(info.spillFormat() == DataFormatDouble);
1098 FPRReg fpr = fprAllocate();
1099 m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
1100 m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
1101 info.fillDouble(*m_stream, fpr);
1105 RELEASE_ASSERT(info.registerFormat() == DataFormatDouble);
1106 FPRReg fpr = info.fpr();
1111 GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge)
1113 AbstractValue& value = m_state.forNode(edge);
1114 SpeculatedType type = value.m_type;
1115 ASSERT((edge.useKind() != KnownCellUse && edge.useKind() != KnownStringUse) || !(value.m_type & ~SpecCell));
1117 m_interpreter.filter(value, SpecCell);
1118 if (value.isClear()) {
1119 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
1123 VirtualRegister virtualRegister = edge->virtualRegister();
1124 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
1126 switch (info.registerFormat()) {
1127 case DataFormatNone: {
1128 if (edge->hasConstant()) {
1129 JSValue jsValue = edge->asJSValue();
1130 GPRReg gpr = allocate();
1131 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1132 m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr);
1133 info.fillCell(*m_stream, gpr);
1137 ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatCell);
1138 if (type & ~SpecCell) {
1141 JSValueSource(JITCompiler::addressFor(virtualRegister)),
1144 MacroAssembler::NotEqual,
1145 JITCompiler::tagFor(virtualRegister),
1146 TrustedImm32(JSValue::CellTag)));
1148 GPRReg gpr = allocate();
1149 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
1150 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
1151 info.fillCell(*m_stream, gpr);
1155 case DataFormatCell: {
1156 GPRReg gpr = info.gpr();
1161 case DataFormatJSCell:
1162 case DataFormatJS: {
1163 GPRReg tagGPR = info.tagGPR();
1164 GPRReg payloadGPR = info.payloadGPR();
1165 m_gprs.lock(tagGPR);
1166 m_gprs.lock(payloadGPR);
1167 if (type & ~SpecCell) {
1169 BadType, JSValueRegs(tagGPR, payloadGPR), edge,
1170 m_jit.branchIfNotCell(info.jsValueRegs()));
1172 m_gprs.unlock(tagGPR);
1173 m_gprs.release(tagGPR);
1174 m_gprs.release(payloadGPR);
1175 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderCell);
1176 info.fillCell(*m_stream, payloadGPR);
1180 case DataFormatJSInt32:
1181 case DataFormatInt32:
1182 case DataFormatJSDouble:
1183 case DataFormatJSBoolean:
1184 case DataFormatBoolean:
1185 case DataFormatDouble:
1186 case DataFormatStorage:
1187 RELEASE_ASSERT_NOT_REACHED();
1190 RELEASE_ASSERT_NOT_REACHED();
1191 return InvalidGPRReg;
1195 GPRReg SpeculativeJIT::fillSpeculateBoolean(Edge edge)
1197 AbstractValue& value = m_state.forNode(edge);
1198 SpeculatedType type = value.m_type;
1199 ASSERT(edge.useKind() != KnownBooleanUse || !(value.m_type & ~SpecBoolean));
1201 m_interpreter.filter(value, SpecBoolean);
1202 if (value.isClear()) {
1203 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
1207 VirtualRegister virtualRegister = edge->virtualRegister();
1208 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
1210 switch (info.registerFormat()) {
1211 case DataFormatNone: {
1212 if (edge->hasConstant()) {
1213 JSValue jsValue = edge->asJSValue();
1214 GPRReg gpr = allocate();
1215 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1216 m_jit.move(MacroAssembler::TrustedImm32(jsValue.asBoolean()), gpr);
1217 info.fillBoolean(*m_stream, gpr);
1221 ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatBoolean);
1223 if (type & ~SpecBoolean)
1224 speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), edge, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)));
1226 GPRReg gpr = allocate();
1227 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
1228 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
1229 info.fillBoolean(*m_stream, gpr);
1233 case DataFormatBoolean: {
1234 GPRReg gpr = info.gpr();
1239 case DataFormatJSBoolean:
1240 case DataFormatJS: {
1241 GPRReg tagGPR = info.tagGPR();
1242 GPRReg payloadGPR = info.payloadGPR();
1243 m_gprs.lock(tagGPR);
1244 m_gprs.lock(payloadGPR);
1245 if (type & ~SpecBoolean)
1246 speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), edge, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::BooleanTag)));
1248 m_gprs.unlock(tagGPR);
1249 m_gprs.release(tagGPR);
1250 m_gprs.release(payloadGPR);
1251 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderBoolean);
1252 info.fillBoolean(*m_stream, payloadGPR);
1256 case DataFormatJSInt32:
1257 case DataFormatInt32:
1258 case DataFormatJSDouble:
1259 case DataFormatJSCell:
1260 case DataFormatCell:
1261 case DataFormatDouble:
1262 case DataFormatStorage:
1263 RELEASE_ASSERT_NOT_REACHED();
1266 RELEASE_ASSERT_NOT_REACHED();
1267 return InvalidGPRReg;
1271 void SpeculativeJIT::compileBaseValueStoreBarrier(Edge& baseEdge, Edge& valueEdge)
1273 ASSERT(!isKnownNotCell(valueEdge.node()));
1275 SpeculateCellOperand base(this, baseEdge);
1276 JSValueOperand value(this, valueEdge);
1277 GPRTemporary scratch1(this);
1278 GPRTemporary scratch2(this);
1280 writeBarrier(base.gpr(), value.tagGPR(), valueEdge, scratch1.gpr(), scratch2.gpr());
1283 void SpeculativeJIT::compileObjectEquality(Node* node)
1285 SpeculateCellOperand op1(this, node->child1());
1286 SpeculateCellOperand op2(this, node->child2());
1287 GPRReg op1GPR = op1.gpr();
1288 GPRReg op2GPR = op2.gpr();
1290 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
1292 JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchIfNotObject(op1GPR));
1294 JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchIfNotObject(op2GPR));
1297 JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchIfNotObject(op1GPR));
1298 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
1300 MacroAssembler::NonZero,
1301 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
1302 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1305 JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchIfNotObject(op2GPR));
1306 speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
1308 MacroAssembler::NonZero,
1309 MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()),
1310 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1313 GPRTemporary resultPayload(this, Reuse, op2);
1314 GPRReg resultPayloadGPR = resultPayload.gpr();
1316 MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2GPR);
1317 m_jit.move(TrustedImm32(1), resultPayloadGPR);
1318 MacroAssembler::Jump done = m_jit.jump();
1319 falseCase.link(&m_jit);
1320 m_jit.move(TrustedImm32(0), resultPayloadGPR);
1323 booleanResult(resultPayloadGPR, node);
1326 void SpeculativeJIT::compileObjectStrictEquality(Edge objectChild, Edge otherChild)
1328 SpeculateCellOperand op1(this, objectChild);
1329 JSValueOperand op2(this, otherChild);
1331 GPRReg op1GPR = op1.gpr();
1332 GPRReg op2GPR = op2.payloadGPR();
1334 DFG_TYPE_CHECK(JSValueSource::unboxedCell(op1GPR), objectChild, SpecObject, m_jit.branchIfNotObject(op1GPR));
1336 GPRTemporary resultPayload(this, Reuse, op1);
1337 GPRReg resultPayloadGPR = resultPayload.gpr();
1339 MacroAssembler::Jump op2CellJump = m_jit.branchIfCell(op2.jsValueRegs());
1341 m_jit.move(TrustedImm32(0), resultPayloadGPR);
1342 MacroAssembler::Jump op2NotCellJump = m_jit.jump();
1344 // At this point we know that we can perform a straight-forward equality comparison on pointer
1345 // values because we are doing strict equality.
1346 op2CellJump.link(&m_jit);
1347 m_jit.compare32(MacroAssembler::Equal, op1GPR, op2GPR, resultPayloadGPR);
1349 op2NotCellJump.link(&m_jit);
1350 booleanResult(resultPayloadGPR, m_currentNode);
1353 void SpeculativeJIT::compilePeepHoleObjectStrictEquality(Edge objectChild, Edge otherChild, Node* branchNode)
1355 BasicBlock* taken = branchNode->branchData()->taken.block;
1356 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1358 SpeculateCellOperand op1(this, objectChild);
1359 JSValueOperand op2(this, otherChild);
1361 GPRReg op1GPR = op1.gpr();
1362 GPRReg op2GPR = op2.payloadGPR();
1364 DFG_TYPE_CHECK(JSValueSource::unboxedCell(op1GPR), objectChild, SpecObject, m_jit.branchIfNotObject(op1GPR));
1366 branch32(MacroAssembler::NotEqual, op2.tagGPR(), TrustedImm32(JSValue::CellTag), notTaken);
1368 if (taken == nextBlock()) {
1369 branch32(MacroAssembler::NotEqual, op1GPR, op2GPR, notTaken);
1372 branch32(MacroAssembler::Equal, op1GPR, op2GPR, taken);
1377 void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild)
1379 SpeculateCellOperand op1(this, leftChild);
1380 JSValueOperand op2(this, rightChild, ManualOperandSpeculation);
1381 GPRTemporary result(this);
1383 GPRReg op1GPR = op1.gpr();
1384 GPRReg op2TagGPR = op2.tagGPR();
1385 GPRReg op2PayloadGPR = op2.payloadGPR();
1386 GPRReg resultGPR = result.gpr();
1388 bool masqueradesAsUndefinedWatchpointValid =
1389 masqueradesAsUndefinedWatchpointIsStillValid();
1391 if (masqueradesAsUndefinedWatchpointValid) {
1393 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR));
1396 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR));
1397 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
1399 MacroAssembler::NonZero,
1400 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
1401 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1405 // It seems that most of the time when programs do a == b where b may be either null/undefined
1406 // or an object, b is usually an object. Balance the branches to make that case fast.
1407 MacroAssembler::Jump rightNotCell = m_jit.branchIfNotCell(op2.jsValueRegs());
1409 // We know that within this branch, rightChild must be a cell.
1410 if (masqueradesAsUndefinedWatchpointValid) {
1412 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchIfNotObject(op2PayloadGPR));
1415 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchIfNotObject(op2PayloadGPR));
1416 speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
1418 MacroAssembler::NonZero,
1419 MacroAssembler::Address(op2PayloadGPR, JSCell::typeInfoFlagsOffset()),
1420 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1423 // At this point we know that we can perform a straight-forward equality comparison on pointer
1424 // values because both left and right are pointers to objects that have no special equality
1426 MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2PayloadGPR);
1427 MacroAssembler::Jump trueCase = m_jit.jump();
1429 rightNotCell.link(&m_jit);
1431 // We know that within this branch, rightChild must not be a cell. Check if that is enough to
1432 // prove that it is either null or undefined.
1433 if (needsTypeCheck(rightChild, SpecCell | SpecOther)) {
1434 m_jit.or32(TrustedImm32(1), op2TagGPR, resultGPR);
1437 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, SpecCell | SpecOther,
1439 MacroAssembler::NotEqual, resultGPR,
1440 MacroAssembler::TrustedImm32(JSValue::NullTag)));
1443 falseCase.link(&m_jit);
1444 m_jit.move(TrustedImm32(0), resultGPR);
1445 MacroAssembler::Jump done = m_jit.jump();
1446 trueCase.link(&m_jit);
1447 m_jit.move(TrustedImm32(1), resultGPR);
1450 booleanResult(resultGPR, m_currentNode);
1453 void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild, Node* branchNode)
1455 BasicBlock* taken = branchNode->branchData()->taken.block;
1456 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1458 SpeculateCellOperand op1(this, leftChild);
1459 JSValueOperand op2(this, rightChild, ManualOperandSpeculation);
1460 GPRTemporary result(this);
1462 GPRReg op1GPR = op1.gpr();
1463 GPRReg op2TagGPR = op2.tagGPR();
1464 GPRReg op2PayloadGPR = op2.payloadGPR();
1465 GPRReg resultGPR = result.gpr();
1467 bool masqueradesAsUndefinedWatchpointValid =
1468 masqueradesAsUndefinedWatchpointIsStillValid();
1470 if (masqueradesAsUndefinedWatchpointValid) {
1472 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR));
1475 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR));
1476 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
1478 MacroAssembler::NonZero,
1479 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
1480 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1483 // It seems that most of the time when programs do a == b where b may be either null/undefined
1484 // or an object, b is usually an object. Balance the branches to make that case fast.
1485 MacroAssembler::Jump rightNotCell = m_jit.branchIfNotCell(op2.jsValueRegs());
1487 // We know that within this branch, rightChild must be a cell.
1488 if (masqueradesAsUndefinedWatchpointValid) {
1490 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
1491 m_jit.branchIfNotObject(op2PayloadGPR));
1494 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
1495 m_jit.branchIfNotObject(op2PayloadGPR));
1496 speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
1498 MacroAssembler::NonZero,
1499 MacroAssembler::Address(op2PayloadGPR, JSCell::typeInfoFlagsOffset()),
1500 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1503 // At this point we know that we can perform a straight-forward equality comparison on pointer
1504 // values because both left and right are pointers to objects that have no special equality
1506 branch32(MacroAssembler::Equal, op1GPR, op2PayloadGPR, taken);
1508 // We know that within this branch, rightChild must not be a cell. Check if that is enough to
1509 // prove that it is either null or undefined.
1510 if (!needsTypeCheck(rightChild, SpecCell | SpecOther))
1511 rightNotCell.link(&m_jit);
1513 jump(notTaken, ForceJump);
1515 rightNotCell.link(&m_jit);
1516 m_jit.or32(TrustedImm32(1), op2TagGPR, resultGPR);
1519 JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, SpecCell | SpecOther,
1521 MacroAssembler::NotEqual, resultGPR,
1522 MacroAssembler::TrustedImm32(JSValue::NullTag)));
1528 void SpeculativeJIT::compileInt32Compare(Node* node, MacroAssembler::RelationalCondition condition)
1530 SpeculateInt32Operand op1(this, node->child1());
1531 SpeculateInt32Operand op2(this, node->child2());
1532 GPRTemporary resultPayload(this);
1534 m_jit.compare32(condition, op1.gpr(), op2.gpr(), resultPayload.gpr());
1536 // If we add a DataFormatBool, we should use it here.
1537 booleanResult(resultPayload.gpr(), node);
1540 void SpeculativeJIT::compileDoubleCompare(Node* node, MacroAssembler::DoubleCondition condition)
1542 SpeculateDoubleOperand op1(this, node->child1());
1543 SpeculateDoubleOperand op2(this, node->child2());
1544 GPRTemporary resultPayload(this);
1546 m_jit.move(TrustedImm32(1), resultPayload.gpr());
1547 MacroAssembler::Jump trueCase = m_jit.branchDouble(condition, op1.fpr(), op2.fpr());
1548 m_jit.move(TrustedImm32(0), resultPayload.gpr());
1549 trueCase.link(&m_jit);
1551 booleanResult(resultPayload.gpr(), node);
1554 void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
1556 JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
1557 GPRTemporary resultPayload(this);
1558 GPRReg valueTagGPR = value.tagGPR();
1559 GPRReg valuePayloadGPR = value.payloadGPR();
1560 GPRReg resultPayloadGPR = resultPayload.gpr();
1561 GPRTemporary structure;
1562 GPRReg structureGPR = InvalidGPRReg;
1564 bool masqueradesAsUndefinedWatchpointValid =
1565 masqueradesAsUndefinedWatchpointIsStillValid();
1567 if (!masqueradesAsUndefinedWatchpointValid) {
1568 // The masquerades as undefined case will use the structure register, so allocate it here.
1569 // Do this at the top of the function to avoid branching around a register allocation.
1570 GPRTemporary realStructure(this);
1571 structure.adopt(realStructure);
1572 structureGPR = structure.gpr();
1575 MacroAssembler::Jump notCell = m_jit.branchIfNotCell(value.jsValueRegs());
1576 if (masqueradesAsUndefinedWatchpointValid) {
1578 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
1579 m_jit.branchIfNotObject(valuePayloadGPR));
1582 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
1583 m_jit.branchIfNotObject(valuePayloadGPR));
1585 MacroAssembler::Jump isNotMasqueradesAsUndefined =
1587 MacroAssembler::Zero,
1588 MacroAssembler::Address(valuePayloadGPR, JSCell::typeInfoFlagsOffset()),
1589 MacroAssembler::TrustedImm32(MasqueradesAsUndefined));
1591 m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), structureGPR);
1592 speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
1594 MacroAssembler::Equal,
1595 MacroAssembler::Address(structureGPR, Structure::globalObjectOffset()),
1596 MacroAssembler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode->origin.semantic))));
1598 isNotMasqueradesAsUndefined.link(&m_jit);
1600 m_jit.move(TrustedImm32(0), resultPayloadGPR);
1601 MacroAssembler::Jump done = m_jit.jump();
1603 notCell.link(&m_jit);
1605 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
1606 if (needsTypeCheck(nodeUse, SpecCell | SpecOther)) {
1607 m_jit.or32(TrustedImm32(1), valueTagGPR, resultPayloadGPR);
1609 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, SpecCell | SpecOther,
1611 MacroAssembler::NotEqual,
1613 TrustedImm32(JSValue::NullTag)));
1615 m_jit.move(TrustedImm32(1), resultPayloadGPR);
1619 booleanResult(resultPayloadGPR, m_currentNode);
1622 void SpeculativeJIT::compileLogicalNot(Node* node)
1624 switch (node->child1().useKind()) {
1626 case KnownBooleanUse: {
1627 SpeculateBooleanOperand value(this, node->child1());
1628 GPRTemporary result(this, Reuse, value);
1629 m_jit.xor32(TrustedImm32(1), value.gpr(), result.gpr());
1630 booleanResult(result.gpr(), node);
1634 case ObjectOrOtherUse: {
1635 compileObjectOrOtherLogicalNot(node->child1());
1640 SpeculateInt32Operand value(this, node->child1());
1641 GPRTemporary resultPayload(this, Reuse, value);
1642 m_jit.compare32(MacroAssembler::Equal, value.gpr(), MacroAssembler::TrustedImm32(0), resultPayload.gpr());
1643 booleanResult(resultPayload.gpr(), node);
1647 case DoubleRepUse: {
1648 SpeculateDoubleOperand value(this, node->child1());
1649 FPRTemporary scratch(this);
1650 GPRTemporary resultPayload(this);
1651 m_jit.move(TrustedImm32(0), resultPayload.gpr());
1652 MacroAssembler::Jump nonZero = m_jit.branchDoubleNonZero(value.fpr(), scratch.fpr());
1653 m_jit.move(TrustedImm32(1), resultPayload.gpr());
1654 nonZero.link(&m_jit);
1655 booleanResult(resultPayload.gpr(), node);
1660 JSValueOperand arg1(this, node->child1());
1661 GPRTemporary resultPayload(this, Reuse, arg1, PayloadWord);
1662 GPRReg arg1TagGPR = arg1.tagGPR();
1663 GPRReg arg1PayloadGPR = arg1.payloadGPR();
1664 GPRReg resultPayloadGPR = resultPayload.gpr();
1668 JITCompiler::Jump slowCase = m_jit.branch32(JITCompiler::NotEqual, arg1TagGPR, TrustedImm32(JSValue::BooleanTag));
1670 m_jit.move(arg1PayloadGPR, resultPayloadGPR);
1672 addSlowPathGenerator(
1674 slowCase, this, operationConvertJSValueToBoolean, resultPayloadGPR, arg1TagGPR,
1675 arg1PayloadGPR, NeedToSpill, ExceptionCheckRequirement::CheckNotNeeded));
1677 m_jit.xor32(TrustedImm32(1), resultPayloadGPR);
1678 booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
1682 return compileStringZeroLength(node);
1684 case StringOrOtherUse:
1685 return compileLogicalNotStringOrOther(node);
1688 RELEASE_ASSERT_NOT_REACHED();
1693 void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BasicBlock* taken, BasicBlock* notTaken)
1695 JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
1696 GPRTemporary scratch(this);
1697 GPRReg valueTagGPR = value.tagGPR();
1698 GPRReg valuePayloadGPR = value.payloadGPR();
1699 GPRReg scratchGPR = scratch.gpr();
1701 MacroAssembler::Jump notCell = m_jit.branchIfNotCell(value.jsValueRegs());
1702 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
1704 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
1705 m_jit.branchIfNotObject(valuePayloadGPR));
1708 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
1709 m_jit.branchIfNotObject(valuePayloadGPR));
1711 JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8(
1713 MacroAssembler::Address(valuePayloadGPR, JSCell::typeInfoFlagsOffset()),
1714 TrustedImm32(MasqueradesAsUndefined));
1716 m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), scratchGPR);
1717 speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
1719 MacroAssembler::Equal,
1720 MacroAssembler::Address(scratchGPR, Structure::globalObjectOffset()),
1721 MacroAssembler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_currentNode->origin.semantic))));
1723 isNotMasqueradesAsUndefined.link(&m_jit);
1725 jump(taken, ForceJump);
1727 notCell.link(&m_jit);
1729 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
1730 if (needsTypeCheck(nodeUse, SpecCell | SpecOther)) {
1731 m_jit.or32(TrustedImm32(1), valueTagGPR, scratchGPR);
1733 JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, SpecCell | SpecOther,
1734 m_jit.branch32(MacroAssembler::NotEqual, scratchGPR, TrustedImm32(JSValue::NullTag)));
1739 noResult(m_currentNode);
1742 void SpeculativeJIT::emitBranch(Node* node)
1744 BasicBlock* taken = node->branchData()->taken.block;
1745 BasicBlock* notTaken = node->branchData()->notTaken.block;
1747 switch (node->child1().useKind()) {
1749 case KnownBooleanUse: {
1750 SpeculateBooleanOperand value(this, node->child1());
1751 MacroAssembler::ResultCondition condition = MacroAssembler::NonZero;
1753 if (taken == nextBlock()) {
1754 condition = MacroAssembler::Zero;
1755 BasicBlock* tmp = taken;
1760 branchTest32(condition, value.gpr(), TrustedImm32(1), taken);
1767 case ObjectOrOtherUse: {
1768 emitObjectOrOtherBranch(node->child1(), taken, notTaken);
1773 emitStringBranch(node->child1(), taken, notTaken);
1777 case StringOrOtherUse: {
1778 emitStringOrOtherBranch(node->child1(), taken, notTaken);
1784 if (node->child1().useKind() == Int32Use) {
1785 bool invert = false;
1787 if (taken == nextBlock()) {
1789 BasicBlock* tmp = taken;
1794 SpeculateInt32Operand value(this, node->child1());
1795 branchTest32(invert ? MacroAssembler::Zero : MacroAssembler::NonZero, value.gpr(), taken);
1797 SpeculateDoubleOperand value(this, node->child1());
1798 FPRTemporary scratch(this);
1799 branchDoubleNonZero(value.fpr(), scratch.fpr(), taken);
1809 JSValueOperand value(this, node->child1());
1811 GPRReg valueTagGPR = value.tagGPR();
1812 GPRReg valuePayloadGPR = value.payloadGPR();
1814 GPRTemporary result(this);
1815 GPRReg resultGPR = result.gpr();
1817 use(node->child1());
1819 JITCompiler::Jump fastPath = m_jit.branch32(JITCompiler::Equal, valueTagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag));
1820 JITCompiler::Jump slowPath = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, JITCompiler::TrustedImm32(JSValue::BooleanTag));
1822 fastPath.link(&m_jit);
1823 branchTest32(JITCompiler::Zero, valuePayloadGPR, notTaken);
1824 jump(taken, ForceJump);
1826 slowPath.link(&m_jit);
1827 silentSpillAllRegisters(resultGPR);
1828 callOperation(operationConvertJSValueToBoolean, resultGPR, valueTagGPR, valuePayloadGPR);
1829 silentFillAllRegisters(resultGPR);
1831 branchTest32(JITCompiler::NonZero, resultGPR, taken);
1834 noResult(node, UseChildrenCalledExplicitly);
1839 RELEASE_ASSERT_NOT_REACHED();
1844 template<typename BaseOperandType, typename PropertyOperandType, typename ValueOperandType, typename TagType>
1845 void SpeculativeJIT::compileContiguousPutByVal(Node* node, BaseOperandType& base, PropertyOperandType& property, ValueOperandType& value, GPRReg valuePayloadReg, TagType valueTag)
1847 Edge child4 = m_jit.graph().varArgChild(node, 3);
1849 ArrayMode arrayMode = node->arrayMode();
1851 GPRReg baseReg = base.gpr();
1852 GPRReg propertyReg = property.gpr();
1854 StorageOperand storage(this, child4);
1855 GPRReg storageReg = storage.gpr();
1857 if (node->op() == PutByValAlias) {
1858 // Store the value to the array.
1859 GPRReg propertyReg = property.gpr();
1860 m_jit.store32(valueTag, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
1861 m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
1867 MacroAssembler::Jump slowCase;
1869 if (arrayMode.isInBounds()) {
1871 OutOfBounds, JSValueRegs(), 0,
1872 m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
1874 MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
1876 slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength()));
1878 if (!arrayMode.isOutOfBounds())
1879 speculationCheck(OutOfBounds, JSValueRegs(), 0, slowCase);
1881 m_jit.add32(TrustedImm32(1), propertyReg);
1882 m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
1883 m_jit.sub32(TrustedImm32(1), propertyReg);
1885 inBounds.link(&m_jit);
1888 m_jit.store32(valueTag, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
1889 m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
1896 if (arrayMode.isOutOfBounds()) {
1897 if (node->op() == PutByValDirect) {
1898 addSlowPathGenerator(slowPathCall(
1900 m_jit.codeBlock()->isStrictMode() ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValDirectBeyondArrayBoundsNonStrict,
1901 NoResult, baseReg, propertyReg, valueTag, valuePayloadReg));
1903 addSlowPathGenerator(slowPathCall(
1905 m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
1906 NoResult, baseReg, propertyReg, valueTag, valuePayloadReg));
1910 noResult(node, UseChildrenCalledExplicitly);
1913 void SpeculativeJIT::compile(Node* node)
1915 NodeType op = node->op();
1917 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
1918 m_jit.clearRegisterAllocationOffsets();
1923 case DoubleConstant:
1924 case PhantomDirectArguments:
1925 case PhantomClonedArguments:
1926 initConstantInfo(node);
1929 case LazyJSConstant:
1930 compileLazyJSConstant(node);
1934 speculate(node, node->child1());
1935 switch (node->child1().useKind()) {
1937 case DoubleRepRealUse: {
1938 SpeculateDoubleOperand op(this, node->child1());
1939 doubleResult(op.fpr(), node);
1944 case DoubleRepAnyIntUse: {
1945 RELEASE_ASSERT_NOT_REACHED();
1949 JSValueOperand op(this, node->child1());
1950 jsValueResult(op.tagGPR(), op.payloadGPR(), node);
1958 AbstractValue& value = m_state.variables().operand(node->local());
1960 // If the CFA is tracking this variable and it found that the variable
1961 // cannot have been assigned, then don't attempt to proceed.
1962 if (value.isClear()) {
1963 m_compileOkay = false;
1967 switch (node->variableAccessData()->flushFormat()) {
1968 case FlushedDouble: {
1969 FPRTemporary result(this);
1970 m_jit.loadDouble(JITCompiler::addressFor(node->machineLocal()), result.fpr());
1971 VirtualRegister virtualRegister = node->virtualRegister();
1972 m_fprs.retain(result.fpr(), virtualRegister, SpillOrderDouble);
1973 generationInfoFromVirtualRegister(virtualRegister).initDouble(node, node->refCount(), result.fpr());
1977 case FlushedInt32: {
1978 GPRTemporary result(this);
1979 m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr());
1981 // Like int32Result, but don't useChildren - our children are phi nodes,
1982 // and don't represent values within this dataflow with virtual registers.
1983 VirtualRegister virtualRegister = node->virtualRegister();
1984 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderInteger);
1985 generationInfoFromVirtualRegister(virtualRegister).initInt32(node, node->refCount(), result.gpr());
1990 GPRTemporary result(this);
1991 m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr());
1993 // Like cellResult, but don't useChildren - our children are phi nodes,
1994 // and don't represent values within this dataflow with virtual registers.
1995 VirtualRegister virtualRegister = node->virtualRegister();
1996 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderCell);
1997 generationInfoFromVirtualRegister(virtualRegister).initCell(node, node->refCount(), result.gpr());
2001 case FlushedBoolean: {
2002 GPRTemporary result(this);
2003 m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr());
2005 // Like booleanResult, but don't useChildren - our children are phi nodes,
2006 // and don't represent values within this dataflow with virtual registers.
2007 VirtualRegister virtualRegister = node->virtualRegister();
2008 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderBoolean);
2009 generationInfoFromVirtualRegister(virtualRegister).initBoolean(node, node->refCount(), result.gpr());
2013 case FlushedJSValue: {
2014 GPRTemporary result(this);
2015 GPRTemporary tag(this);
2016 m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr());
2017 m_jit.load32(JITCompiler::tagFor(node->machineLocal()), tag.gpr());
2019 // Like jsValueResult, but don't useChildren - our children are phi nodes,
2020 // and don't represent values within this dataflow with virtual registers.
2021 VirtualRegister virtualRegister = node->virtualRegister();
2022 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
2023 m_gprs.retain(tag.gpr(), virtualRegister, SpillOrderJS);
2025 generationInfoFromVirtualRegister(virtualRegister).initJSValue(node, node->refCount(), tag.gpr(), result.gpr(), DataFormatJS);
2030 RELEASE_ASSERT_NOT_REACHED();
2035 case GetLocalUnlinked: {
2036 GPRTemporary payload(this);
2037 GPRTemporary tag(this);
2038 m_jit.load32(JITCompiler::payloadFor(node->unlinkedMachineLocal()), payload.gpr());
2039 m_jit.load32(JITCompiler::tagFor(node->unlinkedMachineLocal()), tag.gpr());
2040 jsValueResult(tag.gpr(), payload.gpr(), node);
2045 compileMovHint(m_currentNode);
2051 recordSetLocal(m_currentNode->unlinkedLocal(), VirtualRegister(), DataFormatDead);
2062 switch (node->variableAccessData()->flushFormat()) {
2063 case FlushedDouble: {
2064 SpeculateDoubleOperand value(this, node->child1());
2065 m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node->machineLocal()));
2067 // Indicate that it's no longer necessary to retrieve the value of
2068 // this bytecode variable from registers or other locations in the stack,
2069 // but that it is stored as a double.
2070 recordSetLocal(DataFormatDouble);
2074 case FlushedInt32: {
2075 SpeculateInt32Operand value(this, node->child1());
2076 m_jit.store32(value.gpr(), JITCompiler::payloadFor(node->machineLocal()));
2078 recordSetLocal(DataFormatInt32);
2083 SpeculateCellOperand cell(this, node->child1());
2084 GPRReg cellGPR = cell.gpr();
2085 m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node->machineLocal()));
2087 recordSetLocal(DataFormatCell);
2091 case FlushedBoolean: {
2092 SpeculateBooleanOperand value(this, node->child1());
2093 m_jit.store32(value.gpr(), JITCompiler::payloadFor(node->machineLocal()));
2095 recordSetLocal(DataFormatBoolean);
2099 case FlushedJSValue: {
2100 JSValueOperand value(this, node->child1());
2101 m_jit.store32(value.payloadGPR(), JITCompiler::payloadFor(node->machineLocal()));
2102 m_jit.store32(value.tagGPR(), JITCompiler::tagFor(node->machineLocal()));
2104 recordSetLocal(dataFormatFor(node->variableAccessData()->flushFormat()));
2109 RELEASE_ASSERT_NOT_REACHED();
2116 // This is a no-op; it just marks the fact that the argument is being used.
2117 // But it may be profitable to use this as a hook to run speculation checks
2118 // on arguments, thereby allowing us to trivially eliminate such checks if
2119 // the argument is not used.
2120 recordSetLocal(dataFormatFor(node->variableAccessData()->flushFormat()));
2126 compileBitwiseOp(node);
2132 compileShiftOp(node);
2135 case UInt32ToNumber: {
2136 compileUInt32ToNumber(node);
2140 case DoubleAsInt32: {
2141 compileDoubleAsInt32(node);
2145 case ValueToInt32: {
2146 compileValueToInt32(node);
2151 compileDoubleRep(node);
2156 compileValueRep(node);
2161 compileValueAdd(node);
2165 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
2166 JSValueOperand op2(this, node->child2(), ManualOperandSpeculation);
2167 JSValueOperand op3(this, node->child3(), ManualOperandSpeculation);
2169 GPRReg op1TagGPR = op1.tagGPR();
2170 GPRReg op1PayloadGPR = op1.payloadGPR();
2171 GPRReg op2TagGPR = op2.tagGPR();
2172 GPRReg op2PayloadGPR = op2.payloadGPR();
2174 GPRReg op3PayloadGPR;
2175 if (node->child3()) {
2176 op3TagGPR = op3.tagGPR();
2177 op3PayloadGPR = op3.payloadGPR();
2179 op3TagGPR = InvalidGPRReg;
2180 op3PayloadGPR = InvalidGPRReg;
2185 GPRFlushedCallResult result(this);
2187 callOperation(operationStrCat3, result.gpr(), op1TagGPR, op1PayloadGPR, op2TagGPR, op2PayloadGPR, op3TagGPR, op3PayloadGPR);
2189 callOperation(operationStrCat2, result.gpr(), op1TagGPR, op1PayloadGPR, op2TagGPR, op2PayloadGPR);
2190 m_jit.exceptionCheck();
2192 cellResult(result.gpr(), node);
2197 compileArithAdd(node);
2201 compileArithClz32(node);
2205 compileMakeRope(node);
2209 compileArithSub(node);
2213 compileArithNegate(node);
2217 compileArithMul(node);
2221 compileArithDiv(node);
2226 compileArithMod(node);
2231 compileArithPow(node);
2236 switch (node->child1().useKind()) {
2238 SpeculateStrictInt32Operand op1(this, node->child1());
2239 GPRTemporary result(this, Reuse, op1);
2240 GPRTemporary scratch(this);
2242 m_jit.move(op1.gpr(), result.gpr());
2243 m_jit.rshift32(result.gpr(), MacroAssembler::TrustedImm32(31), scratch.gpr());
2244 m_jit.add32(scratch.gpr(), result.gpr());
2245 m_jit.xor32(scratch.gpr(), result.gpr());
2246 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Signed, result.gpr()));
2247 int32Result(result.gpr(), node);
2252 case DoubleRepUse: {
2253 SpeculateDoubleOperand op1(this, node->child1());
2254 FPRTemporary result(this);
2256 m_jit.absDouble(op1.fpr(), result.fpr());
2257 doubleResult(result.fpr(), node);
2262 RELEASE_ASSERT_NOT_REACHED();
2270 switch (node->binaryUseKind()) {
2272 SpeculateStrictInt32Operand op1(this, node->child1());
2273 SpeculateStrictInt32Operand op2(this, node->child2());
2274 GPRTemporary result(this, Reuse, op1);
2276 GPRReg op1GPR = op1.gpr();
2277 GPRReg op2GPR = op2.gpr();
2278 GPRReg resultGPR = result.gpr();
2280 MacroAssembler::Jump op1Less = m_jit.branch32(op == ArithMin ? MacroAssembler::LessThan : MacroAssembler::GreaterThan, op1GPR, op2GPR);
2281 m_jit.move(op2GPR, resultGPR);
2282 if (op1GPR != resultGPR) {
2283 MacroAssembler::Jump done = m_jit.jump();
2284 op1Less.link(&m_jit);
2285 m_jit.move(op1GPR, resultGPR);
2288 op1Less.link(&m_jit);
2290 int32Result(resultGPR, node);
2294 case DoubleRepUse: {
2295 SpeculateDoubleOperand op1(this, node->child1());
2296 SpeculateDoubleOperand op2(this, node->child2());
2297 FPRTemporary result(this, op1);
2299 FPRReg op1FPR = op1.fpr();
2300 FPRReg op2FPR = op2.fpr();
2301 FPRReg resultFPR = result.fpr();
2303 MacroAssembler::JumpList done;
2305 MacroAssembler::Jump op1Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleLessThan : MacroAssembler::DoubleGreaterThan, op1FPR, op2FPR);
2307 // op2 is eather the lesser one or one of then is NaN
2308 MacroAssembler::Jump op2Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleGreaterThanOrEqual : MacroAssembler::DoubleLessThanOrEqual, op1FPR, op2FPR);
2310 // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding
2311 // op1 + op2 and putting it into result.
2312 m_jit.addDouble(op1FPR, op2FPR, resultFPR);
2313 done.append(m_jit.jump());
2315 op2Less.link(&m_jit);
2316 m_jit.moveDouble(op2FPR, resultFPR);
2318 if (op1FPR != resultFPR) {
2319 done.append(m_jit.jump());
2321 op1Less.link(&m_jit);
2322 m_jit.moveDouble(op1FPR, resultFPR);
2324 op1Less.link(&m_jit);
2328 doubleResult(resultFPR, node);
2333 RELEASE_ASSERT_NOT_REACHED();
2340 compileArithSqrt(node);
2344 SpeculateDoubleOperand op1(this, node->child1());
2345 FPRTemporary result(this, op1);
2347 m_jit.convertDoubleToFloat(op1.fpr(), result.fpr());
2348 m_jit.convertFloatToDouble(result.fpr(), result.fpr());
2350 doubleResult(result.fpr(), node);
2355 compileArithRandom(node);
2362 compileArithRounding(node);
2366 SpeculateDoubleOperand op1(this, node->child1());
2367 FPRReg op1FPR = op1.fpr();
2371 FPRResult result(this);
2372 callOperation(sin, result.fpr(), op1FPR);
2373 doubleResult(result.fpr(), node);
2378 SpeculateDoubleOperand op1(this, node->child1());
2379 FPRReg op1FPR = op1.fpr();
2383 FPRResult result(this);
2384 callOperation(cos, result.fpr(), op1FPR);
2385 doubleResult(result.fpr(), node);
2390 compileArithLog(node);
2394 compileLogicalNot(node);
2398 if (compare(node, JITCompiler::LessThan, JITCompiler::DoubleLessThan, operationCompareLess))
2403 if (compare(node, JITCompiler::LessThanOrEqual, JITCompiler::DoubleLessThanOrEqual, operationCompareLessEq))
2407 case CompareGreater:
2408 if (compare(node, JITCompiler::GreaterThan, JITCompiler::DoubleGreaterThan, operationCompareGreater))
2412 case CompareGreaterEq:
2413 if (compare(node, JITCompiler::GreaterThanOrEqual, JITCompiler::DoubleGreaterThanOrEqual, operationCompareGreaterEq))
2418 if (compare(node, JITCompiler::Equal, JITCompiler::DoubleEqual, operationCompareEq))
2422 case CompareStrictEq:
2423 if (compileStrictEq(node))
2428 compileCompareEqPtr(node);
2431 case StringCharCodeAt: {
2432 compileGetCharCodeAt(node);
2436 case StringCharAt: {
2437 // Relies on StringCharAt node having same basic layout as GetByVal
2438 compileGetByValOnString(node);
2442 case StringFromCharCode: {
2443 compileFromCharCode(node);
2453 case ArrayifyToStructure: {
2459 switch (node->arrayMode().type()) {
2460 case Array::SelectUsingPredictions:
2461 case Array::ForceExit:
2462 RELEASE_ASSERT_NOT_REACHED();
2463 #if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
2464 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
2467 case Array::Undecided: {
2468 SpeculateStrictInt32Operand index(this, node->child2());
2469 GPRTemporary resultTag(this, Reuse, index);
2470 GPRTemporary resultPayload(this);
2472 GPRReg indexGPR = index.gpr();
2473 GPRReg resultTagGPR = resultTag.gpr();
2474 GPRReg resultPayloadGPR = resultPayload.gpr();
2476 speculationCheck(OutOfBounds, JSValueRegs(), node,
2477 m_jit.branch32(MacroAssembler::LessThan, indexGPR, MacroAssembler::TrustedImm32(0)));
2479 use(node->child1());
2482 m_jit.move(MacroAssembler::TrustedImm32(JSValue::UndefinedTag), resultTagGPR);
2483 m_jit.move(MacroAssembler::TrustedImm32(0), resultPayloadGPR);
2484 jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
2487 case Array::Generic: {
2488 SpeculateCellOperand base(this, node->child1()); // Save a register, speculate cell. We'll probably be right.
2489 JSValueOperand property(this, node->child2());
2490 GPRReg baseGPR = base.gpr();
2491 GPRReg propertyTagGPR = property.tagGPR();
2492 GPRReg propertyPayloadGPR = property.payloadGPR();
2495 GPRFlushedCallResult2 resultTag(this);
2496 GPRFlushedCallResult resultPayload(this);
2497 callOperation(operationGetByValCell, resultTag.gpr(), resultPayload.gpr(), baseGPR, propertyTagGPR, propertyPayloadGPR);
2498 m_jit.exceptionCheck();
2500 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
2504 case Array::Contiguous: {
2505 if (node->arrayMode().isInBounds()) {
2506 SpeculateStrictInt32Operand property(this, node->child2());
2507 StorageOperand storage(this, node->child3());
2509 GPRReg propertyReg = property.gpr();
2510 GPRReg storageReg = storage.gpr();
2515 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2517 GPRTemporary resultPayload(this);
2518 if (node->arrayMode().type() == Array::Int32) {
2519 ASSERT(!node->arrayMode().isSaneChain());
2522 OutOfBounds, JSValueRegs(), 0,
2524 MacroAssembler::Equal,
2525 MacroAssembler::BaseIndex(
2526 storageReg, propertyReg, MacroAssembler::TimesEight, TagOffset),
2527 TrustedImm32(JSValue::EmptyValueTag)));
2529 MacroAssembler::BaseIndex(
2530 storageReg, propertyReg, MacroAssembler::TimesEight, PayloadOffset),
2531 resultPayload.gpr());
2532 int32Result(resultPayload.gpr(), node);
2536 GPRTemporary resultTag(this);
2538 MacroAssembler::BaseIndex(
2539 storageReg, propertyReg, MacroAssembler::TimesEight, TagOffset),
2542 MacroAssembler::BaseIndex(
2543 storageReg, propertyReg, MacroAssembler::TimesEight, PayloadOffset),
2544 resultPayload.gpr());
2545 if (node->arrayMode().isSaneChain()) {
2546 JITCompiler::Jump notHole = m_jit.branch32(
2547 MacroAssembler::NotEqual, resultTag.gpr(),
2548 TrustedImm32(JSValue::EmptyValueTag));
2549 m_jit.move(TrustedImm32(JSValue::UndefinedTag), resultTag.gpr());
2550 m_jit.move(TrustedImm32(0), resultPayload.gpr());
2551 notHole.link(&m_jit);
2554 LoadFromHole, JSValueRegs(), 0,
2556 MacroAssembler::Equal, resultTag.gpr(),
2557 TrustedImm32(JSValue::EmptyValueTag)));
2559 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
2563 SpeculateCellOperand base(this, node->child1());
2564 SpeculateStrictInt32Operand property(this, node->child2());
2565 StorageOperand storage(this, node->child3());
2567 GPRReg baseReg = base.gpr();
2568 GPRReg propertyReg = property.gpr();
2569 GPRReg storageReg = storage.gpr();
2574 GPRTemporary resultTag(this);
2575 GPRTemporary resultPayload(this);
2576 GPRReg resultTagReg = resultTag.gpr();
2577 GPRReg resultPayloadReg = resultPayload.gpr();
2579 MacroAssembler::JumpList slowCases;
2581 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2583 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagReg);
2584 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayloadReg);
2585 slowCases.append(m_jit.branch32(MacroAssembler::Equal, resultTagReg, TrustedImm32(JSValue::EmptyValueTag)));
2587 addSlowPathGenerator(
2589 slowCases, this, operationGetByValArrayInt,
2590 JSValueRegs(resultTagReg, resultPayloadReg), baseReg, propertyReg));
2592 jsValueResult(resultTagReg, resultPayloadReg, node);
2595 case Array::Double: {
2596 if (node->arrayMode().isInBounds()) {
2597 SpeculateStrictInt32Operand property(this, node->child2());
2598 StorageOperand storage(this, node->child3());
2600 GPRReg propertyReg = property.gpr();
2601 GPRReg storageReg = storage.gpr();
2606 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2608 FPRTemporary result(this);
2609 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr());
2610 if (!node->arrayMode().isSaneChain())
2611 speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr()));
2612 doubleResult(result.fpr(), node);
2616 SpeculateCellOperand base(this, node->child1());
2617 SpeculateStrictInt32Operand property(this, node->child2());
2618 StorageOperand storage(this, node->child3());
2620 GPRReg baseReg = base.gpr();
2621 GPRReg propertyReg = property.gpr();
2622 GPRReg storageReg = storage.gpr();
2627 GPRTemporary resultTag(this);
2628 GPRTemporary resultPayload(this);
2629 FPRTemporary temp(this);
2630 GPRReg resultTagReg = resultTag.gpr();
2631 GPRReg resultPayloadReg = resultPayload.gpr();
2632 FPRReg tempReg = temp.fpr();
2634 MacroAssembler::JumpList slowCases;
2636 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2638 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
2639 slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempReg, tempReg));
2640 boxDouble(tempReg, resultTagReg, resultPayloadReg);
2642 addSlowPathGenerator(
2644 slowCases, this, operationGetByValArrayInt,
2645 JSValueRegs(resultTagReg, resultPayloadReg), baseReg, propertyReg));
2647 jsValueResult(resultTagReg, resultPayloadReg, node);
2650 case Array::ArrayStorage:
2651 case Array::SlowPutArrayStorage: {
2652 if (node->arrayMode().isInBounds()) {
2653 SpeculateStrictInt32Operand property(this, node->child2());
2654 StorageOperand storage(this, node->child3());
2655 GPRReg propertyReg = property.gpr();
2656 GPRReg storageReg = storage.gpr();
2661 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())));
2663 GPRTemporary resultTag(this);
2664 GPRTemporary resultPayload(this);
2666 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr());
2667 speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag)));
2668 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
2670 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
2674 SpeculateCellOperand base(this, node->child1());
2675 SpeculateStrictInt32Operand property(this, node->child2());
2676 StorageOperand storage(this, node->child3());
2677 GPRReg propertyReg = property.gpr();
2678 GPRReg storageReg = storage.gpr();
2679 GPRReg baseReg = base.gpr();
2684 GPRTemporary resultTag(this);
2685 GPRTemporary resultPayload(this);
2686 GPRReg resultTagReg = resultTag.gpr();
2687 GPRReg resultPayloadReg = resultPayload.gpr();
2689 JITCompiler::Jump outOfBounds = m_jit.branch32(
2690 MacroAssembler::AboveOrEqual, propertyReg,
2691 MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset()));
2693 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagReg);
2694 JITCompiler::Jump hole = m_jit.branch32(
2695 MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag));
2696 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayloadReg);
2698 JITCompiler::JumpList slowCases;
2699 slowCases.append(outOfBounds);
2700 slowCases.append(hole);
2701 addSlowPathGenerator(
2703 slowCases, this, operationGetByValArrayInt,
2704 JSValueRegs(resultTagReg, resultPayloadReg),
2705 baseReg, propertyReg));
2707 jsValueResult(resultTagReg, resultPayloadReg, node);
2711 compileGetByValOnString(node);
2713 case Array::DirectArguments:
2714 compileGetByValOnDirectArguments(node);
2716 case Array::ScopedArguments:
2717 compileGetByValOnScopedArguments(node);
2720 TypedArrayType type = node->arrayMode().typedArrayType();
2722 compileGetByValOnIntTypedArray(node, type);
2724 compileGetByValOnFloatTypedArray(node, type);
2729 case GetByValWithThis: {
2730 JSValueOperand base(this, node->child1());
2731 GPRReg baseTag = base.tagGPR();
2732 GPRReg basePayload = base.payloadGPR();
2733 JSValueOperand thisValue(this, node->child2());
2734 GPRReg thisValueTag = thisValue.tagGPR();
2735 GPRReg thisValuePayload = thisValue.payloadGPR();
2736 JSValueOperand subscript(this, node->child3());
2737 GPRReg subscriptTag = subscript.tagGPR();
2738 GPRReg subscriptPayload = subscript.payloadGPR();
2740 GPRFlushedCallResult resultPayload(this);
2741 GPRFlushedCallResult2 resultTag(this);
2742 GPRReg resultPayloadGPR = resultPayload.gpr();
2743 GPRReg resultTagGPR = resultTag.gpr();
2746 callOperation(operationGetByValWithThis, resultTagGPR, resultPayloadGPR, baseTag, basePayload, thisValueTag, thisValuePayload, subscriptTag, subscriptPayload);
2747 m_jit.exceptionCheck();
2749 jsValueResult(resultTagGPR, resultPayloadGPR, node);
2753 case PutByValDirect:
2755 case PutByValAlias: {
2756 Edge child1 = m_jit.graph().varArgChild(node, 0);
2757 Edge child2 = m_jit.graph().varArgChild(node, 1);
2758 Edge child3 = m_jit.graph().varArgChild(node, 2);
2759 Edge child4 = m_jit.graph().varArgChild(node, 3);
2761 ArrayMode arrayMode = node->arrayMode().modeForPut();
2762 bool alreadyHandled = false;
2764 switch (arrayMode.type()) {
2765 case Array::SelectUsingPredictions:
2766 case Array::ForceExit:
2767 RELEASE_ASSERT_NOT_REACHED();
2768 #if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
2769 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
2770 alreadyHandled = true;
2773 case Array::Generic: {
2774 ASSERT(node->op() == PutByVal || node->op() == PutByValDirect);
2776 SpeculateCellOperand base(this, child1); // Save a register, speculate cell. We'll probably be right.
2777 JSValueOperand property(this, child2);
2778 JSValueOperand value(this, child3);
2779 GPRReg baseGPR = base.gpr();
2780 GPRReg propertyTagGPR = property.tagGPR();
2781 GPRReg propertyPayloadGPR = property.payloadGPR();
2782 GPRReg valueTagGPR = value.tagGPR();
2783 GPRReg valuePayloadGPR = value.payloadGPR();
2786 if (node->op() == PutByValDirect)
2787 callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValDirectCellStrict : operationPutByValDirectCellNonStrict, baseGPR, propertyTagGPR, propertyPayloadGPR, valueTagGPR, valuePayloadGPR);
2789 callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValCellStrict : operationPutByValCellNonStrict, baseGPR, propertyTagGPR, propertyPayloadGPR, valueTagGPR, valuePayloadGPR);
2790 m_jit.exceptionCheck();
2793 alreadyHandled = true;
2803 SpeculateCellOperand base(this, child1);
2804 SpeculateStrictInt32Operand property(this, child2);
2806 GPRReg baseReg = base.gpr();
2807 GPRReg propertyReg = property.gpr();
2809 switch (arrayMode.type()) {
2810 case Array::Int32: {
2811 SpeculateInt32Operand value(this, child3);
2813 GPRReg valuePayloadReg = value.gpr();
2818 compileContiguousPutByVal(node, base, property, value, valuePayloadReg, TrustedImm32(JSValue::Int32Tag));
2821 case Array::Contiguous: {
2822 JSValueOperand value(this, child3);
2824 GPRReg valueTagReg = value.tagGPR();
2825 GPRReg valuePayloadReg = value.payloadGPR();
2830 compileContiguousPutByVal(node, base, property, value, valuePayloadReg, valueTagReg);
2833 case Array::Double: {
2834 compileDoublePutByVal(node, base, property);
2837 case Array::ArrayStorage:
2838 case Array::SlowPutArrayStorage: {
2839 JSValueOperand value(this, child3);
2841 GPRReg valueTagReg = value.tagGPR();
2842 GPRReg valuePayloadReg = value.payloadGPR();
2847 StorageOperand storage(this, child4);
2848 GPRReg storageReg = storage.gpr();
2850 if (node->op() == PutByValAlias) {
2851 // Store the value to the array.
2852 GPRReg propertyReg = property.gpr();
2853 m_jit.store32(value.tagGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2854 m_jit.store32(value.payloadGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2860 MacroAssembler::JumpList slowCases;
2862 MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset()));
2863 if (!arrayMode.isOutOfBounds())
2864 speculationCheck(OutOfBounds, JSValueRegs(), 0, beyondArrayBounds);
2866 slowCases.append(beyondArrayBounds);
2868 // Check if we're writing to a hole; if so increment m_numValuesInVector.
2869 if (arrayMode.isInBounds()) {
2871 StoreToHole, JSValueRegs(), 0,
2872 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)));
2874 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));
2875 if (arrayMode.isSlowPut()) {
2876 // This is sort of strange. If we wanted to optimize this code path, we would invert
2877 // the above branch. But it's simply not worth it since this only happens if we're
2878 // already having a bad time.
2879 slowCases.append(m_jit.jump());
2881 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, ArrayStorage::numValuesInVectorOffset()));
2883 // If we're writing to a hole we might be growing the array;
2884 MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
2885 m_jit.add32(TrustedImm32(1), propertyReg);
2886 m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
2887 m_jit.sub32(TrustedImm32(1), propertyReg);
2889 lengthDoesNotNeedUpdate.link(&m_jit);
2891 notHoleValue.link(&m_jit);
2894 // Store the value to the array.
2895 m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2896 m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2903 if (!slowCases.empty()) {
2904 if (node->op() == PutByValDirect) {
2905 addSlowPathGenerator(slowPathCall(
2907 m_jit.codeBlock()->isStrictMode() ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValDirectBeyondArrayBoundsNonStrict,
2908 NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg));
2910 addSlowPathGenerator(slowPathCall(
2912 m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
2913 NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg));
2917 noResult(node, UseChildrenCalledExplicitly);
2922 TypedArrayType type = arrayMode.typedArrayType();
2924 compilePutByValForIntTypedArray(base.gpr(), property.gpr(), node, type);
2926 compilePutByValForFloatTypedArray(base.gpr(), property.gpr(), node, type);
2931 case PutByValWithThis: {
2933 // We don't have enough registers on X86 to do this
2934 // without setting up the call frame incrementally.
2936 m_jit.poke(GPRInfo::callFrameRegister, index++);
2939 JSValueOperand base(this, m_jit.graph().varArgChild(node, 0));
2940 GPRReg baseTag = base.tagGPR();
2941 GPRReg basePayload = base.payloadGPR();
2943 JSValueOperand thisValue(this, m_jit.graph().varArgChild(node, 1));
2944 GPRReg thisValueTag = thisValue.tagGPR();
2945 GPRReg thisValuePayload = thisValue.payloadGPR();
2947 JSValueOperand property(this, m_jit.graph().varArgChild(node, 2));
2948 GPRReg propertyTag = property.tagGPR();
2949 GPRReg propertyPayload = property.payloadGPR();
2951 m_jit.poke(basePayload, index++);
2952 m_jit.poke(baseTag, index++);
2954 m_jit.poke(thisValuePayload, index++);
2955 m_jit.poke(thisValueTag, index++);
2957 m_jit.poke(propertyPayload, index++);
2958 m_jit.poke(propertyTag, index++);
2963 JSValueOperand value(this, m_jit.graph().varArgChild(node, 3));
2964 GPRReg valueTag = value.tagGPR();
2965 GPRReg valuePayload = value.payloadGPR();
2966 m_jit.poke(valuePayload, index++);
2967 m_jit.poke(valueTag, index++);
2970 appendCall(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis);
2971 m_jit.exceptionCheck();
2973 // We don't have enough registers on MIPS either but the ABI is a little different.
2975 m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
2977 JSValueOperand base(this, m_jit.graph().varArgChild(node, 0));
2978 GPRReg baseTag = base.tagGPR();
2979 GPRReg basePayload = base.payloadGPR();
2981 JSValueOperand thisValue(this, m_jit.graph().varArgChild(node, 1));
2982 GPRReg thisValueTag = thisValue.tagGPR();
2983 GPRReg thisValuePayload = thisValue.payloadGPR();
2985 JSValueOperand property(this, m_jit.graph().varArgChild(node, 2));
2986 GPRReg propertyTag = property.tagGPR();
2987 GPRReg propertyPayload = property.payloadGPR();
2989 // for operationPutByValWithThis[Strict](), base is a 64 bits
2990 // argument, so it should be double word aligned on the stack.
2991 // This requirement still applies when it's in argument registers
2992 // instead of on the stack.
2993 m_jit.move(basePayload, GPRInfo::argumentGPR2);
2994 m_jit.move(baseTag, GPRInfo::argumentGPR3);
2996 m_jit.poke(thisValuePayload, index++);
2997 m_jit.poke(thisValueTag, index++);
2999 m_jit.poke(propertyPayload, index++);
3000 m_jit.poke(propertyTag, index++);
3005 JSValueOperand value(this, m_jit.graph().varArgChild(node, 3));
3006 GPRReg valueTag = value.tagGPR();
3007 GPRReg valuePayload = value.payloadGPR();
3008 m_jit.poke(valuePayload, index++);
3009 m_jit.poke(valueTag, index++);
3012 appendCall(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis);
3013 m_jit.exceptionCheck();
3015 static_assert(GPRInfo::numberOfRegisters >= 8, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
3017 JSValueOperand base(this, m_jit.graph().varArgChild(node, 0));
3018 GPRReg baseTag = base.tagGPR();
3019 GPRReg basePayload = base.payloadGPR();
3021 JSValueOperand thisValue(this, m_jit.graph().varArgChild(node, 1));
3022 GPRReg thisValueTag = thisValue.tagGPR();
3023 GPRReg thisValuePayload = thisValue.payloadGPR();
3025 JSValueOperand property(this, m_jit.graph().varArgChild(node, 2));
3026 GPRReg propertyTag = property.tagGPR();
3027 GPRReg propertyPayload = property.payloadGPR();
3029 JSValueOperand value(this, m_jit.graph().varArgChild(node, 3));
3030 GPRReg valueTag = value.tagGPR();
3031 GPRReg valuePayload = value.payloadGPR();
3034 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis,
3035 NoResult, baseTag, basePayload, thisValueTag, thisValuePayload, propertyTag, propertyPayload, valueTag, valuePayload);
3036 m_jit.exceptionCheck();
3044 SpeculateCellOperand globalObject(this, node->child1());
3045 GPRReg globalObjectGPR = globalObject.gpr();
3047 if (node->child2().useKind() == RegExpObjectUse) {
3048 if (node->child3().useKind() == StringUse) {
3049 SpeculateCellOperand base(this, node->child2());
3050 SpeculateCellOperand argument(this, node->child3());
3051 GPRReg baseGPR = base.gpr();
3052 GPRReg argumentGPR = argument.gpr();
3053 speculateRegExpObject(node->child2(), baseGPR);
3054 speculateString(node->child3(), argumentGPR);
3057 GPRFlushedCallResult2 resultTag(this);
3058 GPRFlushedCallResult resultPayload(this);
3060 operationRegExpExecString, resultTag.gpr(), resultPayload.gpr(),
3061 globalObjectGPR, baseGPR, argumentGPR);
3062 m_jit.exceptionCheck();
3064 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
3068 SpeculateCellOperand base(this, node->child2());
3069 JSValueOperand argument(this, node->child3());
3070 GPRReg baseGPR = base.gpr();
3071 GPRReg argumentTagGPR = argument.tagGPR();
3072 GPRReg argumentPayloadGPR = argument.payloadGPR();
3073 speculateRegExpObject(node->child2(), baseGPR);
3076 GPRFlushedCallResult2 resultTag(this);
3077 GPRFlushedCallResult resultPayload(this);
3079 operationRegExpExec, resultTag.gpr(), resultPayload.gpr(), globalObjectGPR, baseGPR,
3080 argumentTagGPR, argumentPayloadGPR);
3081 m_jit.exceptionCheck();
3083 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
3087 JSValueOperand base(this, node->child2());
3088 JSValueOperand argument(this, node->child3());
3089 GPRReg baseTagGPR = base.tagGPR();
3090 GPRReg basePayloadGPR = base.payloadGPR();
3091 GPRReg argumentTagGPR = argument.tagGPR();
3092 GPRReg argumentPayloadGPR = argument.payloadGPR();
3095 GPRFlushedCallResult2 resultTag(this);
3096 GPRFlushedCallResult resultPayload(this);
3098 operationRegExpExecGeneric, resultTag.gpr(), resultPayload.gpr(), globalObjectGPR,
3099 baseTagGPR, basePayloadGPR, argumentTagGPR, argumentPayloadGPR);
3100 m_jit.exceptionCheck();
3102 jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
3107 SpeculateCellOperand globalObject(this, node->child1());
3108 GPRReg globalObjectGPR = globalObject.gpr();
3110 if (node->child2().useKind() == RegExpObjectUse) {
3111 if (node->child3().useKind() == StringUse) {
3112 SpeculateCellOperand base(this, node->child2());
3113 SpeculateCellOperand argument(this, node->child3());
3114 GPRReg baseGPR = base.gpr();
3115 GPRReg argumentGPR = argument.gpr();
3116 speculateRegExpObject(node->child2(), baseGPR);
3117 speculateString(node->child3(), argumentGPR);
3120 GPRFlushedCallResult result(this);
3122 operationRegExpTestString, result.gpr(), globalObjectGPR, baseGPR, argumentGPR);
3123 m_jit.exceptionCheck();
3125 booleanResult(result.gpr(), node);
3129 SpeculateCellOperand base(this, node->child2());
3130 JSValueOperand argument(this, node->child3());
3131 GPRReg baseGPR = base.gpr();
3132 GPRReg argumentTagGPR = argument.tagGPR();
3133 GPRReg argumentPayloadGPR = argument.payloadGPR();
3134 speculateRegExpObject(node->child2(), baseGPR);
3137 GPRFlushedCallResult result(this);
3139 operationRegExpTest, result.gpr(), globalObjectGPR, baseGPR, argumentTagGPR,
3140 argumentPayloadGPR);
3141 m_jit.exceptionCheck();
3143 booleanResult(result.gpr(), node);
3147 JSValueOperand base(this, node->child2());
3148 JSValueOperand argument(this, node->child3());
3149 GPRReg baseTagGPR = base.tagGPR();
3150 GPRReg basePayloadGPR = base.payloadGPR();
3151 GPRReg argumentTagGPR = argument.tagGPR();
3152 GPRReg argumentPayloadGPR = argument.payloadGPR();
3155 GPRFlushedCallResult result(this);
3157 operationRegExpTestGeneric, result.gpr(), globalObjectGPR, baseTagGPR, basePayloadGPR,
3158 argumentTagGPR, argumentPayloadGPR);
3159 m_jit.exceptionCheck();
3161 booleanResult(result.gpr(), node);
3166 case StringReplaceRegExp: {
3167 if (node->child1().useKind() == StringUse
3168 && node->child2().useKind() == RegExpObjectUse
3169 && node->child3().useKind() == StringUse) {
3170 if (JSString* replace = node->child3()->dynamicCastConstant<JSString*>()) {
3171 if (!replace->length()) {
3172 SpeculateCellOperand string(this, node->child1());
3173 SpeculateCellOperand regExp(this, node->child2());
3174 GPRReg stringGPR = string.gpr();
3175 GPRReg regExpGPR = regExp.gpr();
3176 speculateString(node->child1(), stringGPR);
3177 speculateRegExpObject(node->child2(), regExpGPR);
3180 GPRFlushedCallResult2 resultTag(this);
3181 GPRFlushedCallResult resultPayload(this);
3183 operationStringProtoFuncReplaceRegExpEmptyStr, resultTag.gpr(),
3184 resultPayload.gpr(), stringGPR, regExpGPR);
3185 m_jit.exceptionCheck();
3186 cellResult(resultPayload.gpr(), node);
3191 SpeculateCellOperand string(this, node->child1());
3192 SpeculateCellOperand regExp(this, node->child2());
3193 SpeculateCellOperand replace(this, node->child3());
3194 GPRReg stringGPR = string.gpr();
3195 GPRReg regExpGPR = regExp.gpr();
3196 GPRReg replaceGPR = replace.gpr();
3197 speculateString(node->child1(), stringGPR);
3198 speculateRegExpObject(node->child2(), regExpGPR);
3199 speculateString(node->child3(), replaceGPR);
3202 GPRFlushedCallResult2 resultTag(this);
3203 GPRFlushedCallResult resultPayload(this);
3205 operationStringProtoFuncReplaceRegExpString, resultTag.gpr(), resultPayload.gpr(),
3206 stringGPR, regExpGPR, replaceGPR);
3207 m_jit.exceptionCheck();
3208 cellResult(resultPayload.gpr(), node);
3212 // If we fixed up the edge of child2, we inserted a Check(@child2, String).
3213 OperandSpeculationMode child2SpeculationMode = AutomaticOperandSpeculation;
3214 if (node->child2().useKind() == StringUse)
3215 child2SpeculationMode = ManualOperandSpeculation;
3217 JSValueOperand string(this, node->child1());
3218 JSValueOperand search(this, node->child2(), child2SpeculationMode);
3219 JSValueOperand replace(this, node->child3());
3220 GPRReg stringTagGPR = string.tagGPR();
3221 GPRReg stringPayloadGPR = string.payloadGPR();
3222 GPRReg searchTagGPR = search.tagGPR();
3223 GPRReg searchPayloadGPR = search.payloadGPR();
3224 GPRReg replaceTagGPR = replace.tagGPR();
3225 GPRReg replacePayloadGPR = replace.payloadGPR();
3228 GPRFlushedCallResult2 resultTag(this);
3229 GPRFlushedCallResult resultPayload(this);
3231 operationStringProtoFuncReplaceGeneric, resultTag.gpr(), resultPayload.gpr(),
3232 stringTagGPR, stringPayloadGPR, searchTagGPR, searchPayloadGPR, replaceTagGPR,
3234 m_jit.exceptionCheck();
3235 cellResult(resultPayload.gpr(), node);
3239 case GetRegExpObjectLastIndex: {
3240 compileGetRegExpObjectLastIndex(node);
3244 case SetRegExpObjectLastIndex: {
3245 compileSetRegExpObjectLastIndex(node);
3249 case RecordRegExpCachedResult: {
3250 compileRecordRegExpCachedResult(node);
3255 ASSERT(node->arrayMode().isJSArray());
3257 SpeculateCellOperand base(this, node->child1());
3258 GPRTemporary storageLength(this);
3260 GPRReg baseGPR = base.gpr();
3261 GPRReg storageLengthGPR = storageLength.gpr();
3263 StorageOperand storage(this, node->child3());
3264 GPRReg storageGPR = storage.gpr();
3266 switch (node->arrayMode().type()) {
3267 case Array::Int32: {
3268 SpeculateInt32Operand value(this, node->child2());
3269 GPRReg valuePayloadGPR = value.gpr();
3271 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
3272 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
3273 m_jit.store32(TrustedImm32(JSValue::Int32Tag), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
3274 m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
3275 m_jit.add32(TrustedImm32(1), storageLengthGPR);
3276 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
3277 m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
3279 addSlowPathGenerator(
3281 slowPath, this, operationArrayPush,
3282 JSValueRegs(storageGPR, storageLengthGPR),
3283 TrustedImm32(JSValue::Int32Tag), valuePayloadGPR, baseGPR));
3285 jsValueResult(storageGPR, storageLengthGPR, node);
3289 case Array::Contiguous: {
3290 JSValueOperand value(this, node->child2());
3291 GPRReg valueTagGPR = value.tagGPR();
3292 GPRReg valuePayloadGPR = value.payloadGPR();
3294 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
3295 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
3296 m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
3297 m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
3298 m_jit.add32(TrustedImm32(1), storageLengthGPR);
3299 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
3300 m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
3302 addSlowPathGenerator(
3304 slowPath, this, operationArrayPush,
3305 JSValueRegs(storageGPR, storageLengthGPR),
3306 valueTagGPR, valuePayloadGPR, baseGPR));
3308 jsValueResult(storageGPR, storageLengthGPR, node);
3312 case Array::Double: {
3313 SpeculateDoubleOperand value(this, node->child2());
3314 FPRReg valueFPR = value.fpr();
3317 JSValueRegs(), node->child2(), SpecDoubleReal,
3318 m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
3320 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
3321 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
3322 m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
3323 m_jit.add32(TrustedImm32(1), storageLengthGPR);
3324 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
3325 m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
3327 addSlowPathGenerator(
3329 slowPath, this, operationArrayPushDouble,
3330 JSValueRegs(storageGPR, storageLengthGPR),
3331 valueFPR, baseGPR));
3333 jsValueResult(storageGPR, storageLengthGPR, node);
3337 case Array::ArrayStorage: {
3338 JSValueOperand value(this, node->child2());
3339 GPRReg valueTagGPR = value.tagGPR();
3340 GPRReg valuePayloadGPR = value.payloadGPR();
3342 m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
3344 // Refuse to handle bizarre lengths.
3345 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(0x7ffffffe)));
3347 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
3349 m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
3350 m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
3352 m_jit.add32(TrustedImm32(1), storageLengthGPR);
3353 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
3354 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
3355 m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
3357 addSlowPathGenerator(slowPathCall(slowPath, this, operationArrayPush, JSValueRegs(storageGPR, storageLengthGPR), valueTagGPR, valuePayloadGPR, baseGPR));
3359 jsValueResult(storageGPR, storageLengthGPR, node);
3371 ASSERT(node->arrayMode().isJSArray());
3373 SpeculateCellOperand base(this, node->child1());
3374 StorageOperand storage(this, node->child2());
3375 GPRTemporary valueTag(this);
3376 GPRTemporary valuePayload(this);
3378 GPRReg baseGPR = base.gpr();
3379 GPRReg valueTagGPR = valueTag.gpr();
3380 GPRReg valuePayloadGPR = valuePayload.gpr();
3381 GPRReg storageGPR = storage.gpr();
3383 switch (node->arrayMode().type()) {
3385 case Array::Contiguous: {
3387 MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), valuePayloadGPR);
3388 MacroAssembler::Jump undefinedCase =
3389 m_jit.branchTest32(MacroAssembler::Zero, valuePayloadGPR);
3390 m_jit.sub32(TrustedImm32(1), valuePayloadGPR);
3392 valuePayloadGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
3394 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)),
3396 MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
3398 MacroAssembler::TrustedImm32(JSValue::EmptyValueTag),
3399 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
3401 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)),
3404 addSlowPathGenerator(
3406 undefinedCase, this,
3407 MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR,
3408 MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR));
3409 addSlowPathGenerator(
3411 slowCase, this, operationArrayPopAndRecoverLength,
3412 JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR));
3414 jsValueResult(valueTagGPR, valuePayloadGPR, node);
3418 case Array::Double: {
3419 FPRTemporary temp(this);
3420 FPRReg tempFPR = temp.fpr();
3423 MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), valuePayloadGPR);
3424 MacroAssembler::Jump undefinedCase =
3425 m_jit.branchTest32(MacroAssembler::Zero, valuePayloadGPR);
3426 m_jit.sub32(TrustedImm32(1), valuePayloadGPR);
3428 valuePayloadGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
3430 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight),
3432 MacroAssembler::Jump slowCase = m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempFPR, tempFPR);
3433 JSValue nan = JSValue(JSValue::EncodeAsDouble, PNaN);
3435 MacroAssembler::TrustedImm32(nan.u.asBits.tag),
3436 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
3438 MacroAssembler::TrustedImm32(nan.u.asBits.payload),
3439 MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
3440 boxDouble(tempFPR, valueTagGPR, valuePayloadGPR);
3442 addSlowPathGenerator(
3444 undefinedCase, this,
3445 MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR,
3446 MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR));
3447 addSlowPathGenerator(
3449 slowCase, this, operationArrayPopAndRecoverLength,
3450 JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR));
3452 jsValueResult(valueTagGPR, valuePayloadGPR, node);
3456 case Array::ArrayStorage: {
3457 GPRTemporary storageLength(this);
3458 GPRReg storageLengthGPR = storageLength.gpr();
3460 m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
3462 JITCompiler::JumpList setUndefinedCases;
3463 setUndefinedCases.append(m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR));
3465 m_jit.sub32(TrustedImm32(1), storageLengthGPR);
3467 MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
3469 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), valueTagGPR);
3470 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), valuePayloadGPR);
3472 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
3474 setUndefinedCases.append(m_jit.branch32(MacroAssembler::Equal, TrustedImm32(JSValue::EmptyValueTag), valueTagGPR));
3476 m_jit.store32(TrustedImm32(JSValue::EmptyValueTag), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
3478 m_jit.sub32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
3480 addSlowPathGenerator(
3482 setUndefinedCases, this,
3483 MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR,
3484 MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR));
3486 addSlowPathGenerator(
3488 slowCase, this, operationArrayPop,
3489 JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR));
3491 jsValueResult(valueTagGPR, valuePayloadGPR, node);
3503 jump(node->targetBlock());
3517 ASSERT(GPRInfo::callFrameRegister != GPRInfo::regT2);
3518 ASSERT(GPRInfo::regT1 != GPRInfo::returnValueGPR);
3519 ASSERT(GPRInfo::returnValueGPR != GPRInfo::callFrameRegister);
3521 // Return the result in returnValueGPR.
3522 JSValueOperand op1(this, node->child1());
3525 boxDouble(op1.fpr(), GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
3527 if (op1.payloadGPR() == GPRInfo::returnValueGPR2 && op1.tagGPR() == GPRInfo::returnValueGPR)
3528 m_jit.swap(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2);
3529 else if (op1.payloadGPR() == GPRInfo::returnValueGPR2) {
3530 m_jit.move(op1.payloadGPR(), GPRInfo::returnValueGPR);
3531 m_jit.move(op1.tagGPR(), GPRInfo::returnValueGPR2);
3533 m_jit.move(op1.tagGPR(), GPRInfo::returnValueGPR2);
3534 m_jit.move(op1.payloadGPR(), GPRInfo::returnValueGPR);
3538 m_jit.emitRestoreCalleeSaves();
3539 m_jit.emitFunctionEpilogue();
3547 case ThrowReferenceError: {
3548 // We expect that throw statements are rare and are intended to exit the code block
3549 // anyway, so we just OSR back to the old JIT for now.
3550 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
3554 case BooleanToNumber: {
3555 switch (node->child1().useKind()) {
3557 SpeculateBooleanOperand value(this, node->child1());
3558 GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).
3560 m_jit.move(value.gpr(), result.gpr());
3562 int32Result(result.gpr(), node);
3567 JSValueOperand value(this, node->child1());
3569 if (!m_interpreter.needsTypeCheck(node->child1(), SpecBoolInt32 | SpecBoolean)) {
3570 GPRTemporary result(this);
3572 GPRReg valueGPR = value.payloadGPR();
3573 GPRReg resultGPR = result.gpr();
3575 m_jit.move(valueGPR, resultGPR);
3576 int32Result(result.gpr(), node);
3580 GPRTemporary resultTag(this);
3581 GPRTemporary resultPayload(this);
3583 GPRReg valueTagGPR = value.tagGPR();
3584 GPRReg valuePayloadGPR = value.payloadGPR();
3585 GPRReg resultTagGPR = resultTag.gpr();
3586 GPRReg resultPayloadGPR = resultPayload.gpr();
3588 m_jit.move(valuePayloadGPR, resultPayloadGPR);
3589 JITCompiler::Jump isBoolean = m_jit.branch32(
3590 JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::BooleanTag));
3591 m_jit.move(valueTagGPR, resultTagGPR);
3592 JITCompiler::Jump done = m_jit.jump();
3593 isBoolean.link(&m_jit);
3594 m_jit.move(TrustedImm32(JSValue::Int32Tag), resultTagGPR);
3597 jsValueResult(resultTagGPR, resultPayloadGPR, node);
3602 RELEASE_ASSERT_NOT_REACHED();
3609 RELEASE_ASSERT(node->child1().useKind() == UntypedUse);
3610 JSValueOperand argument(this, node->child1());
3611 GPRTemporary resultTag(this, Reuse, argument, TagWord);
3612 GPRTemporary resultPayload(this, Reuse, argument, PayloadWord);