1/*
2 * Copyright (C) 2011-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "DFGSpeculativeJIT.h"
28
29#if ENABLE(DFG_JIT)
30
31#include "ArrayPrototype.h"
32#include "AtomicsObject.h"
33#include "CallFrameShuffler.h"
34#include "DFGAbstractInterpreterInlines.h"
35#include "DFGCallArrayAllocatorSlowPathGenerator.h"
36#include "DFGDoesGC.h"
37#include "DFGOperations.h"
38#include "DFGSlowPathGenerator.h"
39#include "DirectArguments.h"
40#include "GetterSetter.h"
41#include "HasOwnPropertyCache.h"
42#include "JSCInlines.h"
43#include "JSLexicalEnvironment.h"
44#include "JSMap.h"
45#include "JSPropertyNameEnumerator.h"
46#include "JSSet.h"
47#include "ObjectPrototype.h"
48#include "SetupVarargsFrame.h"
49#include "SpillRegistersMode.h"
50#include "StringPrototype.h"
51#include "SuperSampler.h"
52#include "Watchdog.h"
53
54namespace JSC { namespace DFG {
55
56#if USE(JSVALUE64)
57
58void SpeculativeJIT::boxInt52(GPRReg sourceGPR, GPRReg targetGPR, DataFormat format)
59{
60 GPRReg tempGPR;
61 if (sourceGPR == targetGPR)
62 tempGPR = allocate();
63 else
64 tempGPR = targetGPR;
65
66 FPRReg fpr = fprAllocate();
67
68 if (format == DataFormatInt52)
69 m_jit.rshift64(TrustedImm32(JSValue::int52ShiftAmount), sourceGPR);
70 else
71 ASSERT(format == DataFormatStrictInt52);
72
73 m_jit.boxInt52(sourceGPR, targetGPR, tempGPR, fpr);
74
75 if (format == DataFormatInt52 && sourceGPR != targetGPR)
76 m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), sourceGPR);
77
78 if (tempGPR != targetGPR)
79 unlock(tempGPR);
80
81 unlock(fpr);
82}
83
84GPRReg SpeculativeJIT::fillJSValue(Edge edge)
85{
86 VirtualRegister virtualRegister = edge->virtualRegister();
87 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
88
89 switch (info.registerFormat()) {
90 case DataFormatNone: {
91 GPRReg gpr = allocate();
92
93 if (edge->hasConstant()) {
94 JSValue jsValue = edge->asJSValue();
95 m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr);
96 info.fillJSValue(*m_stream, gpr, DataFormatJS);
97 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
98 } else {
99 DataFormat spillFormat = info.spillFormat();
100 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
101 switch (spillFormat) {
102 case DataFormatInt32: {
103 m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr);
104 m_jit.or64(GPRInfo::tagTypeNumberRegister, gpr);
105 spillFormat = DataFormatJSInt32;
106 break;
107 }
108
109 default:
110 m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
111 DFG_ASSERT(m_jit.graph(), m_currentNode, spillFormat & DataFormatJS, spillFormat);
112 break;
113 }
114 info.fillJSValue(*m_stream, gpr, spillFormat);
115 }
116 return gpr;
117 }
118
119 case DataFormatInt32: {
120 GPRReg gpr = info.gpr();
121 // If the register has already been locked we need to take a copy.
122 // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInt32, not DataFormatJSInt32.
123 if (m_gprs.isLocked(gpr)) {
124 GPRReg result = allocate();
125 m_jit.or64(GPRInfo::tagTypeNumberRegister, gpr, result);
126 return result;
127 }
128 m_gprs.lock(gpr);
129 m_jit.or64(GPRInfo::tagTypeNumberRegister, gpr);
130 info.fillJSValue(*m_stream, gpr, DataFormatJSInt32);
131 return gpr;
132 }
133
134 case DataFormatCell:
135 // No retag required on JSVALUE64!
136 case DataFormatJS:
137 case DataFormatJSInt32:
138 case DataFormatJSDouble:
139 case DataFormatJSCell:
140 case DataFormatJSBoolean: {
141 GPRReg gpr = info.gpr();
142 m_gprs.lock(gpr);
143 return gpr;
144 }
145
146 case DataFormatBoolean:
147 case DataFormatStorage:
148 case DataFormatDouble:
149 case DataFormatInt52:
150 // this type currently never occurs
151 DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
152
153 default:
154 DFG_CRASH(m_jit.graph(), m_currentNode, "Corrupt data format");
155 return InvalidGPRReg;
156 }
157}
158
159void SpeculativeJIT::cachedGetById(CodeOrigin origin, JSValueRegs base, JSValueRegs result, unsigned identifierNumber, JITCompiler::Jump slowPathTarget , SpillRegistersMode mode, AccessType type)
160{
161 cachedGetById(origin, base.gpr(), result.gpr(), identifierNumber, slowPathTarget, mode, type);
162}
163
164void SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode, AccessType type)
165{
166 CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
167 RegisterSet usedRegisters = this->usedRegisters();
168 if (spillMode == DontSpill) {
169 // We've already flushed registers to the stack, we don't need to spill these.
170 usedRegisters.set(baseGPR, false);
171 usedRegisters.set(resultGPR, false);
172 }
173 JITGetByIdGenerator gen(
174 m_jit.codeBlock(), codeOrigin, callSite, usedRegisters, identifierUID(identifierNumber),
175 JSValueRegs(baseGPR), JSValueRegs(resultGPR), type);
176 gen.generateFastPath(m_jit);
177
178 JITCompiler::JumpList slowCases;
179 slowCases.append(slowPathTarget);
180 slowCases.append(gen.slowPathJump());
181
182 std::unique_ptr<SlowPathGenerator> slowPath = slowPathCall(
183 slowCases, this, appropriateOptimizingGetByIdFunction(type),
184 spillMode, ExceptionCheckRequirement::CheckNeeded,
185 resultGPR, gen.stubInfo(), baseGPR, identifierUID(identifierNumber));
186
187 m_jit.addGetById(gen, slowPath.get());
188 addSlowPathGenerator(WTFMove(slowPath));
189}
190
191void SpeculativeJIT::cachedGetByIdWithThis(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg thisGPR, GPRReg resultGPR, unsigned identifierNumber, const JITCompiler::JumpList& slowPathTarget)
192{
193 CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
194 RegisterSet usedRegisters = this->usedRegisters();
195 // We've already flushed registers to the stack, we don't need to spill these.
196 usedRegisters.set(baseGPR, false);
197 usedRegisters.set(thisGPR, false);
198 usedRegisters.set(resultGPR, false);
199
200 JITGetByIdWithThisGenerator gen(
201 m_jit.codeBlock(), codeOrigin, callSite, usedRegisters, identifierUID(identifierNumber),
202 JSValueRegs(resultGPR), JSValueRegs(baseGPR), JSValueRegs(thisGPR), AccessType::GetWithThis);
203 gen.generateFastPath(m_jit);
204
205 JITCompiler::JumpList slowCases;
206 slowCases.append(slowPathTarget);
207 slowCases.append(gen.slowPathJump());
208
209 std::unique_ptr<SlowPathGenerator> slowPath = slowPathCall(
210 slowCases, this, operationGetByIdWithThisOptimize,
211 DontSpill, ExceptionCheckRequirement::CheckNeeded,
212 resultGPR, gen.stubInfo(), baseGPR, thisGPR, identifierUID(identifierNumber));
213
214 m_jit.addGetByIdWithThis(gen, slowPath.get());
215 addSlowPathGenerator(WTFMove(slowPath));
216}
217
218void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNullOrUndefined(Edge operand)
219{
220 JSValueOperand arg(this, operand, ManualOperandSpeculation);
221 GPRReg argGPR = arg.gpr();
222
223 GPRTemporary result(this);
224 GPRReg resultGPR = result.gpr();
225
226 m_jit.move(TrustedImm32(0), resultGPR);
227
228 JITCompiler::JumpList done;
229 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
230 if (!isKnownNotCell(operand.node()))
231 done.append(m_jit.branchIfCell(JSValueRegs(argGPR)));
232 } else {
233 GPRTemporary localGlobalObject(this);
234 GPRTemporary remoteGlobalObject(this);
235 GPRTemporary scratch(this);
236
237 JITCompiler::Jump notCell;
238 if (!isKnownCell(operand.node()))
239 notCell = m_jit.branchIfNotCell(JSValueRegs(argGPR));
240
241 JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8(
242 JITCompiler::Zero,
243 JITCompiler::Address(argGPR, JSCell::typeInfoFlagsOffset()),
244 JITCompiler::TrustedImm32(MasqueradesAsUndefined));
245 done.append(isNotMasqueradesAsUndefined);
246
247 GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
248 GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
249 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.graph().globalObjectFor(m_currentNode->origin.semantic)), localGlobalObjectGPR);
250 m_jit.emitLoadStructure(*m_jit.vm(), argGPR, resultGPR, scratch.gpr());
251 m_jit.loadPtr(JITCompiler::Address(resultGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
252 m_jit.comparePtr(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, resultGPR);
253 done.append(m_jit.jump());
254 if (!isKnownCell(operand.node()))
255 notCell.link(&m_jit);
256 }
257
258 if (!isKnownNotOther(operand.node())) {
259 m_jit.move(argGPR, resultGPR);
260 m_jit.and64(JITCompiler::TrustedImm32(~TagBitUndefined), resultGPR);
261 m_jit.compare64(JITCompiler::Equal, resultGPR, JITCompiler::TrustedImm32(ValueNull), resultGPR);
262 }
263
264 done.link(&m_jit);
265
266 m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
267 jsValueResult(resultGPR, m_currentNode, DataFormatJSBoolean);
268}
269
270void SpeculativeJIT::nonSpeculativePeepholeBranchNullOrUndefined(Edge operand, Node* branchNode)
271{
272 BasicBlock* taken = branchNode->branchData()->taken.block;
273 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
274
275 JSValueOperand arg(this, operand, ManualOperandSpeculation);
276 GPRReg argGPR = arg.gpr();
277
278 GPRTemporary result(this, Reuse, arg);
279 GPRReg resultGPR = result.gpr();
280
281 // First, handle the case where "operand" is a cell.
282 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
283 if (!isKnownNotCell(operand.node())) {
284 JITCompiler::Jump isCell = m_jit.branchIfCell(JSValueRegs(argGPR));
285 addBranch(isCell, notTaken);
286 }
287 } else {
288 GPRTemporary localGlobalObject(this);
289 GPRTemporary remoteGlobalObject(this);
290 GPRTemporary scratch(this);
291
292 JITCompiler::Jump notCell;
293 if (!isKnownCell(operand.node()))
294 notCell = m_jit.branchIfNotCell(JSValueRegs(argGPR));
295
296 branchTest8(JITCompiler::Zero,
297 JITCompiler::Address(argGPR, JSCell::typeInfoFlagsOffset()),
298 JITCompiler::TrustedImm32(MasqueradesAsUndefined), notTaken);
299
300 GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
301 GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
302 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.graph().globalObjectFor(m_currentNode->origin.semantic)), localGlobalObjectGPR);
303 m_jit.emitLoadStructure(*m_jit.vm(), argGPR, resultGPR, scratch.gpr());
304 m_jit.loadPtr(JITCompiler::Address(resultGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
305 branchPtr(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, taken);
306
307 if (!isKnownCell(operand.node())) {
308 jump(notTaken, ForceJump);
309 notCell.link(&m_jit);
310 }
311 }
312
313 if (isKnownNotOther(operand.node()))
314 jump(notTaken);
315 else {
316 JITCompiler::RelationalCondition condition = JITCompiler::Equal;
317 if (taken == nextBlock()) {
318 condition = JITCompiler::NotEqual;
319 std::swap(taken, notTaken);
320 }
321 m_jit.move(argGPR, resultGPR);
322 m_jit.and64(JITCompiler::TrustedImm32(~TagBitUndefined), resultGPR);
323 branch64(condition, resultGPR, JITCompiler::TrustedImm64(ValueNull), taken);
324 jump(notTaken);
325 }
326}
327
328void SpeculativeJIT::nonSpeculativePeepholeStrictEq(Node* node, Node* branchNode, bool invert)
329{
330 BasicBlock* taken = branchNode->branchData()->taken.block;
331 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
332
333 // The branch instruction will branch to the taken block.
334 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
335 if (taken == nextBlock()) {
336 invert = !invert;
337 BasicBlock* tmp = taken;
338 taken = notTaken;
339 notTaken = tmp;
340 }
341
342 JSValueOperand arg1(this, node->child1());
343 JSValueOperand arg2(this, node->child2());
344 GPRReg arg1GPR = arg1.gpr();
345 GPRReg arg2GPR = arg2.gpr();
346
347 GPRTemporary result(this);
348 GPRReg resultGPR = result.gpr();
349
350 arg1.use();
351 arg2.use();
352
353 if (isKnownCell(node->child1().node()) && isKnownCell(node->child2().node())) {
354 // see if we get lucky: if the arguments are cells and they reference the same
355 // cell, then they must be strictly equal.
356 branch64(JITCompiler::Equal, arg1GPR, arg2GPR, invert ? notTaken : taken);
357
358 silentSpillAllRegisters(resultGPR);
359 callOperation(operationCompareStrictEqCell, resultGPR, arg1GPR, arg2GPR);
360 silentFillAllRegisters();
361 m_jit.exceptionCheck();
362
363 branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, resultGPR, taken);
364 } else {
365 m_jit.or64(arg1GPR, arg2GPR, resultGPR);
366
367 JITCompiler::Jump twoCellsCase = m_jit.branchIfCell(resultGPR);
368
369 JITCompiler::Jump leftOK = m_jit.branchIfInt32(arg1GPR);
370 JITCompiler::Jump leftDouble = m_jit.branchIfNumber(arg1GPR);
371 leftOK.link(&m_jit);
372 JITCompiler::Jump rightOK = m_jit.branchIfInt32(arg2GPR);
373 JITCompiler::Jump rightDouble = m_jit.branchIfNumber(arg2GPR);
374 rightOK.link(&m_jit);
375
376 branch64(invert ? JITCompiler::NotEqual : JITCompiler::Equal, arg1GPR, arg2GPR, taken);
377 jump(notTaken, ForceJump);
378
379 twoCellsCase.link(&m_jit);
380 branch64(JITCompiler::Equal, arg1GPR, arg2GPR, invert ? notTaken : taken);
381
382 leftDouble.link(&m_jit);
383 rightDouble.link(&m_jit);
384
385 silentSpillAllRegisters(resultGPR);
386 callOperation(operationCompareStrictEq, resultGPR, arg1GPR, arg2GPR);
387 silentFillAllRegisters();
388 m_jit.exceptionCheck();
389
390 branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, resultGPR, taken);
391 }
392
393 jump(notTaken);
394}
395
396void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node* node, bool invert)
397{
398 JSValueOperand arg1(this, node->child1());
399 JSValueOperand arg2(this, node->child2());
400 JSValueRegs arg1Regs = arg1.jsValueRegs();
401 JSValueRegs arg2Regs = arg2.jsValueRegs();
402
403 GPRTemporary result(this);
404 GPRReg resultGPR = result.gpr();
405
406 arg1.use();
407 arg2.use();
408
409 if (isKnownCell(node->child1().node()) && isKnownCell(node->child2().node())) {
410 // see if we get lucky: if the arguments are cells and they reference the same
411 // cell, then they must be strictly equal.
412 // FIXME: this should flush registers instead of silent spill/fill.
413 JITCompiler::Jump notEqualCase = m_jit.branch64(JITCompiler::NotEqual, arg1Regs.gpr(), arg2Regs.gpr());
414
415 m_jit.move(JITCompiler::TrustedImm64(!invert), resultGPR);
416
417 JITCompiler::Jump done = m_jit.jump();
418
419 notEqualCase.link(&m_jit);
420
421 silentSpillAllRegisters(resultGPR);
422 callOperation(operationCompareStrictEqCell, resultGPR, arg1Regs, arg2Regs);
423 silentFillAllRegisters();
424 m_jit.exceptionCheck();
425
426 done.link(&m_jit);
427 unblessedBooleanResult(resultGPR, m_currentNode, UseChildrenCalledExplicitly);
428 return;
429 }
430
431 m_jit.or64(arg1Regs.gpr(), arg2Regs.gpr(), resultGPR);
432
433 JITCompiler::JumpList slowPathCases;
434
435 JITCompiler::Jump twoCellsCase = m_jit.branchIfCell(resultGPR);
436
437 JITCompiler::Jump leftOK = m_jit.branchIfInt32(arg1Regs);
438 slowPathCases.append(m_jit.branchIfNumber(arg1Regs, InvalidGPRReg));
439 leftOK.link(&m_jit);
440 JITCompiler::Jump rightOK = m_jit.branchIfInt32(arg2Regs);
441 slowPathCases.append(m_jit.branchIfNumber(arg2Regs, InvalidGPRReg));
442 rightOK.link(&m_jit);
443
444 m_jit.compare64(invert ? JITCompiler::NotEqual : JITCompiler::Equal, arg1Regs.gpr(), arg2Regs.gpr(), resultGPR);
445
446 JITCompiler::Jump done = m_jit.jump();
447
448 twoCellsCase.link(&m_jit);
449 slowPathCases.append(m_jit.branch64(JITCompiler::NotEqual, arg1Regs.gpr(), arg2Regs.gpr()));
450
451 m_jit.move(JITCompiler::TrustedImm64(!invert), resultGPR);
452
453 addSlowPathGenerator(slowPathCall(slowPathCases, this, operationCompareStrictEq, resultGPR, arg1Regs, arg2Regs));
454
455 done.link(&m_jit);
456
457 unblessedBooleanResult(resultGPR, m_currentNode, UseChildrenCalledExplicitly);
458}
459
460void SpeculativeJIT::emitCall(Node* node)
461{
462 CallLinkInfo::CallType callType;
463 bool isVarargs = false;
464 bool isForwardVarargs = false;
465 bool isTail = false;
466 bool isEmulatedTail = false;
467 bool isDirect = false;
468 switch (node->op()) {
469 case Call:
470 case CallEval:
471 callType = CallLinkInfo::Call;
472 break;
473 case TailCall:
474 callType = CallLinkInfo::TailCall;
475 isTail = true;
476 break;
477 case TailCallInlinedCaller:
478 callType = CallLinkInfo::Call;
479 isEmulatedTail = true;
480 break;
481 case Construct:
482 callType = CallLinkInfo::Construct;
483 break;
484 case CallVarargs:
485 callType = CallLinkInfo::CallVarargs;
486 isVarargs = true;
487 break;
488 case TailCallVarargs:
489 callType = CallLinkInfo::TailCallVarargs;
490 isVarargs = true;
491 isTail = true;
492 break;
493 case TailCallVarargsInlinedCaller:
494 callType = CallLinkInfo::CallVarargs;
495 isVarargs = true;
496 isEmulatedTail = true;
497 break;
498 case ConstructVarargs:
499 callType = CallLinkInfo::ConstructVarargs;
500 isVarargs = true;
501 break;
502 case CallForwardVarargs:
503 callType = CallLinkInfo::CallVarargs;
504 isForwardVarargs = true;
505 break;
506 case ConstructForwardVarargs:
507 callType = CallLinkInfo::ConstructVarargs;
508 isForwardVarargs = true;
509 break;
510 case TailCallForwardVarargs:
511 callType = CallLinkInfo::TailCallVarargs;
512 isTail = true;
513 isForwardVarargs = true;
514 break;
515 case TailCallForwardVarargsInlinedCaller:
516 callType = CallLinkInfo::CallVarargs;
517 isEmulatedTail = true;
518 isForwardVarargs = true;
519 break;
520 case DirectCall:
521 callType = CallLinkInfo::DirectCall;
522 isDirect = true;
523 break;
524 case DirectConstruct:
525 callType = CallLinkInfo::DirectConstruct;
526 isDirect = true;
527 break;
528 case DirectTailCall:
529 callType = CallLinkInfo::DirectTailCall;
530 isTail = true;
531 isDirect = true;
532 break;
533 case DirectTailCallInlinedCaller:
534 callType = CallLinkInfo::DirectCall;
535 isEmulatedTail = true;
536 isDirect = true;
537 break;
538 default:
539 DFG_CRASH(m_jit.graph(), node, "bad node type");
540 break;
541 }
542
543 GPRReg calleeGPR = InvalidGPRReg;
544 CallFrameShuffleData shuffleData;
545
546 ExecutableBase* executable = nullptr;
547 FunctionExecutable* functionExecutable = nullptr;
548 if (isDirect) {
549 executable = node->castOperand<ExecutableBase*>();
550 functionExecutable = jsDynamicCast<FunctionExecutable*>(*m_jit.vm(), executable);
551 }
552
553 unsigned numPassedArgs = 0;
554 unsigned numAllocatedArgs = 0;
555
556 // Gotta load the arguments somehow. Varargs is trickier.
557 if (isVarargs || isForwardVarargs) {
558 RELEASE_ASSERT(!isDirect);
559 CallVarargsData* data = node->callVarargsData();
560
561 int numUsedStackSlots = m_jit.graph().m_nextMachineLocal;
562
563 if (isForwardVarargs) {
564 flushRegisters();
565 if (node->child3())
566 use(node->child3());
567
568 GPRReg scratchGPR1;
569 GPRReg scratchGPR2;
570 GPRReg scratchGPR3;
571
572 scratchGPR1 = JITCompiler::selectScratchGPR();
573 scratchGPR2 = JITCompiler::selectScratchGPR(scratchGPR1);
574 scratchGPR3 = JITCompiler::selectScratchGPR(scratchGPR1, scratchGPR2);
575
576 m_jit.move(TrustedImm32(numUsedStackSlots), scratchGPR2);
577 JITCompiler::JumpList slowCase;
578 InlineCallFrame* inlineCallFrame;
579 if (node->child3())
580 inlineCallFrame = node->child3()->origin.semantic.inlineCallFrame();
581 else
582 inlineCallFrame = node->origin.semantic.inlineCallFrame();
583 // emitSetupVarargsFrameFastCase modifies the stack pointer if it succeeds.
584 emitSetupVarargsFrameFastCase(*m_jit.vm(), m_jit, scratchGPR2, scratchGPR1, scratchGPR2, scratchGPR3, inlineCallFrame, data->firstVarArgOffset, slowCase);
585 JITCompiler::Jump done = m_jit.jump();
586 slowCase.link(&m_jit);
587 callOperation(operationThrowStackOverflowForVarargs);
588 m_jit.exceptionCheck();
589 m_jit.abortWithReason(DFGVarargsThrowingPathDidNotThrow);
590 done.link(&m_jit);
591 } else {
592 GPRReg argumentsGPR;
593 GPRReg scratchGPR1;
594 GPRReg scratchGPR2;
595 GPRReg scratchGPR3;
596
597 auto loadArgumentsGPR = [&] (GPRReg reservedGPR) {
598 if (reservedGPR != InvalidGPRReg)
599 lock(reservedGPR);
600 JSValueOperand arguments(this, node->child3());
601 argumentsGPR = arguments.gpr();
602 if (reservedGPR != InvalidGPRReg)
603 unlock(reservedGPR);
604 flushRegisters();
605
606 scratchGPR1 = JITCompiler::selectScratchGPR(argumentsGPR, reservedGPR);
607 scratchGPR2 = JITCompiler::selectScratchGPR(argumentsGPR, scratchGPR1, reservedGPR);
608 scratchGPR3 = JITCompiler::selectScratchGPR(argumentsGPR, scratchGPR1, scratchGPR2, reservedGPR);
609 };
610
611 loadArgumentsGPR(InvalidGPRReg);
612
613 DFG_ASSERT(m_jit.graph(), node, isFlushed());
614
615 // Right now, arguments is in argumentsGPR and the register file is flushed.
616 callOperation(operationSizeFrameForVarargs, GPRInfo::returnValueGPR, argumentsGPR, numUsedStackSlots, data->firstVarArgOffset);
617 m_jit.exceptionCheck();
618
619 // Now we have the argument count of the callee frame, but we've lost the arguments operand.
620 // Reconstruct the arguments operand while preserving the callee frame.
621 loadArgumentsGPR(GPRInfo::returnValueGPR);
622 m_jit.move(TrustedImm32(numUsedStackSlots), scratchGPR1);
623 emitSetVarargsFrame(m_jit, GPRInfo::returnValueGPR, false, scratchGPR1, scratchGPR1);
624 m_jit.addPtr(TrustedImm32(-(sizeof(CallerFrameAndPC) + WTF::roundUpToMultipleOf(stackAlignmentBytes(), 5 * sizeof(void*)))), scratchGPR1, JITCompiler::stackPointerRegister);
625
626 callOperation(operationSetupVarargsFrame, GPRInfo::returnValueGPR, scratchGPR1, argumentsGPR, data->firstVarArgOffset, GPRInfo::returnValueGPR);
627 m_jit.exceptionCheck();
628 m_jit.addPtr(TrustedImm32(sizeof(CallerFrameAndPC)), GPRInfo::returnValueGPR, JITCompiler::stackPointerRegister);
629 }
630
631 DFG_ASSERT(m_jit.graph(), node, isFlushed());
632
633 // We don't need the arguments array anymore.
634 if (isVarargs)
635 use(node->child3());
636
637 // Now set up the "this" argument.
638 JSValueOperand thisArgument(this, node->child2());
639 GPRReg thisArgumentGPR = thisArgument.gpr();
640 thisArgument.use();
641
642 m_jit.store64(thisArgumentGPR, JITCompiler::calleeArgumentSlot(0));
643 } else {
644 // The call instruction's first child is the function; the subsequent children are the
645 // arguments.
646 numPassedArgs = node->numChildren() - 1;
647 numAllocatedArgs = numPassedArgs;
648
649 if (functionExecutable) {
650 // Allocate more args if this would let us avoid arity checks. This is throttled by
651 // CallLinkInfo's limit. It's probably good to throttle it - if the callee wants a
652 // ginormous amount of argument space then it's better for them to do it so that when we
653 // make calls to other things, we don't waste space.
654 unsigned desiredNumAllocatedArgs = static_cast<unsigned>(functionExecutable->parameterCount()) + 1;
655 if (desiredNumAllocatedArgs <= Options::maximumDirectCallStackSize()) {
656 numAllocatedArgs = std::max(numAllocatedArgs, desiredNumAllocatedArgs);
657
658 // Whoever converts to DirectCall should do this adjustment. It's too late for us to
659 // do this adjustment now since we will have already emitted code that relied on the
660 // value of m_parameterSlots.
661 DFG_ASSERT(
662 m_jit.graph(), node,
663 Graph::parameterSlotsForArgCount(numAllocatedArgs)
664 <= m_jit.graph().m_parameterSlots);
665 }
666 }
667
668 if (isTail) {
669 Edge calleeEdge = m_jit.graph().child(node, 0);
670 JSValueOperand callee(this, calleeEdge);
671 calleeGPR = callee.gpr();
672 if (!isDirect)
673 callee.use();
674
675 shuffleData.tagTypeNumber = GPRInfo::tagTypeNumberRegister;
676 shuffleData.numLocals = m_jit.graph().frameRegisterCount();
677 shuffleData.callee = ValueRecovery::inGPR(calleeGPR, DataFormatJS);
678 shuffleData.args.resize(numAllocatedArgs);
679 shuffleData.numPassedArgs = numPassedArgs;
680
681 for (unsigned i = 0; i < numPassedArgs; ++i) {
682 Edge argEdge = m_jit.graph().varArgChild(node, i + 1);
683 GenerationInfo& info = generationInfo(argEdge.node());
684 if (!isDirect)
685 use(argEdge);
686 shuffleData.args[i] = info.recovery(argEdge->virtualRegister());
687 }
688
689 for (unsigned i = numPassedArgs; i < numAllocatedArgs; ++i)
690 shuffleData.args[i] = ValueRecovery::constant(jsUndefined());
691
692 shuffleData.setupCalleeSaveRegisters(m_jit.codeBlock());
693 } else {
694 m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), JITCompiler::calleeFramePayloadSlot(CallFrameSlot::argumentCount));
695
696 for (unsigned i = 0; i < numPassedArgs; i++) {
697 Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
698 JSValueOperand arg(this, argEdge);
699 GPRReg argGPR = arg.gpr();
700 use(argEdge);
701
702 m_jit.store64(argGPR, JITCompiler::calleeArgumentSlot(i));
703 }
704
705 for (unsigned i = numPassedArgs; i < numAllocatedArgs; ++i)
706 m_jit.storeTrustedValue(jsUndefined(), JITCompiler::calleeArgumentSlot(i));
707 }
708 }
709
710 if (!isTail || isVarargs || isForwardVarargs) {
711 Edge calleeEdge = m_jit.graph().child(node, 0);
712 JSValueOperand callee(this, calleeEdge);
713 calleeGPR = callee.gpr();
714 callee.use();
715 m_jit.store64(calleeGPR, JITCompiler::calleeFrameSlot(CallFrameSlot::callee));
716
717 flushRegisters();
718 }
719
720 CodeOrigin staticOrigin = node->origin.semantic;
721 InlineCallFrame* staticInlineCallFrame = staticOrigin.inlineCallFrame();
722 ASSERT(!isTail || !staticInlineCallFrame || !staticInlineCallFrame->getCallerSkippingTailCalls());
723 ASSERT(!isEmulatedTail || (staticInlineCallFrame && staticInlineCallFrame->getCallerSkippingTailCalls()));
724 CodeOrigin dynamicOrigin =
725 isEmulatedTail ? *staticInlineCallFrame->getCallerSkippingTailCalls() : staticOrigin;
726
727 CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(dynamicOrigin, m_stream->size());
728
729 auto setResultAndResetStack = [&] () {
730 GPRFlushedCallResult result(this);
731 GPRReg resultGPR = result.gpr();
732 m_jit.move(GPRInfo::returnValueGPR, resultGPR);
733
734 jsValueResult(resultGPR, m_currentNode, DataFormatJS, UseChildrenCalledExplicitly);
735
736 // After the calls are done, we need to reestablish our stack
737 // pointer. We rely on this for varargs calls, calls with arity
738 // mismatch (the callframe is slided) and tail calls.
739 m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister);
740 };
741
742 CallLinkInfo* callLinkInfo = m_jit.codeBlock()->addCallLinkInfo();
743 callLinkInfo->setUpCall(callType, m_currentNode->origin.semantic, calleeGPR);
744
745 if (node->op() == CallEval) {
746 // We want to call operationCallEval but we don't want to overwrite the parameter area in
747 // which we have created a prototypical eval call frame. This means that we have to
748 // subtract stack to make room for the call. Lucky for us, at this point we have the whole
749 // register file to ourselves.
750
751 m_jit.emitStoreCallSiteIndex(callSite);
752 m_jit.addPtr(TrustedImm32(-static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC))), JITCompiler::stackPointerRegister, GPRInfo::regT0);
753 m_jit.storePtr(GPRInfo::callFrameRegister, JITCompiler::Address(GPRInfo::regT0, CallFrame::callerFrameOffset()));
754
755 // Now we need to make room for:
756 // - The caller frame and PC of a call to operationCallEval.
757 // - Potentially two arguments on the stack.
758 unsigned requiredBytes = sizeof(CallerFrameAndPC) + sizeof(ExecState*) * 2;
759 requiredBytes = WTF::roundUpToMultipleOf(stackAlignmentBytes(), requiredBytes);
760 m_jit.subPtr(TrustedImm32(requiredBytes), JITCompiler::stackPointerRegister);
761 m_jit.setupArguments<decltype(operationCallEval)>(GPRInfo::regT0);
762 prepareForExternalCall();
763 m_jit.appendCall(operationCallEval);
764 m_jit.exceptionCheck();
765 JITCompiler::Jump done = m_jit.branchIfNotEmpty(GPRInfo::returnValueGPR);
766
767 // This is the part where we meant to make a normal call. Oops.
768 m_jit.addPtr(TrustedImm32(requiredBytes), JITCompiler::stackPointerRegister);
769 m_jit.load64(JITCompiler::calleeFrameSlot(CallFrameSlot::callee), GPRInfo::regT0);
770 m_jit.emitDumbVirtualCall(*m_jit.vm(), callLinkInfo);
771
772 done.link(&m_jit);
773 setResultAndResetStack();
774 return;
775 }
776
777 if (isDirect) {
778 callLinkInfo->setExecutableDuringCompilation(executable);
779 callLinkInfo->setMaxNumArguments(numAllocatedArgs);
780
781 if (isTail) {
782 RELEASE_ASSERT(node->op() == DirectTailCall);
783
784 JITCompiler::PatchableJump patchableJump = m_jit.patchableJump();
785 JITCompiler::Label mainPath = m_jit.label();
786
787 m_jit.emitStoreCallSiteIndex(callSite);
788
789 callLinkInfo->setFrameShuffleData(shuffleData);
790 CallFrameShuffler(m_jit, shuffleData).prepareForTailCall();
791
792 JITCompiler::Call call = m_jit.nearTailCall();
793
794 JITCompiler::Label slowPath = m_jit.label();
795 patchableJump.m_jump.linkTo(slowPath, &m_jit);
796
797 silentSpillAllRegisters(InvalidGPRReg);
798 callOperation(operationLinkDirectCall, callLinkInfo, calleeGPR);
799 silentFillAllRegisters();
800 m_jit.exceptionCheck();
801 m_jit.jump().linkTo(mainPath, &m_jit);
802
803 useChildren(node);
804
805 m_jit.addJSDirectTailCall(patchableJump, call, slowPath, callLinkInfo);
806 return;
807 }
808
809 JITCompiler::Label mainPath = m_jit.label();
810
811 m_jit.emitStoreCallSiteIndex(callSite);
812
813 JITCompiler::Call call = m_jit.nearCall();
814 JITCompiler::Jump done = m_jit.jump();
815
816 JITCompiler::Label slowPath = m_jit.label();
817 if (isX86())
818 m_jit.pop(JITCompiler::selectScratchGPR(calleeGPR));
819
820 callOperation(operationLinkDirectCall, callLinkInfo, calleeGPR);
821 m_jit.exceptionCheck();
822 m_jit.jump().linkTo(mainPath, &m_jit);
823
824 done.link(&m_jit);
825
826 setResultAndResetStack();
827
828 m_jit.addJSDirectCall(call, slowPath, callLinkInfo);
829 return;
830 }
831
832 m_jit.emitStoreCallSiteIndex(callSite);
833
834 JITCompiler::DataLabelPtr targetToCheck;
835 JITCompiler::Jump slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleeGPR, targetToCheck, TrustedImmPtr(nullptr));
836
837 if (isTail) {
838 if (node->op() == TailCall) {
839 callLinkInfo->setFrameShuffleData(shuffleData);
840 CallFrameShuffler(m_jit, shuffleData).prepareForTailCall();
841 } else {
842 m_jit.emitRestoreCalleeSaves();
843 m_jit.prepareForTailCallSlow();
844 }
845 }
846
847 JITCompiler::Call fastCall = isTail ? m_jit.nearTailCall() : m_jit.nearCall();
848
849 JITCompiler::Jump done = m_jit.jump();
850
851 slowPath.link(&m_jit);
852
853 if (node->op() == TailCall) {
854 CallFrameShuffler callFrameShuffler(m_jit, shuffleData);
855 callFrameShuffler.setCalleeJSValueRegs(JSValueRegs(GPRInfo::regT0));
856 callFrameShuffler.prepareForSlowPath();
857 } else {
858 m_jit.move(calleeGPR, GPRInfo::regT0); // Callee needs to be in regT0
859
860 if (isTail)
861 m_jit.emitRestoreCalleeSaves(); // This needs to happen after we moved calleeGPR to regT0
862 }
863
864 m_jit.move(TrustedImmPtr(callLinkInfo), GPRInfo::regT2); // Link info needs to be in regT2
865 JITCompiler::Call slowCall = m_jit.nearCall();
866
867 done.link(&m_jit);
868
869 if (isTail)
870 m_jit.abortWithReason(JITDidReturnFromTailCall);
871 else
872 setResultAndResetStack();
873
874 m_jit.addJSCall(fastCall, slowCall, targetToCheck, callLinkInfo);
875}
876
877// Clang should allow unreachable [[clang::fallthrough]] in template functions if any template expansion uses it
878// http://llvm.org/bugs/show_bug.cgi?id=18619
879IGNORE_WARNINGS_BEGIN("implicit-fallthrough")
880template<bool strict>
881GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnFormat)
882{
883 AbstractValue& value = m_state.forNode(edge);
884 SpeculatedType type = value.m_type;
885 ASSERT(edge.useKind() != KnownInt32Use || !(value.m_type & ~SpecInt32Only));
886
887 m_interpreter.filter(value, SpecInt32Only);
888 if (value.isClear()) {
889 if (mayHaveTypeCheck(edge.useKind()))
890 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
891 returnFormat = DataFormatInt32;
892 return allocate();
893 }
894
895 VirtualRegister virtualRegister = edge->virtualRegister();
896 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
897
898 switch (info.registerFormat()) {
899 case DataFormatNone: {
900 GPRReg gpr = allocate();
901
902 if (edge->hasConstant()) {
903 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
904 ASSERT(edge->isInt32Constant());
905 m_jit.move(MacroAssembler::Imm32(edge->asInt32()), gpr);
906 info.fillInt32(*m_stream, gpr);
907 returnFormat = DataFormatInt32;
908 return gpr;
909 }
910
911 DataFormat spillFormat = info.spillFormat();
912
913 DFG_ASSERT(m_jit.graph(), m_currentNode, (spillFormat & DataFormatJS) || spillFormat == DataFormatInt32, spillFormat);
914
915 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
916
917 if (spillFormat == DataFormatJSInt32 || spillFormat == DataFormatInt32) {
918 // If we know this was spilled as an integer we can fill without checking.
919 if (strict) {
920 m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr);
921 info.fillInt32(*m_stream, gpr);
922 returnFormat = DataFormatInt32;
923 return gpr;
924 }
925 if (spillFormat == DataFormatInt32) {
926 m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr);
927 info.fillInt32(*m_stream, gpr);
928 returnFormat = DataFormatInt32;
929 } else {
930 m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
931 info.fillJSValue(*m_stream, gpr, DataFormatJSInt32);
932 returnFormat = DataFormatJSInt32;
933 }
934 return gpr;
935 }
936 m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
937
938 // Fill as JSValue, and fall through.
939 info.fillJSValue(*m_stream, gpr, DataFormatJSInt32);
940 m_gprs.unlock(gpr);
941 FALLTHROUGH;
942 }
943
944 case DataFormatJS: {
945 DFG_ASSERT(m_jit.graph(), m_currentNode, !(type & SpecInt52Any));
946 // Check the value is an integer.
947 GPRReg gpr = info.gpr();
948 m_gprs.lock(gpr);
949 if (type & ~SpecInt32Only)
950 speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branchIfNotInt32(gpr));
951 info.fillJSValue(*m_stream, gpr, DataFormatJSInt32);
952 // If !strict we're done, return.
953 if (!strict) {
954 returnFormat = DataFormatJSInt32;
955 return gpr;
956 }
957 // else fall through & handle as DataFormatJSInt32.
958 m_gprs.unlock(gpr);
959 FALLTHROUGH;
960 }
961
962 case DataFormatJSInt32: {
963 // In a strict fill we need to strip off the value tag.
964 if (strict) {
965 GPRReg gpr = info.gpr();
966 GPRReg result;
967 // If the register has already been locked we need to take a copy.
968 // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInt32, not DataFormatJSInt32.
969 if (m_gprs.isLocked(gpr))
970 result = allocate();
971 else {
972 m_gprs.lock(gpr);
973 info.fillInt32(*m_stream, gpr);
974 result = gpr;
975 }
976 m_jit.zeroExtend32ToPtr(gpr, result);
977 returnFormat = DataFormatInt32;
978 return result;
979 }
980
981 GPRReg gpr = info.gpr();
982 m_gprs.lock(gpr);
983 returnFormat = DataFormatJSInt32;
984 return gpr;
985 }
986
987 case DataFormatInt32: {
988 GPRReg gpr = info.gpr();
989 m_gprs.lock(gpr);
990 returnFormat = DataFormatInt32;
991 return gpr;
992 }
993
994 case DataFormatJSDouble:
995 case DataFormatCell:
996 case DataFormatBoolean:
997 case DataFormatJSCell:
998 case DataFormatJSBoolean:
999 case DataFormatDouble:
1000 case DataFormatStorage:
1001 case DataFormatInt52:
1002 case DataFormatStrictInt52:
1003 DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
1004
1005 default:
1006 DFG_CRASH(m_jit.graph(), m_currentNode, "Corrupt data format");
1007 return InvalidGPRReg;
1008 }
1009}
1010IGNORE_WARNINGS_END
1011
1012GPRReg SpeculativeJIT::fillSpeculateInt32(Edge edge, DataFormat& returnFormat)
1013{
1014 return fillSpeculateInt32Internal<false>(edge, returnFormat);
1015}
1016
1017GPRReg SpeculativeJIT::fillSpeculateInt32Strict(Edge edge)
1018{
1019 DataFormat mustBeDataFormatInt32;
1020 GPRReg result = fillSpeculateInt32Internal<true>(edge, mustBeDataFormatInt32);
1021 DFG_ASSERT(m_jit.graph(), m_currentNode, mustBeDataFormatInt32 == DataFormatInt32, mustBeDataFormatInt32);
1022 return result;
1023}
1024
1025GPRReg SpeculativeJIT::fillSpeculateInt52(Edge edge, DataFormat desiredFormat)
1026{
1027 ASSERT(desiredFormat == DataFormatInt52 || desiredFormat == DataFormatStrictInt52);
1028 AbstractValue& value = m_state.forNode(edge);
1029
1030 m_interpreter.filter(value, SpecInt52Any);
1031 if (value.isClear()) {
1032 if (mayHaveTypeCheck(edge.useKind()))
1033 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
1034 return allocate();
1035 }
1036
1037 VirtualRegister virtualRegister = edge->virtualRegister();
1038 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
1039
1040 switch (info.registerFormat()) {
1041 case DataFormatNone: {
1042 GPRReg gpr = allocate();
1043
1044 if (edge->hasConstant()) {
1045 JSValue jsValue = edge->asJSValue();
1046 ASSERT(jsValue.isAnyInt());
1047 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1048 int64_t value = jsValue.asAnyInt();
1049 if (desiredFormat == DataFormatInt52)
1050 value = value << JSValue::int52ShiftAmount;
1051 m_jit.move(MacroAssembler::Imm64(value), gpr);
1052 info.fillGPR(*m_stream, gpr, desiredFormat);
1053 return gpr;
1054 }
1055
1056 DataFormat spillFormat = info.spillFormat();
1057
1058 DFG_ASSERT(m_jit.graph(), m_currentNode, spillFormat == DataFormatInt52 || spillFormat == DataFormatStrictInt52, spillFormat);
1059
1060 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
1061
1062 m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
1063 if (desiredFormat == DataFormatStrictInt52) {
1064 if (spillFormat == DataFormatInt52)
1065 m_jit.rshift64(TrustedImm32(JSValue::int52ShiftAmount), gpr);
1066 info.fillStrictInt52(*m_stream, gpr);
1067 return gpr;
1068 }
1069 if (spillFormat == DataFormatStrictInt52)
1070 m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), gpr);
1071 info.fillInt52(*m_stream, gpr);
1072 return gpr;
1073 }
1074
1075 case DataFormatStrictInt52: {
1076 GPRReg gpr = info.gpr();
1077 bool wasLocked = m_gprs.isLocked(gpr);
1078 lock(gpr);
1079 if (desiredFormat == DataFormatStrictInt52)
1080 return gpr;
1081 if (wasLocked) {
1082 GPRReg result = allocate();
1083 m_jit.move(gpr, result);
1084 unlock(gpr);
1085 gpr = result;
1086 } else
1087 info.fillInt52(*m_stream, gpr);
1088 m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), gpr);
1089 return gpr;
1090 }
1091
1092 case DataFormatInt52: {
1093 GPRReg gpr = info.gpr();
1094 bool wasLocked = m_gprs.isLocked(gpr);
1095 lock(gpr);
1096 if (desiredFormat == DataFormatInt52)
1097 return gpr;
1098 if (wasLocked) {
1099 GPRReg result = allocate();
1100 m_jit.move(gpr, result);
1101 unlock(gpr);
1102 gpr = result;
1103 } else
1104 info.fillStrictInt52(*m_stream, gpr);
1105 m_jit.rshift64(TrustedImm32(JSValue::int52ShiftAmount), gpr);
1106 return gpr;
1107 }
1108
1109 default:
1110 DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
1111 return InvalidGPRReg;
1112 }
1113}
1114
1115FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge)
1116{
1117 ASSERT(edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepAnyIntUse);
1118 ASSERT(edge->hasDoubleResult());
1119 VirtualRegister virtualRegister = edge->virtualRegister();
1120 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
1121
1122 if (info.registerFormat() == DataFormatNone) {
1123 if (edge->hasConstant()) {
1124 if (edge->isNumberConstant()) {
1125 FPRReg fpr = fprAllocate();
1126 int64_t doubleAsInt = reinterpretDoubleToInt64(edge->asNumber());
1127 if (!doubleAsInt)
1128 m_jit.moveZeroToDouble(fpr);
1129 else {
1130 GPRReg gpr = allocate();
1131 m_jit.move(MacroAssembler::Imm64(doubleAsInt), gpr);
1132 m_jit.move64ToDouble(gpr, fpr);
1133 unlock(gpr);
1134 }
1135
1136 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
1137 info.fillDouble(*m_stream, fpr);
1138 return fpr;
1139 }
1140 if (mayHaveTypeCheck(edge.useKind()))
1141 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
1142 return fprAllocate();
1143 }
1144
1145 DataFormat spillFormat = info.spillFormat();
1146 if (spillFormat != DataFormatDouble) {
1147 DFG_CRASH(
1148 m_jit.graph(), m_currentNode, toCString(
1149 "Expected ", edge, " to have double format but instead it is spilled as ",
1150 dataFormatToString(spillFormat)).data());
1151 }
1152 DFG_ASSERT(m_jit.graph(), m_currentNode, spillFormat == DataFormatDouble, spillFormat);
1153 FPRReg fpr = fprAllocate();
1154 m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
1155 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
1156 info.fillDouble(*m_stream, fpr);
1157 return fpr;
1158 }
1159
1160 DFG_ASSERT(m_jit.graph(), m_currentNode, info.registerFormat() == DataFormatDouble, info.registerFormat());
1161 FPRReg fpr = info.fpr();
1162 m_fprs.lock(fpr);
1163 return fpr;
1164}
1165
1166GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge)
1167{
1168 AbstractValue& value = m_state.forNode(edge);
1169 SpeculatedType type = value.m_type;
1170 ASSERT((edge.useKind() != KnownCellUse && edge.useKind() != KnownStringUse) || !(value.m_type & ~SpecCellCheck));
1171
1172 m_interpreter.filter(value, SpecCellCheck);
1173 if (value.isClear()) {
1174 if (mayHaveTypeCheck(edge.useKind()))
1175 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
1176 return allocate();
1177 }
1178
1179 VirtualRegister virtualRegister = edge->virtualRegister();
1180 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
1181
1182 switch (info.registerFormat()) {
1183 case DataFormatNone: {
1184 GPRReg gpr = allocate();
1185
1186 if (edge->hasConstant()) {
1187 JSValue jsValue = edge->asJSValue();
1188 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1189 m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr);
1190 info.fillJSValue(*m_stream, gpr, DataFormatJSCell);
1191 return gpr;
1192 }
1193
1194 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
1195 m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
1196
1197 info.fillJSValue(*m_stream, gpr, DataFormatJS);
1198 if (type & ~SpecCellCheck)
1199 speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branchIfNotCell(JSValueRegs(gpr)));
1200 info.fillJSValue(*m_stream, gpr, DataFormatJSCell);
1201 return gpr;
1202 }
1203
1204 case DataFormatCell:
1205 case DataFormatJSCell: {
1206 GPRReg gpr = info.gpr();
1207 m_gprs.lock(gpr);
1208 if (!ASSERT_DISABLED) {
1209 MacroAssembler::Jump checkCell = m_jit.branchIfCell(JSValueRegs(gpr));
1210 m_jit.abortWithReason(DFGIsNotCell);
1211 checkCell.link(&m_jit);
1212 }
1213 return gpr;
1214 }
1215
1216 case DataFormatJS: {
1217 GPRReg gpr = info.gpr();
1218 m_gprs.lock(gpr);
1219 if (type & ~SpecCellCheck)
1220 speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branchIfNotCell(JSValueRegs(gpr)));
1221 info.fillJSValue(*m_stream, gpr, DataFormatJSCell);
1222 return gpr;
1223 }
1224
1225 case DataFormatJSInt32:
1226 case DataFormatInt32:
1227 case DataFormatJSDouble:
1228 case DataFormatJSBoolean:
1229 case DataFormatBoolean:
1230 case DataFormatDouble:
1231 case DataFormatStorage:
1232 case DataFormatInt52:
1233 case DataFormatStrictInt52:
1234 DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
1235
1236 default:
1237 DFG_CRASH(m_jit.graph(), m_currentNode, "Corrupt data format");
1238 return InvalidGPRReg;
1239 }
1240}
1241
1242GPRReg SpeculativeJIT::fillSpeculateBoolean(Edge edge)
1243{
1244 AbstractValue& value = m_state.forNode(edge);
1245 SpeculatedType type = value.m_type;
1246 ASSERT(edge.useKind() != KnownBooleanUse || !(value.m_type & ~SpecBoolean));
1247
1248 m_interpreter.filter(value, SpecBoolean);
1249 if (value.isClear()) {
1250 if (mayHaveTypeCheck(edge.useKind()))
1251 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
1252 return allocate();
1253 }
1254
1255 VirtualRegister virtualRegister = edge->virtualRegister();
1256 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
1257
1258 switch (info.registerFormat()) {
1259 case DataFormatNone: {
1260 GPRReg gpr = allocate();
1261
1262 if (edge->hasConstant()) {
1263 JSValue jsValue = edge->asJSValue();
1264 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1265 m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr);
1266 info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean);
1267 return gpr;
1268 }
1269 DFG_ASSERT(m_jit.graph(), m_currentNode, info.spillFormat() & DataFormatJS, info.spillFormat());
1270 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
1271 m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
1272
1273 info.fillJSValue(*m_stream, gpr, DataFormatJS);
1274 if (type & ~SpecBoolean) {
1275 m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
1276 speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branchTest64(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg));
1277 m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
1278 }
1279 info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean);
1280 return gpr;
1281 }
1282
1283 case DataFormatBoolean:
1284 case DataFormatJSBoolean: {
1285 GPRReg gpr = info.gpr();
1286 m_gprs.lock(gpr);
1287 return gpr;
1288 }
1289
1290 case DataFormatJS: {
1291 GPRReg gpr = info.gpr();
1292 m_gprs.lock(gpr);
1293 if (type & ~SpecBoolean) {
1294 m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
1295 speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branchTest64(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg));
1296 m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
1297 }
1298 info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean);
1299 return gpr;
1300 }
1301
1302 case DataFormatJSInt32:
1303 case DataFormatInt32:
1304 case DataFormatJSDouble:
1305 case DataFormatJSCell:
1306 case DataFormatCell:
1307 case DataFormatDouble:
1308 case DataFormatStorage:
1309 case DataFormatInt52:
1310 case DataFormatStrictInt52:
1311 DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
1312
1313 default:
1314 DFG_CRASH(m_jit.graph(), m_currentNode, "Corrupt data format");
1315 return InvalidGPRReg;
1316 }
1317}
1318
1319void SpeculativeJIT::compileObjectStrictEquality(Edge objectChild, Edge otherChild)
1320{
1321 SpeculateCellOperand op1(this, objectChild);
1322 JSValueOperand op2(this, otherChild);
1323 GPRTemporary result(this);
1324
1325 GPRReg op1GPR = op1.gpr();
1326 GPRReg op2GPR = op2.gpr();
1327 GPRReg resultGPR = result.gpr();
1328
1329 DFG_TYPE_CHECK(JSValueSource::unboxedCell(op1GPR), objectChild, SpecObject, m_jit.branchIfNotObject(op1GPR));
1330
1331 // At this point we know that we can perform a straight-forward equality comparison on pointer
1332 // values because we are doing strict equality.
1333 m_jit.compare64(MacroAssembler::Equal, op1GPR, op2GPR, resultGPR);
1334 m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
1335 jsValueResult(resultGPR, m_currentNode, DataFormatJSBoolean);
1336}
1337
1338void SpeculativeJIT::compilePeepHoleObjectStrictEquality(Edge objectChild, Edge otherChild, Node* branchNode)
1339{
1340 BasicBlock* taken = branchNode->branchData()->taken.block;
1341 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1342
1343 SpeculateCellOperand op1(this, objectChild);
1344 JSValueOperand op2(this, otherChild);
1345
1346 GPRReg op1GPR = op1.gpr();
1347 GPRReg op2GPR = op2.gpr();
1348
1349 DFG_TYPE_CHECK(JSValueSource::unboxedCell(op1GPR), objectChild, SpecObject, m_jit.branchIfNotObject(op1GPR));
1350
1351 if (taken == nextBlock()) {
1352 branchPtr(MacroAssembler::NotEqual, op1GPR, op2GPR, notTaken);
1353 jump(taken);
1354 } else {
1355 branchPtr(MacroAssembler::Equal, op1GPR, op2GPR, taken);
1356 jump(notTaken);
1357 }
1358}
1359
1360void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild)
1361{
1362 SpeculateCellOperand op1(this, leftChild);
1363 JSValueOperand op2(this, rightChild, ManualOperandSpeculation);
1364 GPRTemporary result(this);
1365
1366 GPRReg op1GPR = op1.gpr();
1367 GPRReg op2GPR = op2.gpr();
1368 GPRReg resultGPR = result.gpr();
1369
1370 bool masqueradesAsUndefinedWatchpointValid =
1371 masqueradesAsUndefinedWatchpointIsStillValid();
1372
1373 if (masqueradesAsUndefinedWatchpointValid) {
1374 DFG_TYPE_CHECK(
1375 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR));
1376 } else {
1377 DFG_TYPE_CHECK(
1378 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR));
1379 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
1380 m_jit.branchTest8(
1381 MacroAssembler::NonZero,
1382 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
1383 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1384 }
1385
1386 // It seems that most of the time when programs do a == b where b may be either null/undefined
1387 // or an object, b is usually an object. Balance the branches to make that case fast.
1388 MacroAssembler::Jump rightNotCell = m_jit.branchIfNotCell(JSValueRegs(op2GPR));
1389
1390 // We know that within this branch, rightChild must be a cell.
1391 if (masqueradesAsUndefinedWatchpointValid) {
1392 DFG_TYPE_CHECK(
1393 JSValueRegs(op2GPR), rightChild, (~SpecCellCheck) | SpecObject, m_jit.branchIfNotObject(op2GPR));
1394 } else {
1395 DFG_TYPE_CHECK(
1396 JSValueRegs(op2GPR), rightChild, (~SpecCellCheck) | SpecObject, m_jit.branchIfNotObject(op2GPR));
1397 speculationCheck(BadType, JSValueRegs(op2GPR), rightChild,
1398 m_jit.branchTest8(
1399 MacroAssembler::NonZero,
1400 MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()),
1401 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1402 }
1403
1404 // At this point we know that we can perform a straight-forward equality comparison on pointer
1405 // values because both left and right are pointers to objects that have no special equality
1406 // protocols.
1407 m_jit.compare64(MacroAssembler::Equal, op1GPR, op2GPR, resultGPR);
1408 MacroAssembler::Jump done = m_jit.jump();
1409
1410 rightNotCell.link(&m_jit);
1411
1412 // We know that within this branch, rightChild must not be a cell. Check if that is enough to
1413 // prove that it is either null or undefined.
1414 if (needsTypeCheck(rightChild, SpecCellCheck | SpecOther)) {
1415 m_jit.move(op2GPR, resultGPR);
1416 m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), resultGPR);
1417
1418 typeCheck(
1419 JSValueRegs(op2GPR), rightChild, SpecCellCheck | SpecOther,
1420 m_jit.branch64(
1421 MacroAssembler::NotEqual, resultGPR,
1422 MacroAssembler::TrustedImm64(ValueNull)));
1423 }
1424 m_jit.move(TrustedImm32(0), result.gpr());
1425
1426 done.link(&m_jit);
1427 m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
1428 jsValueResult(resultGPR, m_currentNode, DataFormatJSBoolean);
1429}
1430
1431void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild, Node* branchNode)
1432{
1433 BasicBlock* taken = branchNode->branchData()->taken.block;
1434 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1435
1436 SpeculateCellOperand op1(this, leftChild);
1437 JSValueOperand op2(this, rightChild, ManualOperandSpeculation);
1438 GPRTemporary result(this);
1439
1440 GPRReg op1GPR = op1.gpr();
1441 GPRReg op2GPR = op2.gpr();
1442 GPRReg resultGPR = result.gpr();
1443
1444 bool masqueradesAsUndefinedWatchpointValid =
1445 masqueradesAsUndefinedWatchpointIsStillValid();
1446
1447 if (masqueradesAsUndefinedWatchpointValid) {
1448 DFG_TYPE_CHECK(
1449 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR));
1450 } else {
1451 DFG_TYPE_CHECK(
1452 JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR));
1453 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
1454 m_jit.branchTest8(
1455 MacroAssembler::NonZero,
1456 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
1457 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1458 }
1459
1460 // It seems that most of the time when programs do a == b where b may be either null/undefined
1461 // or an object, b is usually an object. Balance the branches to make that case fast.
1462 MacroAssembler::Jump rightNotCell = m_jit.branchIfNotCell(JSValueRegs(op2GPR));
1463
1464 // We know that within this branch, rightChild must be a cell.
1465 if (masqueradesAsUndefinedWatchpointValid) {
1466 DFG_TYPE_CHECK(
1467 JSValueRegs(op2GPR), rightChild, (~SpecCellCheck) | SpecObject, m_jit.branchIfNotObject(op2GPR));
1468 } else {
1469 DFG_TYPE_CHECK(
1470 JSValueRegs(op2GPR), rightChild, (~SpecCellCheck) | SpecObject, m_jit.branchIfNotObject(op2GPR));
1471 speculationCheck(BadType, JSValueRegs(op2GPR), rightChild,
1472 m_jit.branchTest8(
1473 MacroAssembler::NonZero,
1474 MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()),
1475 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1476 }
1477
1478 // At this point we know that we can perform a straight-forward equality comparison on pointer
1479 // values because both left and right are pointers to objects that have no special equality
1480 // protocols.
1481 branch64(MacroAssembler::Equal, op1GPR, op2GPR, taken);
1482
1483 // We know that within this branch, rightChild must not be a cell. Check if that is enough to
1484 // prove that it is either null or undefined.
1485 if (!needsTypeCheck(rightChild, SpecCellCheck | SpecOther))
1486 rightNotCell.link(&m_jit);
1487 else {
1488 jump(notTaken, ForceJump);
1489
1490 rightNotCell.link(&m_jit);
1491 m_jit.move(op2GPR, resultGPR);
1492 m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), resultGPR);
1493
1494 typeCheck(
1495 JSValueRegs(op2GPR), rightChild, SpecCellCheck | SpecOther, m_jit.branch64(
1496 MacroAssembler::NotEqual, resultGPR,
1497 MacroAssembler::TrustedImm64(ValueNull)));
1498 }
1499
1500 jump(notTaken);
1501}
1502
1503void SpeculativeJIT::compileSymbolUntypedEquality(Node* node, Edge symbolEdge, Edge untypedEdge)
1504{
1505 SpeculateCellOperand symbol(this, symbolEdge);
1506 JSValueOperand untyped(this, untypedEdge);
1507 GPRTemporary result(this, Reuse, symbol, untyped);
1508
1509 GPRReg symbolGPR = symbol.gpr();
1510 GPRReg untypedGPR = untyped.gpr();
1511 GPRReg resultGPR = result.gpr();
1512
1513 speculateSymbol(symbolEdge, symbolGPR);
1514
1515 // At this point we know that we can perform a straight-forward equality comparison on pointer
1516 // values because we are doing strict equality.
1517 m_jit.compare64(MacroAssembler::Equal, symbolGPR, untypedGPR, resultGPR);
1518 unblessedBooleanResult(resultGPR, node);
1519}
1520
1521void SpeculativeJIT::compileInt52Compare(Node* node, MacroAssembler::RelationalCondition condition)
1522{
1523 SpeculateWhicheverInt52Operand op1(this, node->child1());
1524 SpeculateWhicheverInt52Operand op2(this, node->child2(), op1);
1525 GPRTemporary result(this, Reuse, op1, op2);
1526
1527 m_jit.compare64(condition, op1.gpr(), op2.gpr(), result.gpr());
1528
1529 // If we add a DataFormatBool, we should use it here.
1530 m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
1531 jsValueResult(result.gpr(), m_currentNode, DataFormatJSBoolean);
1532}
1533
1534void SpeculativeJIT::compilePeepHoleInt52Branch(Node* node, Node* branchNode, JITCompiler::RelationalCondition condition)
1535{
1536 BasicBlock* taken = branchNode->branchData()->taken.block;
1537 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1538
1539 // The branch instruction will branch to the taken block.
1540 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
1541 if (taken == nextBlock()) {
1542 condition = JITCompiler::invert(condition);
1543 BasicBlock* tmp = taken;
1544 taken = notTaken;
1545 notTaken = tmp;
1546 }
1547
1548 SpeculateWhicheverInt52Operand op1(this, node->child1());
1549 SpeculateWhicheverInt52Operand op2(this, node->child2(), op1);
1550
1551 branch64(condition, op1.gpr(), op2.gpr(), taken);
1552 jump(notTaken);
1553}
1554
1555void SpeculativeJIT::compileCompareEqPtr(Node* node)
1556{
1557 JSValueOperand value(this, node->child1());
1558 GPRTemporary result(this);
1559 GPRReg valueGPR = value.gpr();
1560 GPRReg resultGPR = result.gpr();
1561
1562 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), node->cellOperand()->cell()), resultGPR);
1563 m_jit.compare64(MacroAssembler::Equal, valueGPR, resultGPR, resultGPR);
1564 unblessedBooleanResult(resultGPR, node);
1565}
1566
1567void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
1568{
1569 JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
1570 GPRTemporary result(this);
1571 GPRReg valueGPR = value.gpr();
1572 GPRReg resultGPR = result.gpr();
1573 GPRTemporary structure;
1574 GPRReg structureGPR = InvalidGPRReg;
1575 GPRTemporary scratch;
1576 GPRReg scratchGPR = InvalidGPRReg;
1577
1578 bool masqueradesAsUndefinedWatchpointValid =
1579 masqueradesAsUndefinedWatchpointIsStillValid();
1580
1581 if (!masqueradesAsUndefinedWatchpointValid) {
1582 // The masquerades as undefined case will use the structure register, so allocate it here.
1583 // Do this at the top of the function to avoid branching around a register allocation.
1584 GPRTemporary realStructure(this);
1585 GPRTemporary realScratch(this);
1586 structure.adopt(realStructure);
1587 scratch.adopt(realScratch);
1588 structureGPR = structure.gpr();
1589 scratchGPR = scratch.gpr();
1590 }
1591
1592 MacroAssembler::Jump notCell = m_jit.branchIfNotCell(JSValueRegs(valueGPR));
1593 if (masqueradesAsUndefinedWatchpointValid) {
1594 DFG_TYPE_CHECK(
1595 JSValueRegs(valueGPR), nodeUse, (~SpecCellCheck) | SpecObject, m_jit.branchIfNotObject(valueGPR));
1596 } else {
1597 DFG_TYPE_CHECK(
1598 JSValueRegs(valueGPR), nodeUse, (~SpecCellCheck) | SpecObject, m_jit.branchIfNotObject(valueGPR));
1599
1600 MacroAssembler::Jump isNotMasqueradesAsUndefined =
1601 m_jit.branchTest8(
1602 MacroAssembler::Zero,
1603 MacroAssembler::Address(valueGPR, JSCell::typeInfoFlagsOffset()),
1604 MacroAssembler::TrustedImm32(MasqueradesAsUndefined));
1605
1606 m_jit.emitLoadStructure(*m_jit.vm(), valueGPR, structureGPR, scratchGPR);
1607 speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse,
1608 m_jit.branchPtr(
1609 MacroAssembler::Equal,
1610 MacroAssembler::Address(structureGPR, Structure::globalObjectOffset()),
1611 TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.graph().globalObjectFor(m_currentNode->origin.semantic))));
1612
1613 isNotMasqueradesAsUndefined.link(&m_jit);
1614 }
1615 m_jit.move(TrustedImm32(ValueFalse), resultGPR);
1616 MacroAssembler::Jump done = m_jit.jump();
1617
1618 notCell.link(&m_jit);
1619
1620 if (needsTypeCheck(nodeUse, SpecCellCheck | SpecOther)) {
1621 m_jit.move(valueGPR, resultGPR);
1622 m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), resultGPR);
1623 typeCheck(
1624 JSValueRegs(valueGPR), nodeUse, SpecCellCheck | SpecOther, m_jit.branch64(
1625 MacroAssembler::NotEqual,
1626 resultGPR,
1627 MacroAssembler::TrustedImm64(ValueNull)));
1628 }
1629 m_jit.move(TrustedImm32(ValueTrue), resultGPR);
1630
1631 done.link(&m_jit);
1632
1633 jsValueResult(resultGPR, m_currentNode, DataFormatJSBoolean);
1634}
1635
1636void SpeculativeJIT::compileLogicalNot(Node* node)
1637{
1638 switch (node->child1().useKind()) {
1639 case ObjectOrOtherUse: {
1640 compileObjectOrOtherLogicalNot(node->child1());
1641 return;
1642 }
1643
1644 case Int32Use: {
1645 SpeculateInt32Operand value(this, node->child1());
1646 GPRTemporary result(this, Reuse, value);
1647 m_jit.compare32(MacroAssembler::Equal, value.gpr(), MacroAssembler::TrustedImm32(0), result.gpr());
1648 m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
1649 jsValueResult(result.gpr(), node, DataFormatJSBoolean);
1650 return;
1651 }
1652
1653 case DoubleRepUse: {
1654 SpeculateDoubleOperand value(this, node->child1());
1655 FPRTemporary scratch(this);
1656 GPRTemporary result(this);
1657 m_jit.move(TrustedImm32(ValueFalse), result.gpr());
1658 MacroAssembler::Jump nonZero = m_jit.branchDoubleNonZero(value.fpr(), scratch.fpr());
1659 m_jit.xor32(TrustedImm32(true), result.gpr());
1660 nonZero.link(&m_jit);
1661 jsValueResult(result.gpr(), node, DataFormatJSBoolean);
1662 return;
1663 }
1664
1665 case BooleanUse:
1666 case KnownBooleanUse: {
1667 if (!needsTypeCheck(node->child1(), SpecBoolean)) {
1668 SpeculateBooleanOperand value(this, node->child1());
1669 GPRTemporary result(this, Reuse, value);
1670
1671 m_jit.move(value.gpr(), result.gpr());
1672 m_jit.xor64(TrustedImm32(true), result.gpr());
1673
1674 jsValueResult(result.gpr(), node, DataFormatJSBoolean);
1675 return;
1676 }
1677
1678 JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
1679 GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).
1680
1681 m_jit.move(value.gpr(), result.gpr());
1682 m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), result.gpr());
1683 typeCheck(
1684 JSValueRegs(value.gpr()), node->child1(), SpecBoolean, m_jit.branchTest64(
1685 JITCompiler::NonZero, result.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
1686 m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueTrue)), result.gpr());
1687
1688 // If we add a DataFormatBool, we should use it here.
1689 jsValueResult(result.gpr(), node, DataFormatJSBoolean);
1690 return;
1691 }
1692
1693 case UntypedUse: {
1694 JSValueOperand arg1(this, node->child1());
1695 GPRTemporary result(this);
1696
1697 GPRReg arg1GPR = arg1.gpr();
1698 GPRReg resultGPR = result.gpr();
1699
1700 FPRTemporary valueFPR(this);
1701 FPRTemporary tempFPR(this);
1702
1703 bool shouldCheckMasqueradesAsUndefined = !masqueradesAsUndefinedWatchpointIsStillValid();
1704 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
1705 Optional<GPRTemporary> scratch;
1706 GPRReg scratchGPR = InvalidGPRReg;
1707 if (shouldCheckMasqueradesAsUndefined) {
1708 scratch.emplace(this);
1709 scratchGPR = scratch->gpr();
1710 }
1711 bool negateResult = true;
1712 m_jit.emitConvertValueToBoolean(*m_jit.vm(), JSValueRegs(arg1GPR), resultGPR, scratchGPR, valueFPR.fpr(), tempFPR.fpr(), shouldCheckMasqueradesAsUndefined, globalObject, negateResult);
1713 m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
1714 jsValueResult(resultGPR, node, DataFormatJSBoolean);
1715 return;
1716 }
1717 case StringUse:
1718 return compileStringZeroLength(node);
1719
1720 case StringOrOtherUse:
1721 return compileLogicalNotStringOrOther(node);
1722
1723 default:
1724 DFG_CRASH(m_jit.graph(), node, "Bad use kind");
1725 break;
1726 }
1727}
1728
1729void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BasicBlock* taken, BasicBlock* notTaken)
1730{
1731 JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
1732 GPRTemporary scratch(this);
1733 GPRTemporary structure;
1734 GPRReg valueGPR = value.gpr();
1735 GPRReg scratchGPR = scratch.gpr();
1736 GPRReg structureGPR = InvalidGPRReg;
1737
1738 if (!masqueradesAsUndefinedWatchpointIsStillValid()) {
1739 GPRTemporary realStructure(this);
1740 structure.adopt(realStructure);
1741 structureGPR = structure.gpr();
1742 }
1743
1744 MacroAssembler::Jump notCell = m_jit.branchIfNotCell(JSValueRegs(valueGPR));
1745 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
1746 DFG_TYPE_CHECK(
1747 JSValueRegs(valueGPR), nodeUse, (~SpecCellCheck) | SpecObject, m_jit.branchIfNotObject(valueGPR));
1748 } else {
1749 DFG_TYPE_CHECK(
1750 JSValueRegs(valueGPR), nodeUse, (~SpecCellCheck) | SpecObject, m_jit.branchIfNotObject(valueGPR));
1751
1752 JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8(
1753 JITCompiler::Zero,
1754 MacroAssembler::Address(valueGPR, JSCell::typeInfoFlagsOffset()),
1755 TrustedImm32(MasqueradesAsUndefined));
1756
1757 m_jit.emitLoadStructure(*m_jit.vm(), valueGPR, structureGPR, scratchGPR);
1758 speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse,
1759 m_jit.branchPtr(
1760 MacroAssembler::Equal,
1761 MacroAssembler::Address(structureGPR, Structure::globalObjectOffset()),
1762 TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.graph().globalObjectFor(m_currentNode->origin.semantic))));
1763
1764 isNotMasqueradesAsUndefined.link(&m_jit);
1765 }
1766 jump(taken, ForceJump);
1767
1768 notCell.link(&m_jit);
1769
1770 if (needsTypeCheck(nodeUse, SpecCellCheck | SpecOther)) {
1771 m_jit.move(valueGPR, scratchGPR);
1772 m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), scratchGPR);
1773 typeCheck(
1774 JSValueRegs(valueGPR), nodeUse, SpecCellCheck | SpecOther, m_jit.branch64(
1775 MacroAssembler::NotEqual, scratchGPR, MacroAssembler::TrustedImm64(ValueNull)));
1776 }
1777 jump(notTaken);
1778
1779 noResult(m_currentNode);
1780}
1781
1782void SpeculativeJIT::emitBranch(Node* node)
1783{
1784 BasicBlock* taken = node->branchData()->taken.block;
1785 BasicBlock* notTaken = node->branchData()->notTaken.block;
1786
1787 switch (node->child1().useKind()) {
1788 case ObjectOrOtherUse: {
1789 emitObjectOrOtherBranch(node->child1(), taken, notTaken);
1790 return;
1791 }
1792
1793 case Int32Use:
1794 case DoubleRepUse: {
1795 if (node->child1().useKind() == Int32Use) {
1796 bool invert = false;
1797
1798 if (taken == nextBlock()) {
1799 invert = true;
1800 BasicBlock* tmp = taken;
1801 taken = notTaken;
1802 notTaken = tmp;
1803 }
1804
1805 SpeculateInt32Operand value(this, node->child1());
1806 branchTest32(invert ? MacroAssembler::Zero : MacroAssembler::NonZero, value.gpr(), taken);
1807 } else {
1808 SpeculateDoubleOperand value(this, node->child1());
1809 FPRTemporary scratch(this);
1810 branchDoubleNonZero(value.fpr(), scratch.fpr(), taken);
1811 }
1812
1813 jump(notTaken);
1814
1815 noResult(node);
1816 return;
1817 }
1818
1819 case StringUse: {
1820 emitStringBranch(node->child1(), taken, notTaken);
1821 return;
1822 }
1823
1824 case StringOrOtherUse: {
1825 emitStringOrOtherBranch(node->child1(), taken, notTaken);
1826 return;
1827 }
1828
1829 case UntypedUse:
1830 case BooleanUse:
1831 case KnownBooleanUse: {
1832 JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
1833 GPRReg valueGPR = value.gpr();
1834
1835 if (node->child1().useKind() == BooleanUse || node->child1().useKind() == KnownBooleanUse) {
1836 if (!needsTypeCheck(node->child1(), SpecBoolean)) {
1837 MacroAssembler::ResultCondition condition = MacroAssembler::NonZero;
1838
1839 if (taken == nextBlock()) {
1840 condition = MacroAssembler::Zero;
1841 BasicBlock* tmp = taken;
1842 taken = notTaken;
1843 notTaken = tmp;
1844 }
1845
1846 branchTest32(condition, valueGPR, TrustedImm32(true), taken);
1847 jump(notTaken);
1848 } else {
1849 branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(false))), notTaken);
1850 branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(true))), taken);
1851
1852 typeCheck(JSValueRegs(valueGPR), node->child1(), SpecBoolean, m_jit.jump());
1853 }
1854 value.use();
1855 } else {
1856 GPRTemporary result(this);
1857 FPRTemporary fprValue(this);
1858 FPRTemporary fprTemp(this);
1859 Optional<GPRTemporary> scratch;
1860
1861 GPRReg scratchGPR = InvalidGPRReg;
1862 bool shouldCheckMasqueradesAsUndefined = !masqueradesAsUndefinedWatchpointIsStillValid();
1863 if (shouldCheckMasqueradesAsUndefined) {
1864 scratch.emplace(this);
1865 scratchGPR = scratch->gpr();
1866 }
1867
1868 GPRReg resultGPR = result.gpr();
1869 FPRReg valueFPR = fprValue.fpr();
1870 FPRReg tempFPR = fprTemp.fpr();
1871
1872 if (node->child1()->prediction() & SpecInt32Only) {
1873 branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsNumber(0))), notTaken);
1874 branch64(MacroAssembler::AboveOrEqual, valueGPR, GPRInfo::tagTypeNumberRegister, taken);
1875 }
1876
1877 if (node->child1()->prediction() & SpecBoolean) {
1878 branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(false))), notTaken);
1879 branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(true))), taken);
1880 }
1881
1882 value.use();
1883
1884 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
1885 auto truthy = m_jit.branchIfTruthy(*m_jit.vm(), JSValueRegs(valueGPR), resultGPR, scratchGPR, valueFPR, tempFPR, shouldCheckMasqueradesAsUndefined, globalObject);
1886 addBranch(truthy, taken);
1887 jump(notTaken);
1888 }
1889
1890 noResult(node, UseChildrenCalledExplicitly);
1891 return;
1892 }
1893
1894 default:
1895 DFG_CRASH(m_jit.graph(), m_currentNode, "Bad use kind");
1896 }
1897}
1898
1899void SpeculativeJIT::compile(Node* node)
1900{
1901 NodeType op = node->op();
1902
1903 if (validateDFGDoesGC) {
1904 bool expectDoesGC = doesGC(m_jit.graph(), node);
1905 m_jit.store8(TrustedImm32(expectDoesGC), m_jit.vm()->heap.addressOfExpectDoesGC());
1906 }
1907
1908#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
1909 m_jit.clearRegisterAllocationOffsets();
1910#endif
1911
1912 switch (op) {
1913 case JSConstant:
1914 case DoubleConstant:
1915 case Int52Constant:
1916 case PhantomDirectArguments:
1917 case PhantomClonedArguments:
1918 initConstantInfo(node);
1919 break;
1920
1921 case LazyJSConstant:
1922 compileLazyJSConstant(node);
1923 break;
1924
1925 case Identity: {
1926 compileIdentity(node);
1927 break;
1928 }
1929
1930 case GetLocal: {
1931 AbstractValue& value = m_state.operand(node->local());
1932
1933 // If the CFA is tracking this variable and it found that the variable
1934 // cannot have been assigned, then don't attempt to proceed.
1935 if (value.isClear()) {
1936 m_compileOkay = false;
1937 break;
1938 }
1939
1940 switch (node->variableAccessData()->flushFormat()) {
1941 case FlushedDouble: {
1942 FPRTemporary result(this);
1943 m_jit.loadDouble(JITCompiler::addressFor(node->machineLocal()), result.fpr());
1944 VirtualRegister virtualRegister = node->virtualRegister();
1945 m_fprs.retain(result.fpr(), virtualRegister, SpillOrderDouble);
1946 generationInfoFromVirtualRegister(virtualRegister).initDouble(node, node->refCount(), result.fpr());
1947 break;
1948 }
1949
1950 case FlushedInt32: {
1951 GPRTemporary result(this);
1952 m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr());
1953
1954 // Like int32Result, but don't useChildren - our children are phi nodes,
1955 // and don't represent values within this dataflow with virtual registers.
1956 VirtualRegister virtualRegister = node->virtualRegister();
1957 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderInteger);
1958 generationInfoFromVirtualRegister(virtualRegister).initInt32(node, node->refCount(), result.gpr());
1959 break;
1960 }
1961
1962 case FlushedInt52: {
1963 GPRTemporary result(this);
1964 m_jit.load64(JITCompiler::addressFor(node->machineLocal()), result.gpr());
1965
1966 VirtualRegister virtualRegister = node->virtualRegister();
1967 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
1968 generationInfoFromVirtualRegister(virtualRegister).initInt52(node, node->refCount(), result.gpr());
1969 break;
1970 }
1971
1972 default:
1973 GPRTemporary result(this);
1974 m_jit.load64(JITCompiler::addressFor(node->machineLocal()), result.gpr());
1975
1976 // Like jsValueResult, but don't useChildren - our children are phi nodes,
1977 // and don't represent values within this dataflow with virtual registers.
1978 VirtualRegister virtualRegister = node->virtualRegister();
1979 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
1980
1981 DataFormat format;
1982 if (isCellSpeculation(value.m_type))
1983 format = DataFormatJSCell;
1984 else if (isBooleanSpeculation(value.m_type))
1985 format = DataFormatJSBoolean;
1986 else
1987 format = DataFormatJS;
1988
1989 generationInfoFromVirtualRegister(virtualRegister).initJSValue(node, node->refCount(), result.gpr(), format);
1990 break;
1991 }
1992 break;
1993 }
1994
1995 case MovHint: {
1996 compileMovHint(m_currentNode);
1997 noResult(node);
1998 break;
1999 }
2000
2001 case ZombieHint: {
2002 recordSetLocal(m_currentNode->unlinkedLocal(), VirtualRegister(), DataFormatDead);
2003 noResult(node);
2004 break;
2005 }
2006
2007 case ExitOK: {
2008 noResult(node);
2009 break;
2010 }
2011
2012 case SetLocal: {
2013 switch (node->variableAccessData()->flushFormat()) {
2014 case FlushedDouble: {
2015 SpeculateDoubleOperand value(this, node->child1());
2016 m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node->machineLocal()));
2017 noResult(node);
2018 // Indicate that it's no longer necessary to retrieve the value of
2019 // this bytecode variable from registers or other locations in the stack,
2020 // but that it is stored as a double.
2021 recordSetLocal(DataFormatDouble);
2022 break;
2023 }
2024
2025 case FlushedInt32: {
2026 SpeculateInt32Operand value(this, node->child1());
2027 m_jit.store32(value.gpr(), JITCompiler::payloadFor(node->machineLocal()));
2028 noResult(node);
2029 recordSetLocal(DataFormatInt32);
2030 break;
2031 }
2032
2033 case FlushedInt52: {
2034 SpeculateInt52Operand value(this, node->child1());
2035 m_jit.store64(value.gpr(), JITCompiler::addressFor(node->machineLocal()));
2036 noResult(node);
2037 recordSetLocal(DataFormatInt52);
2038 break;
2039 }
2040
2041 case FlushedCell: {
2042 SpeculateCellOperand cell(this, node->child1());
2043 GPRReg cellGPR = cell.gpr();
2044 m_jit.store64(cellGPR, JITCompiler::addressFor(node->machineLocal()));
2045 noResult(node);
2046 recordSetLocal(DataFormatCell);
2047 break;
2048 }
2049
2050 case FlushedBoolean: {
2051 SpeculateBooleanOperand boolean(this, node->child1());
2052 m_jit.store64(boolean.gpr(), JITCompiler::addressFor(node->machineLocal()));
2053 noResult(node);
2054 recordSetLocal(DataFormatBoolean);
2055 break;
2056 }
2057
2058 case FlushedJSValue: {
2059 JSValueOperand value(this, node->child1());
2060 m_jit.store64(value.gpr(), JITCompiler::addressFor(node->machineLocal()));
2061 noResult(node);
2062 recordSetLocal(dataFormatFor(node->variableAccessData()->flushFormat()));
2063 break;
2064 }
2065
2066 default:
2067 DFG_CRASH(m_jit.graph(), node, "Bad flush format");
2068 break;
2069 }
2070
2071 break;
2072 }
2073
2074 case SetArgument:
2075 // This is a no-op; it just marks the fact that the argument is being used.
2076 // But it may be profitable to use this as a hook to run speculation checks
2077 // on arguments, thereby allowing us to trivially eliminate such checks if
2078 // the argument is not used.
2079 recordSetLocal(dataFormatFor(node->variableAccessData()->flushFormat()));
2080 break;
2081
2082 case ValueBitNot:
2083 compileValueBitNot(node);
2084 break;
2085
2086 case ArithBitNot:
2087 compileBitwiseNot(node);
2088 break;
2089
2090 case ValueBitAnd:
2091 case ValueBitXor:
2092 case ValueBitOr:
2093 compileValueBitwiseOp(node);
2094 break;
2095
2096 case ArithBitAnd:
2097 case ArithBitOr:
2098 case ArithBitXor:
2099 compileBitwiseOp(node);
2100 break;
2101
2102 case BitRShift:
2103 case BitLShift:
2104 case BitURShift:
2105 compileShiftOp(node);
2106 break;
2107
2108 case UInt32ToNumber: {
2109 compileUInt32ToNumber(node);
2110 break;
2111 }
2112
2113 case DoubleAsInt32: {
2114 compileDoubleAsInt32(node);
2115 break;
2116 }
2117
2118 case ValueToInt32: {
2119 compileValueToInt32(node);
2120 break;
2121 }
2122
2123 case DoubleRep: {
2124 compileDoubleRep(node);
2125 break;
2126 }
2127
2128 case ValueRep: {
2129 compileValueRep(node);
2130 break;
2131 }
2132
2133 case Int52Rep: {
2134 switch (node->child1().useKind()) {
2135 case Int32Use: {
2136 SpeculateInt32Operand operand(this, node->child1());
2137 GPRTemporary result(this, Reuse, operand);
2138
2139 m_jit.signExtend32ToPtr(operand.gpr(), result.gpr());
2140
2141 strictInt52Result(result.gpr(), node);
2142 break;
2143 }
2144
2145 case AnyIntUse: {
2146 GPRTemporary result(this);
2147 GPRReg resultGPR = result.gpr();
2148
2149 convertAnyInt(node->child1(), resultGPR);
2150
2151 strictInt52Result(resultGPR, node);
2152 break;
2153 }
2154
2155 case DoubleRepAnyIntUse: {
2156 SpeculateDoubleOperand value(this, node->child1());
2157 FPRReg valueFPR = value.fpr();
2158
2159 flushRegisters();
2160 GPRFlushedCallResult result(this);
2161 GPRReg resultGPR = result.gpr();
2162 callOperation(operationConvertDoubleToInt52, resultGPR, valueFPR);
2163
2164 DFG_TYPE_CHECK_WITH_EXIT_KIND(Int52Overflow,
2165 JSValueRegs(), node->child1(), SpecAnyIntAsDouble,
2166 m_jit.branch64(
2167 JITCompiler::Equal, resultGPR,
2168 JITCompiler::TrustedImm64(JSValue::notInt52)));
2169
2170 strictInt52Result(resultGPR, node);
2171 break;
2172 }
2173
2174 default:
2175 DFG_CRASH(m_jit.graph(), node, "Bad use kind");
2176 }
2177 break;
2178 }
2179
2180 case ValueNegate:
2181 compileValueNegate(node);
2182 break;
2183
2184 case ValueAdd:
2185 compileValueAdd(node);
2186 break;
2187
2188 case ValueSub:
2189 compileValueSub(node);
2190 break;
2191
2192 case StrCat: {
2193 compileStrCat(node);
2194 break;
2195 }
2196
2197 case ArithAdd:
2198 compileArithAdd(node);
2199 break;
2200
2201 case ArithClz32:
2202 compileArithClz32(node);
2203 break;
2204
2205 case MakeRope:
2206 compileMakeRope(node);
2207 break;
2208
2209 case ArithSub:
2210 compileArithSub(node);
2211 break;
2212
2213 case ArithNegate:
2214 compileArithNegate(node);
2215 break;
2216
2217 case ArithMul:
2218 compileArithMul(node);
2219 break;
2220
2221 case ValueMul:
2222 compileValueMul(node);
2223 break;
2224
2225 case ValueDiv: {
2226 compileValueDiv(node);
2227 break;
2228 }
2229
2230 case ArithDiv: {
2231 compileArithDiv(node);
2232 break;
2233 }
2234
2235 case ArithMod: {
2236 compileArithMod(node);
2237 break;
2238 }
2239
2240 case ArithAbs:
2241 compileArithAbs(node);
2242 break;
2243
2244 case ArithMin:
2245 case ArithMax: {
2246 compileArithMinMax(node);
2247 break;
2248 }
2249
2250 case ArithPow:
2251 compileArithPow(node);
2252 break;
2253
2254 case ArithSqrt:
2255 compileArithSqrt(node);
2256 break;
2257
2258 case ArithFRound:
2259 compileArithFRound(node);
2260 break;
2261
2262 case ArithRandom:
2263 compileArithRandom(node);
2264 break;
2265
2266 case ArithRound:
2267 case ArithFloor:
2268 case ArithCeil:
2269 case ArithTrunc:
2270 compileArithRounding(node);
2271 break;
2272
2273 case ArithUnary:
2274 compileArithUnary(node);
2275 break;
2276
2277 case LogicalNot:
2278 compileLogicalNot(node);
2279 break;
2280
2281 case CompareLess:
2282 if (compare(node, JITCompiler::LessThan, JITCompiler::DoubleLessThan, operationCompareLess))
2283 return;
2284 break;
2285
2286 case CompareLessEq:
2287 if (compare(node, JITCompiler::LessThanOrEqual, JITCompiler::DoubleLessThanOrEqual, operationCompareLessEq))
2288 return;
2289 break;
2290
2291 case CompareGreater:
2292 if (compare(node, JITCompiler::GreaterThan, JITCompiler::DoubleGreaterThan, operationCompareGreater))
2293 return;
2294 break;
2295
2296 case CompareGreaterEq:
2297 if (compare(node, JITCompiler::GreaterThanOrEqual, JITCompiler::DoubleGreaterThanOrEqual, operationCompareGreaterEq))
2298 return;
2299 break;
2300
2301 case CompareBelow:
2302 compileCompareUnsigned(node, JITCompiler::Below);
2303 break;
2304
2305 case CompareBelowEq:
2306 compileCompareUnsigned(node, JITCompiler::BelowOrEqual);
2307 break;
2308
2309 case CompareEq:
2310 if (compare(node, JITCompiler::Equal, JITCompiler::DoubleEqual, operationCompareEq))
2311 return;
2312 break;
2313
2314 case CompareStrictEq:
2315 if (compileStrictEq(node))
2316 return;
2317 break;
2318
2319 case CompareEqPtr:
2320 compileCompareEqPtr(node);
2321 break;
2322
2323 case SameValue:
2324 compileSameValue(node);
2325 break;
2326
2327 case StringCharCodeAt: {
2328 compileGetCharCodeAt(node);
2329 break;
2330 }
2331
2332 case StringCharAt: {
2333 // Relies on StringCharAt node having same basic layout as GetByVal
2334 compileGetByValOnString(node);
2335 break;
2336 }
2337
2338 case StringFromCharCode: {
2339 compileFromCharCode(node);
2340 break;
2341 }
2342
2343 case CheckArray: {
2344 checkArray(node);
2345 break;
2346 }
2347
2348 case Arrayify:
2349 case ArrayifyToStructure: {
2350 arrayify(node);
2351 break;
2352 }
2353
2354 case GetByVal: {
2355 switch (node->arrayMode().type()) {
2356 case Array::AnyTypedArray:
2357 case Array::ForceExit:
2358 case Array::SelectUsingArguments:
2359 case Array::SelectUsingPredictions:
2360 case Array::Unprofiled:
2361 DFG_CRASH(m_jit.graph(), node, "Bad array mode type");
2362 break;
2363 case Array::Undecided: {
2364 SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 1));
2365 GPRTemporary result(this, Reuse, index);
2366 GPRReg indexGPR = index.gpr();
2367 GPRReg resultGPR = result.gpr();
2368
2369 speculationCheck(OutOfBounds, JSValueRegs(), node,
2370 m_jit.branch32(MacroAssembler::LessThan, indexGPR, MacroAssembler::TrustedImm32(0)));
2371
2372 use(m_graph.varArgChild(node, 0));
2373 index.use();
2374
2375 m_jit.move(MacroAssembler::TrustedImm64(ValueUndefined), resultGPR);
2376 jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
2377 break;
2378 }
2379 case Array::Generic: {
2380 if (m_graph.varArgChild(node, 0).useKind() == ObjectUse) {
2381 if (m_graph.varArgChild(node, 1).useKind() == StringUse) {
2382 compileGetByValForObjectWithString(node);
2383 break;
2384 }
2385
2386 if (m_graph.varArgChild(node, 1).useKind() == SymbolUse) {
2387 compileGetByValForObjectWithSymbol(node);
2388 break;
2389 }
2390 }
2391 JSValueOperand base(this, m_graph.varArgChild(node, 0));
2392 JSValueOperand property(this, m_graph.varArgChild(node, 1));
2393 GPRReg baseGPR = base.gpr();
2394 GPRReg propertyGPR = property.gpr();
2395
2396 flushRegisters();
2397 GPRFlushedCallResult result(this);
2398 callOperation(operationGetByVal, result.gpr(), baseGPR, propertyGPR);
2399 m_jit.exceptionCheck();
2400
2401 jsValueResult(result.gpr(), node);
2402 break;
2403 }
2404 case Array::Int32:
2405 case Array::Contiguous: {
2406 if (node->arrayMode().isInBounds()) {
2407 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
2408 StorageOperand storage(this, m_graph.varArgChild(node, 2));
2409
2410 GPRReg propertyReg = property.gpr();
2411 GPRReg storageReg = storage.gpr();
2412
2413 if (!m_compileOkay)
2414 return;
2415
2416 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2417
2418 GPRTemporary result(this);
2419
2420 m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.gpr());
2421 if (node->arrayMode().isSaneChain()) {
2422 ASSERT(node->arrayMode().type() == Array::Contiguous);
2423 JITCompiler::Jump notHole = m_jit.branchIfNotEmpty(result.gpr());
2424 m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), result.gpr());
2425 notHole.link(&m_jit);
2426 } else {
2427 speculationCheck(
2428 LoadFromHole, JSValueRegs(), 0,
2429 m_jit.branchIfEmpty(result.gpr()));
2430 }
2431 jsValueResult(result.gpr(), node, node->arrayMode().type() == Array::Int32 ? DataFormatJSInt32 : DataFormatJS);
2432 break;
2433 }
2434
2435 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
2436 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
2437 StorageOperand storage(this, m_graph.varArgChild(node, 2));
2438
2439 GPRReg baseReg = base.gpr();
2440 GPRReg propertyReg = property.gpr();
2441 GPRReg storageReg = storage.gpr();
2442
2443 if (!m_compileOkay)
2444 return;
2445
2446 GPRTemporary result(this);
2447 GPRReg resultReg = result.gpr();
2448
2449 MacroAssembler::JumpList slowCases;
2450
2451 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2452
2453 m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg);
2454 slowCases.append(m_jit.branchIfEmpty(resultReg));
2455
2456 addSlowPathGenerator(
2457 slowPathCall(
2458 slowCases, this, operationGetByValObjectInt,
2459 result.gpr(), baseReg, propertyReg));
2460
2461 jsValueResult(resultReg, node);
2462 break;
2463 }
2464
2465 case Array::Double: {
2466 if (node->arrayMode().isInBounds()) {
2467 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
2468 StorageOperand storage(this, m_graph.varArgChild(node, 2));
2469
2470 GPRReg propertyReg = property.gpr();
2471 GPRReg storageReg = storage.gpr();
2472
2473 if (!m_compileOkay)
2474 return;
2475
2476 FPRTemporary result(this);
2477 FPRReg resultReg = result.fpr();
2478
2479 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2480
2481 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg);
2482 if (!node->arrayMode().isSaneChain())
2483 speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branchIfNaN(resultReg));
2484 doubleResult(resultReg, node);
2485 break;
2486 }
2487
2488 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
2489 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
2490 StorageOperand storage(this, m_graph.varArgChild(node, 2));
2491
2492 GPRReg baseReg = base.gpr();
2493 GPRReg propertyReg = property.gpr();
2494 GPRReg storageReg = storage.gpr();
2495
2496 if (!m_compileOkay)
2497 return;
2498
2499 GPRTemporary result(this);
2500 FPRTemporary temp(this);
2501 GPRReg resultReg = result.gpr();
2502 FPRReg tempReg = temp.fpr();
2503
2504 MacroAssembler::JumpList slowCases;
2505
2506 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2507
2508 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
2509 slowCases.append(m_jit.branchIfNaN(tempReg));
2510 boxDouble(tempReg, resultReg);
2511
2512 addSlowPathGenerator(
2513 slowPathCall(
2514 slowCases, this, operationGetByValObjectInt,
2515 result.gpr(), baseReg, propertyReg));
2516
2517 jsValueResult(resultReg, node);
2518 break;
2519 }
2520
2521 case Array::ArrayStorage:
2522 case Array::SlowPutArrayStorage: {
2523 if (node->arrayMode().isInBounds()) {
2524 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
2525 StorageOperand storage(this, m_graph.varArgChild(node, 2));
2526
2527 GPRReg propertyReg = property.gpr();
2528 GPRReg storageReg = storage.gpr();
2529
2530 if (!m_compileOkay)
2531 return;
2532
2533 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())));
2534
2535 GPRTemporary result(this);
2536 m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()), result.gpr());
2537 speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branchIfEmpty(result.gpr()));
2538
2539 jsValueResult(result.gpr(), node);
2540 break;
2541 }
2542
2543 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
2544 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
2545 StorageOperand storage(this, m_graph.varArgChild(node, 2));
2546
2547 GPRReg baseReg = base.gpr();
2548 GPRReg propertyReg = property.gpr();
2549 GPRReg storageReg = storage.gpr();
2550
2551 if (!m_compileOkay)
2552 return;
2553
2554 GPRTemporary result(this);
2555 GPRReg resultReg = result.gpr();
2556
2557 MacroAssembler::JumpList slowCases;
2558
2559 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())));
2560
2561 m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()), resultReg);
2562 slowCases.append(m_jit.branchIfEmpty(resultReg));
2563
2564 addSlowPathGenerator(
2565 slowPathCall(
2566 slowCases, this, operationGetByValObjectInt,
2567 result.gpr(), baseReg, propertyReg));
2568
2569 jsValueResult(resultReg, node);
2570 break;
2571 }
2572 case Array::String:
2573 compileGetByValOnString(node);
2574 break;
2575 case Array::DirectArguments:
2576 compileGetByValOnDirectArguments(node);
2577 break;
2578 case Array::ScopedArguments:
2579 compileGetByValOnScopedArguments(node);
2580 break;
2581 case Array::Int8Array:
2582 case Array::Int16Array:
2583 case Array::Int32Array:
2584 case Array::Uint8Array:
2585 case Array::Uint8ClampedArray:
2586 case Array::Uint16Array:
2587 case Array::Uint32Array:
2588 case Array::Float32Array:
2589 case Array::Float64Array: {
2590 TypedArrayType type = node->arrayMode().typedArrayType();
2591 if (isInt(type))
2592 compileGetByValOnIntTypedArray(node, type);
2593 else
2594 compileGetByValOnFloatTypedArray(node, type);
2595 } }
2596 break;
2597 }
2598
2599 case GetByValWithThis: {
2600 compileGetByValWithThis(node);
2601 break;
2602 }
2603
2604 case PutByValDirect:
2605 case PutByVal:
2606 case PutByValAlias: {
2607 Edge child1 = m_jit.graph().varArgChild(node, 0);
2608 Edge child2 = m_jit.graph().varArgChild(node, 1);
2609 Edge child3 = m_jit.graph().varArgChild(node, 2);
2610 Edge child4 = m_jit.graph().varArgChild(node, 3);
2611
2612 ArrayMode arrayMode = node->arrayMode().modeForPut();
2613 bool alreadyHandled = false;
2614
2615 switch (arrayMode.type()) {
2616 case Array::SelectUsingPredictions:
2617 case Array::ForceExit:
2618 DFG_CRASH(m_jit.graph(), node, "Bad array mode type");
2619 break;
2620 case Array::Generic: {
2621 DFG_ASSERT(m_jit.graph(), node, node->op() == PutByVal || node->op() == PutByValDirect, node->op());
2622
2623 if (child1.useKind() == CellUse) {
2624 if (child2.useKind() == StringUse) {
2625 compilePutByValForCellWithString(node, child1, child2, child3);
2626 alreadyHandled = true;
2627 break;
2628 }
2629
2630 if (child2.useKind() == SymbolUse) {
2631 compilePutByValForCellWithSymbol(node, child1, child2, child3);
2632 alreadyHandled = true;
2633 break;
2634 }
2635 }
2636
2637 JSValueOperand arg1(this, child1);
2638 JSValueOperand arg2(this, child2);
2639 JSValueOperand arg3(this, child3);
2640 GPRReg arg1GPR = arg1.gpr();
2641 GPRReg arg2GPR = arg2.gpr();
2642 GPRReg arg3GPR = arg3.gpr();
2643 flushRegisters();
2644 if (node->op() == PutByValDirect)
2645 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValDirectStrict : operationPutByValDirectNonStrict, arg1GPR, arg2GPR, arg3GPR);
2646 else
2647 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValStrict : operationPutByValNonStrict, arg1GPR, arg2GPR, arg3GPR);
2648 m_jit.exceptionCheck();
2649
2650 noResult(node);
2651 alreadyHandled = true;
2652 break;
2653 }
2654 default:
2655 break;
2656 }
2657
2658 if (alreadyHandled)
2659 break;
2660
2661 SpeculateCellOperand base(this, child1);
2662 SpeculateStrictInt32Operand property(this, child2);
2663
2664 GPRReg baseReg = base.gpr();
2665 GPRReg propertyReg = property.gpr();
2666
2667 switch (arrayMode.type()) {
2668 case Array::Int32:
2669 case Array::Contiguous: {
2670 JSValueOperand value(this, child3, ManualOperandSpeculation);
2671
2672 GPRReg valueReg = value.gpr();
2673
2674 if (!m_compileOkay)
2675 return;
2676
2677 if (arrayMode.type() == Array::Int32) {
2678 DFG_TYPE_CHECK(
2679 JSValueRegs(valueReg), child3, SpecInt32Only,
2680 m_jit.branchIfNotInt32(valueReg));
2681 }
2682
2683 StorageOperand storage(this, child4);
2684 GPRReg storageReg = storage.gpr();
2685
2686 if (node->op() == PutByValAlias) {
2687 // Store the value to the array.
2688 GPRReg propertyReg = property.gpr();
2689 GPRReg valueReg = value.gpr();
2690 m_jit.store64(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight));
2691
2692 noResult(node);
2693 break;
2694 }
2695
2696 GPRTemporary temporary;
2697 GPRReg temporaryReg = temporaryRegisterForPutByVal(temporary, node);
2698
2699 MacroAssembler::Jump slowCase;
2700
2701 if (arrayMode.isInBounds()) {
2702 speculationCheck(
2703 OutOfBounds, JSValueRegs(), 0,
2704 m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2705 } else {
2706 MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
2707
2708 slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength()));
2709
2710 if (!arrayMode.isOutOfBounds())
2711 speculationCheck(OutOfBounds, JSValueRegs(), 0, slowCase);
2712
2713 m_jit.add32(TrustedImm32(1), propertyReg, temporaryReg);
2714 m_jit.store32(temporaryReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
2715
2716 inBounds.link(&m_jit);
2717 }
2718
2719 m_jit.store64(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight));
2720
2721 base.use();
2722 property.use();
2723 value.use();
2724 storage.use();
2725
2726 if (arrayMode.isOutOfBounds()) {
2727 addSlowPathGenerator(slowPathCall(
2728 slowCase, this,
2729 m_jit.isStrictModeFor(node->origin.semantic)
2730 ? (node->op() == PutByValDirect ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsStrict)
2731 : (node->op() == PutByValDirect ? operationPutByValDirectBeyondArrayBoundsNonStrict : operationPutByValBeyondArrayBoundsNonStrict),
2732 NoResult, baseReg, propertyReg, valueReg));
2733 }
2734
2735 noResult(node, UseChildrenCalledExplicitly);
2736 break;
2737 }
2738
2739 case Array::Double: {
2740 compileDoublePutByVal(node, base, property);
2741 break;
2742 }
2743
2744 case Array::ArrayStorage:
2745 case Array::SlowPutArrayStorage: {
2746 JSValueOperand value(this, child3);
2747
2748 GPRReg valueReg = value.gpr();
2749
2750 if (!m_compileOkay)
2751 return;
2752
2753 StorageOperand storage(this, child4);
2754 GPRReg storageReg = storage.gpr();
2755
2756 if (node->op() == PutByValAlias) {
2757 // Store the value to the array.
2758 GPRReg propertyReg = property.gpr();
2759 GPRReg valueReg = value.gpr();
2760 m_jit.store64(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()));
2761
2762 noResult(node);
2763 break;
2764 }
2765
2766 GPRTemporary temporary;
2767 GPRReg temporaryReg = temporaryRegisterForPutByVal(temporary, node);
2768
2769 MacroAssembler::JumpList slowCases;
2770
2771 MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset()));
2772 if (!arrayMode.isOutOfBounds())
2773 speculationCheck(OutOfBounds, JSValueRegs(), 0, beyondArrayBounds);
2774 else
2775 slowCases.append(beyondArrayBounds);
2776
2777 // Check if we're writing to a hole; if so increment m_numValuesInVector.
2778 if (arrayMode.isInBounds()) {
2779 speculationCheck(
2780 StoreToHole, JSValueRegs(), 0,
2781 m_jit.branchTest64(MacroAssembler::Zero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset())));
2782 } else {
2783 MacroAssembler::Jump notHoleValue = m_jit.branchTest64(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()));
2784 if (arrayMode.isSlowPut()) {
2785 // This is sort of strange. If we wanted to optimize this code path, we would invert
2786 // the above branch. But it's simply not worth it since this only happens if we're
2787 // already having a bad time.
2788 slowCases.append(m_jit.jump());
2789 } else {
2790 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, ArrayStorage::numValuesInVectorOffset()));
2791
2792 // If we're writing to a hole we might be growing the array;
2793 MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
2794 m_jit.add32(TrustedImm32(1), propertyReg, temporaryReg);
2795 m_jit.store32(temporaryReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
2796
2797 lengthDoesNotNeedUpdate.link(&m_jit);
2798 }
2799 notHoleValue.link(&m_jit);
2800 }
2801
2802 // Store the value to the array.
2803 m_jit.store64(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()));
2804
2805 base.use();
2806 property.use();
2807 value.use();
2808 storage.use();
2809
2810 if (!slowCases.empty()) {
2811 addSlowPathGenerator(slowPathCall(
2812 slowCases, this,
2813 m_jit.isStrictModeFor(node->origin.semantic)
2814 ? (node->op() == PutByValDirect ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsStrict)
2815 : (node->op() == PutByValDirect ? operationPutByValDirectBeyondArrayBoundsNonStrict : operationPutByValBeyondArrayBoundsNonStrict),
2816 NoResult, baseReg, propertyReg, valueReg));
2817 }
2818
2819 noResult(node, UseChildrenCalledExplicitly);
2820 break;
2821 }
2822
2823 case Array::Int8Array:
2824 case Array::Int16Array:
2825 case Array::Int32Array:
2826 case Array::Uint8Array:
2827 case Array::Uint8ClampedArray:
2828 case Array::Uint16Array:
2829 case Array::Uint32Array:
2830 case Array::Float32Array:
2831 case Array::Float64Array: {
2832 TypedArrayType type = arrayMode.typedArrayType();
2833 if (isInt(type))
2834 compilePutByValForIntTypedArray(base.gpr(), property.gpr(), node, type);
2835 else
2836 compilePutByValForFloatTypedArray(base.gpr(), property.gpr(), node, type);
2837 break;
2838 }
2839
2840 case Array::AnyTypedArray:
2841 case Array::String:
2842 case Array::DirectArguments:
2843 case Array::ForceExit:
2844 case Array::Generic:
2845 case Array::ScopedArguments:
2846 case Array::SelectUsingArguments:
2847 case Array::SelectUsingPredictions:
2848 case Array::Undecided:
2849 case Array::Unprofiled:
2850 RELEASE_ASSERT_NOT_REACHED();
2851 }
2852 break;
2853 }
2854
2855 case AtomicsAdd:
2856 case AtomicsAnd:
2857 case AtomicsCompareExchange:
2858 case AtomicsExchange:
2859 case AtomicsLoad:
2860 case AtomicsOr:
2861 case AtomicsStore:
2862 case AtomicsSub:
2863 case AtomicsXor: {
2864 unsigned numExtraArgs = numExtraAtomicsArgs(node->op());
2865 Edge baseEdge = m_jit.graph().child(node, 0);
2866 Edge indexEdge = m_jit.graph().child(node, 1);
2867 Edge argEdges[maxNumExtraAtomicsArgs];
2868 for (unsigned i = numExtraArgs; i--;)
2869 argEdges[i] = m_jit.graph().child(node, 2 + i);
2870 Edge storageEdge = m_jit.graph().child(node, 2 + numExtraArgs);
2871
2872 GPRReg baseGPR;
2873 GPRReg indexGPR;
2874 GPRReg argGPRs[2];
2875 GPRReg resultGPR;
2876
2877 auto callSlowPath = [&] () {
2878 switch (node->op()) {
2879 case AtomicsAdd:
2880 callOperation(operationAtomicsAdd, resultGPR, baseGPR, indexGPR, argGPRs[0]);
2881 break;
2882 case AtomicsAnd:
2883 callOperation(operationAtomicsAnd, resultGPR, baseGPR, indexGPR, argGPRs[0]);
2884 break;
2885 case AtomicsCompareExchange:
2886 callOperation(operationAtomicsCompareExchange, resultGPR, baseGPR, indexGPR, argGPRs[0], argGPRs[1]);
2887 break;
2888 case AtomicsExchange:
2889 callOperation(operationAtomicsExchange, resultGPR, baseGPR, indexGPR, argGPRs[0]);
2890 break;
2891 case AtomicsLoad:
2892 callOperation(operationAtomicsLoad, resultGPR, baseGPR, indexGPR);
2893 break;
2894 case AtomicsOr:
2895 callOperation(operationAtomicsOr, resultGPR, baseGPR, indexGPR, argGPRs[0]);
2896 break;
2897 case AtomicsStore:
2898 callOperation(operationAtomicsStore, resultGPR, baseGPR, indexGPR, argGPRs[0]);
2899 break;
2900 case AtomicsSub:
2901 callOperation(operationAtomicsSub, resultGPR, baseGPR, indexGPR, argGPRs[0]);
2902 break;
2903 case AtomicsXor:
2904 callOperation(operationAtomicsXor, resultGPR, baseGPR, indexGPR, argGPRs[0]);
2905 break;
2906 default:
2907 RELEASE_ASSERT_NOT_REACHED();
2908 break;
2909 }
2910 };
2911
2912 if (!storageEdge) {
2913 // We are in generic mode!
2914 JSValueOperand base(this, baseEdge);
2915 JSValueOperand index(this, indexEdge);
2916 Optional<JSValueOperand> args[2];
2917 baseGPR = base.gpr();
2918 indexGPR = index.gpr();
2919 for (unsigned i = numExtraArgs; i--;) {
2920 args[i].emplace(this, argEdges[i]);
2921 argGPRs[i] = args[i]->gpr();
2922 }
2923
2924 flushRegisters();
2925 GPRFlushedCallResult result(this);
2926 resultGPR = result.gpr();
2927 callSlowPath();
2928 m_jit.exceptionCheck();
2929
2930 jsValueResult(resultGPR, node);
2931 break;
2932 }
2933
2934 TypedArrayType type = node->arrayMode().typedArrayType();
2935
2936 SpeculateCellOperand base(this, baseEdge);
2937 SpeculateStrictInt32Operand index(this, indexEdge);
2938
2939 baseGPR = base.gpr();
2940 indexGPR = index.gpr();
2941
2942 emitTypedArrayBoundsCheck(node, baseGPR, indexGPR);
2943
2944 GPRTemporary args[2];
2945
2946 JITCompiler::JumpList slowPathCases;
2947
2948 bool ok = true;
2949 for (unsigned i = numExtraArgs; i--;) {
2950 if (!getIntTypedArrayStoreOperand(args[i], indexGPR, argEdges[i], slowPathCases)) {
2951 noResult(node);
2952 ok = false;
2953 }
2954 argGPRs[i] = args[i].gpr();
2955 }
2956 if (!ok)
2957 break;
2958
2959 StorageOperand storage(this, storageEdge);
2960 GPRTemporary oldValue(this);
2961 GPRTemporary result(this);
2962 GPRTemporary newValue(this);
2963 GPRReg storageGPR = storage.gpr();
2964 GPRReg oldValueGPR = oldValue.gpr();
2965 resultGPR = result.gpr();
2966 GPRReg newValueGPR = newValue.gpr();
2967
2968 // FIXME: It shouldn't be necessary to nop-pad between register allocation and a jump label.
2969 // https://bugs.webkit.org/show_bug.cgi?id=170974
2970 m_jit.nop();
2971
2972 JITCompiler::Label loop = m_jit.label();
2973
2974 loadFromIntTypedArray(storageGPR, indexGPR, oldValueGPR, type);
2975 m_jit.move(oldValueGPR, newValueGPR);
2976 m_jit.move(oldValueGPR, resultGPR);
2977
2978 switch (node->op()) {
2979 case AtomicsAdd:
2980 m_jit.add32(argGPRs[0], newValueGPR);
2981 break;
2982 case AtomicsAnd:
2983 m_jit.and32(argGPRs[0], newValueGPR);
2984 break;
2985 case AtomicsCompareExchange: {
2986 switch (elementSize(type)) {
2987 case 1:
2988 if (isSigned(type))
2989 m_jit.signExtend8To32(argGPRs[0], argGPRs[0]);
2990 else
2991 m_jit.and32(TrustedImm32(0xff), argGPRs[0]);
2992 break;
2993 case 2:
2994 if (isSigned(type))
2995 m_jit.signExtend16To32(argGPRs[0], argGPRs[0]);
2996 else
2997 m_jit.and32(TrustedImm32(0xffff), argGPRs[0]);
2998 break;
2999 case 4:
3000 break;
3001 default:
3002 RELEASE_ASSERT_NOT_REACHED();
3003 break;
3004 }
3005 JITCompiler::Jump fail = m_jit.branch32(JITCompiler::NotEqual, oldValueGPR, argGPRs[0]);
3006 m_jit.move(argGPRs[1], newValueGPR);
3007 fail.link(&m_jit);
3008 break;
3009 }
3010 case AtomicsExchange:
3011 m_jit.move(argGPRs[0], newValueGPR);
3012 break;
3013 case AtomicsLoad:
3014 break;
3015 case AtomicsOr:
3016 m_jit.or32(argGPRs[0], newValueGPR);
3017 break;
3018 case AtomicsStore:
3019 m_jit.move(argGPRs[0], newValueGPR);
3020 m_jit.move(argGPRs[0], resultGPR);
3021 break;
3022 case AtomicsSub:
3023 m_jit.sub32(argGPRs[0], newValueGPR);
3024 break;
3025 case AtomicsXor:
3026 m_jit.xor32(argGPRs[0], newValueGPR);
3027 break;
3028 default:
3029 RELEASE_ASSERT_NOT_REACHED();
3030 break;
3031 }
3032
3033 JITCompiler::JumpList success;
3034 switch (elementSize(type)) {
3035 case 1:
3036 success = m_jit.branchAtomicWeakCAS8(JITCompiler::Success, oldValueGPR, newValueGPR, JITCompiler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesOne));
3037 break;
3038 case 2:
3039 success = m_jit.branchAtomicWeakCAS16(JITCompiler::Success, oldValueGPR, newValueGPR, JITCompiler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesTwo));
3040 break;
3041 case 4:
3042 success = m_jit.branchAtomicWeakCAS32(JITCompiler::Success, oldValueGPR, newValueGPR, JITCompiler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesFour));
3043 break;
3044 default:
3045 RELEASE_ASSERT_NOT_REACHED();
3046 break;
3047 }
3048 m_jit.jump().linkTo(loop, &m_jit);
3049
3050 if (!slowPathCases.empty()) {
3051 slowPathCases.link(&m_jit);
3052 silentSpillAllRegisters(resultGPR);
3053 // Since we spilled, we can do things to registers.
3054 m_jit.boxCell(baseGPR, JSValueRegs(baseGPR));
3055 m_jit.boxInt32(indexGPR, JSValueRegs(indexGPR));
3056 for (unsigned i = numExtraArgs; i--;)
3057 m_jit.boxInt32(argGPRs[i], JSValueRegs(argGPRs[i]));
3058 callSlowPath();
3059 silentFillAllRegisters();
3060 m_jit.exceptionCheck();
3061 }
3062
3063 success.link(&m_jit);
3064 setIntTypedArrayLoadResult(node, resultGPR, type);
3065 break;
3066 }
3067
3068 case AtomicsIsLockFree: {
3069 if (node->child1().useKind() != Int32Use) {
3070 JSValueOperand operand(this, node->child1());
3071 GPRReg operandGPR = operand.gpr();
3072 flushRegisters();
3073 GPRFlushedCallResult result(this);
3074 GPRReg resultGPR = result.gpr();
3075 callOperation(operationAtomicsIsLockFree, resultGPR, operandGPR);
3076 m_jit.exceptionCheck();
3077 jsValueResult(resultGPR, node);
3078 break;
3079 }
3080
3081 SpeculateInt32Operand operand(this, node->child1());
3082 GPRTemporary result(this);
3083 GPRReg operandGPR = operand.gpr();
3084 GPRReg resultGPR = result.gpr();
3085 m_jit.move(TrustedImm32(ValueTrue), resultGPR);
3086 JITCompiler::JumpList done;
3087 done.append(m_jit.branch32(JITCompiler::Equal, operandGPR, TrustedImm32(4)));
3088 done.append(m_jit.branch32(JITCompiler::Equal, operandGPR, TrustedImm32(1)));
3089 done.append(m_jit.branch32(JITCompiler::Equal, operandGPR, TrustedImm32(2)));
3090 m_jit.move(TrustedImm32(ValueFalse), resultGPR);
3091 done.link(&m_jit);
3092 jsValueResult(resultGPR, node);
3093 break;
3094 }
3095
3096 case RegExpExec: {
3097 compileRegExpExec(node);
3098 break;
3099 }
3100
3101 case RegExpExecNonGlobalOrSticky: {
3102 compileRegExpExecNonGlobalOrSticky(node);
3103 break;
3104 }
3105
3106 case RegExpMatchFastGlobal: {
3107 compileRegExpMatchFastGlobal(node);
3108 break;
3109 }
3110
3111 case RegExpTest: {
3112 compileRegExpTest(node);
3113 break;
3114 }
3115
3116 case RegExpMatchFast: {
3117 compileRegExpMatchFast(node);
3118 break;
3119 }
3120
3121 case StringReplace:
3122 case StringReplaceRegExp: {
3123 compileStringReplace(node);
3124 break;
3125 }
3126
3127 case GetRegExpObjectLastIndex: {
3128 compileGetRegExpObjectLastIndex(node);
3129 break;
3130 }
3131
3132 case SetRegExpObjectLastIndex: {
3133 compileSetRegExpObjectLastIndex(node);
3134 break;
3135 }
3136
3137 case RecordRegExpCachedResult: {
3138 compileRecordRegExpCachedResult(node);
3139 break;
3140 }
3141
3142 case ArrayPush: {
3143 compileArrayPush(node);
3144 break;
3145 }
3146
3147 case ArraySlice: {
3148 compileArraySlice(node);
3149 break;
3150 }
3151
3152 case ArrayIndexOf: {
3153 compileArrayIndexOf(node);
3154 break;
3155 }
3156
3157 case ArrayPop: {
3158 ASSERT(node->arrayMode().isJSArray());
3159
3160 SpeculateCellOperand base(this, node->child1());
3161 StorageOperand storage(this, node->child2());
3162 GPRTemporary value(this);
3163 GPRTemporary storageLength(this);
3164 FPRTemporary temp(this); // This is kind of lame, since we don't always need it. I'm relying on the fact that we don't have FPR pressure, especially in code that uses pop().
3165
3166 GPRReg baseGPR = base.gpr();
3167 GPRReg storageGPR = storage.gpr();
3168 GPRReg valueGPR = value.gpr();
3169 GPRReg storageLengthGPR = storageLength.gpr();
3170 FPRReg tempFPR = temp.fpr();
3171
3172 switch (node->arrayMode().type()) {
3173 case Array::Int32:
3174 case Array::Double:
3175 case Array::Contiguous: {
3176 m_jit.load32(
3177 MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
3178 MacroAssembler::Jump undefinedCase =
3179 m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR);
3180 m_jit.sub32(TrustedImm32(1), storageLengthGPR);
3181 m_jit.store32(
3182 storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
3183 MacroAssembler::Jump slowCase;
3184 if (node->arrayMode().type() == Array::Double) {
3185 m_jit.loadDouble(
3186 MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight),
3187 tempFPR);
3188 // FIXME: This would not have to be here if changing the publicLength also zeroed the values between the old
3189 // length and the new length.
3190 m_jit.store64(
3191 MacroAssembler::TrustedImm64(bitwise_cast<int64_t>(PNaN)), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
3192 slowCase = m_jit.branchIfNaN(tempFPR);
3193 boxDouble(tempFPR, valueGPR);
3194 } else {
3195 m_jit.load64(
3196 MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight),
3197 valueGPR);
3198 // FIXME: This would not have to be here if changing the publicLength also zeroed the values between the old
3199 // length and the new length.
3200 m_jit.store64(
3201 MacroAssembler::TrustedImm64((int64_t)0), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
3202 slowCase = m_jit.branchIfEmpty(valueGPR);
3203 }
3204
3205 addSlowPathGenerator(
3206 slowPathMove(
3207 undefinedCase, this,
3208 MacroAssembler::TrustedImm64(JSValue::encode(jsUndefined())), valueGPR));
3209 addSlowPathGenerator(
3210 slowPathCall(
3211 slowCase, this, operationArrayPopAndRecoverLength, valueGPR, baseGPR));
3212
3213 // We can't know for sure that the result is an int because of the slow paths. :-/
3214 jsValueResult(valueGPR, node);
3215 break;
3216 }
3217
3218 case Array::ArrayStorage: {
3219 m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
3220
3221 JITCompiler::Jump undefinedCase =
3222 m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR);
3223
3224 m_jit.sub32(TrustedImm32(1), storageLengthGPR);
3225
3226 JITCompiler::JumpList slowCases;
3227 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset())));
3228
3229 m_jit.load64(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()), valueGPR);
3230 slowCases.append(m_jit.branchIfEmpty(valueGPR));
3231
3232 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
3233
3234 m_jit.store64(MacroAssembler::TrustedImm64((int64_t)0), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()));
3235 m_jit.sub32(MacroAssembler::TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
3236
3237 addSlowPathGenerator(
3238 slowPathMove(
3239 undefinedCase, this,
3240 MacroAssembler::TrustedImm64(JSValue::encode(jsUndefined())), valueGPR));
3241
3242 addSlowPathGenerator(
3243 slowPathCall(
3244 slowCases, this, operationArrayPop, valueGPR, baseGPR));
3245
3246 jsValueResult(valueGPR, node);
3247 break;
3248 }
3249
3250 default:
3251 CRASH();
3252 break;
3253 }
3254 break;
3255 }
3256
3257 case DFG::Jump: {
3258 jump(node->targetBlock());
3259 noResult(node);
3260 break;
3261 }
3262
3263 case Branch:
3264 emitBranch(node);
3265 break;
3266
3267 case Switch:
3268 emitSwitch(node);
3269 break;
3270
3271 case Return: {
3272 ASSERT(GPRInfo::callFrameRegister != GPRInfo::regT1);
3273 ASSERT(GPRInfo::regT1 != GPRInfo::returnValueGPR);
3274 ASSERT(GPRInfo::returnValueGPR != GPRInfo::callFrameRegister);
3275
3276 // Return the result in returnValueGPR.
3277 JSValueOperand op1(this, node->child1());
3278 m_jit.move(op1.gpr(), GPRInfo::returnValueGPR);
3279
3280 m_jit.emitRestoreCalleeSaves();
3281 m_jit.emitFunctionEpilogue();
3282 m_jit.ret();
3283
3284 noResult(node);
3285 break;
3286 }
3287
3288 case Throw: {
3289 compileThrow(node);
3290 break;
3291 }
3292
3293 case ThrowStaticError: {
3294 compileThrowStaticError(node);
3295 break;
3296 }
3297
3298 case BooleanToNumber: {
3299 switch (node->child1().useKind()) {
3300 case BooleanUse: {
3301 JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
3302 GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).
3303
3304 m_jit.move(value.gpr(), result.gpr());
3305 m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), result.gpr());
3306 DFG_TYPE_CHECK(
3307 JSValueRegs(value.gpr()), node->child1(), SpecBoolean, m_jit.branchTest64(
3308 JITCompiler::NonZero, result.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
3309
3310 int32Result(result.gpr(), node);
3311 break;
3312 }
3313
3314 case UntypedUse: {
3315 JSValueOperand value(this, node->child1());
3316 GPRTemporary result(this);
3317
3318 if (!m_interpreter.needsTypeCheck(node->child1(), SpecBoolInt32 | SpecBoolean)) {
3319 m_jit.move(value.gpr(), result.gpr());
3320 m_jit.and32(TrustedImm32(1), result.gpr());
3321 int32Result(result.gpr(), node);
3322 break;
3323 }
3324
3325 m_jit.move(value.gpr(), result.gpr());
3326 m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), result.gpr());
3327 JITCompiler::Jump isBoolean = m_jit.branchTest64(
3328 JITCompiler::Zero, result.gpr(), TrustedImm32(static_cast<int32_t>(~1)));
3329 m_jit.move(value.gpr(), result.gpr());
3330 JITCompiler::Jump done = m_jit.jump();
3331 isBoolean.link(&m_jit);
3332 m_jit.or64(GPRInfo::tagTypeNumberRegister, result.gpr());
3333 done.link(&m_jit);
3334
3335 jsValueResult(result.gpr(), node);
3336 break;
3337 }
3338
3339 default:
3340 DFG_CRASH(m_jit.graph(), node, "Bad use kind");
3341 break;
3342 }
3343 break;
3344 }
3345
3346 case ToPrimitive: {
3347 compileToPrimitive(node);
3348 break;
3349 }
3350
3351 case ToNumber: {
3352 JSValueOperand argument(this, node->child1());
3353 GPRTemporary result(this, Reuse, argument);
3354
3355 GPRReg argumentGPR = argument.gpr();
3356 GPRReg resultGPR = result.gpr();
3357
3358 argument.use();
3359
3360 // We have several attempts to remove ToNumber. But ToNumber still exists.
3361 // It means that converting non-numbers to numbers by this ToNumber is not rare.
3362 // Instead of the slow path generator, we emit callOperation here.
3363 if (!(m_state.forNode(node->child1()).m_type & SpecBytecodeNumber)) {
3364 flushRegisters();
3365 callOperation(operationToNumber, resultGPR, argumentGPR);
3366 m_jit.exceptionCheck();
3367 } else {
3368 MacroAssembler::Jump notNumber = m_jit.branchIfNotNumber(argumentGPR);
3369 m_jit.move(argumentGPR, resultGPR);
3370 MacroAssembler::Jump done = m_jit.jump();
3371
3372 notNumber.link(&m_jit);
3373 silentSpillAllRegisters(resultGPR);
3374 callOperation(operationToNumber, resultGPR, argumentGPR);
3375 silentFillAllRegisters();
3376 m_jit.exceptionCheck();
3377
3378 done.link(&m_jit);
3379 }
3380
3381 jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
3382 break;
3383 }
3384
3385 case ToString:
3386 case CallStringConstructor:
3387 case StringValueOf: {
3388 compileToStringOrCallStringConstructorOrStringValueOf(node);
3389 break;
3390 }
3391
3392 case NewStringObject: {
3393 compileNewStringObject(node);
3394 break;
3395 }
3396
3397 case NewSymbol: {
3398 compileNewSymbol(node);
3399 break;
3400 }
3401
3402 case NewArray: {
3403 compileNewArray(node);
3404 break;
3405 }
3406
3407 case NewArrayWithSpread: {
3408 compileNewArrayWithSpread(node);
3409 break;
3410 }
3411
3412 case Spread: {
3413 compileSpread(node);
3414 break;
3415 }
3416
3417 case NewArrayWithSize: {
3418 compileNewArrayWithSize(node);
3419 break;
3420 }
3421
3422 case NewArrayBuffer: {
3423 compileNewArrayBuffer(node);
3424 break;
3425 }
3426
3427 case NewTypedArray: {
3428 compileNewTypedArray(node);
3429 break;
3430 }
3431
3432 case NewRegexp: {
3433 compileNewRegexp(node);
3434 break;
3435 }
3436
3437 case ToObject:
3438 case CallObjectConstructor: {
3439 compileToObjectOrCallObjectConstructor(node);
3440 break;
3441 }
3442
3443 case ToThis: {
3444 compileToThis(node);
3445 break;
3446 }
3447
3448 case ObjectCreate: {
3449 compileObjectCreate(node);
3450 break;
3451 }
3452
3453 case ObjectKeys: {
3454 compileObjectKeys(node);
3455 break;
3456 }
3457
3458 case CreateThis: {
3459 compileCreateThis(node);
3460 break;
3461 }
3462
3463 case NewObject: {
3464 compileNewObject(node);
3465 break;
3466 }
3467
3468 case GetCallee: {
3469 compileGetCallee(node);
3470 break;
3471 }
3472
3473 case SetCallee: {
3474 compileSetCallee(node);
3475 break;
3476 }
3477
3478 case GetArgumentCountIncludingThis: {
3479 compileGetArgumentCountIncludingThis(node);
3480 break;
3481 }
3482
3483 case SetArgumentCountIncludingThis:
3484 compileSetArgumentCountIncludingThis(node);
3485 break;
3486
3487 case GetRestLength: {
3488 compileGetRestLength(node);
3489 break;
3490 }
3491
3492 case GetScope:
3493 compileGetScope(node);
3494 break;
3495
3496 case SkipScope:
3497 compileSkipScope(node);
3498 break;
3499
3500 case GetGlobalObject:
3501 compileGetGlobalObject(node);
3502 break;
3503
3504 case GetGlobalThis:
3505 compileGetGlobalThis(node);
3506 break;
3507
3508 case GetClosureVar: {
3509 compileGetClosureVar(node);
3510 break;
3511 }
3512 case PutClosureVar: {
3513 compilePutClosureVar(node);
3514 break;
3515 }
3516
3517 case TryGetById: {
3518 compileGetById(node, AccessType::TryGet);
3519 break;
3520 }
3521
3522 case GetByIdDirect: {
3523 compileGetById(node, AccessType::GetDirect);
3524 break;
3525 }
3526
3527 case GetByIdDirectFlush: {
3528 compileGetByIdFlush(node, AccessType::GetDirect);
3529 break;
3530 }
3531
3532 case GetById: {
3533 compileGetById(node, AccessType::Get);
3534 break;
3535 }
3536
3537 case GetByIdFlush: {
3538 compileGetByIdFlush(node, AccessType::Get);
3539 break;
3540 }
3541
3542 case GetByIdWithThis: {
3543 if (node->child1().useKind() == CellUse && node->child2().useKind() == CellUse) {
3544 SpeculateCellOperand base(this, node->child1());
3545 GPRReg baseGPR = base.gpr();
3546 SpeculateCellOperand thisValue(this, node->child2());
3547 GPRReg thisValueGPR = thisValue.gpr();
3548
3549 GPRFlushedCallResult result(this);
3550 GPRReg resultGPR = result.gpr();
3551
3552 flushRegisters();
3553
3554 cachedGetByIdWithThis(node->origin.semantic, baseGPR, thisValueGPR, resultGPR, node->identifierNumber(), JITCompiler::JumpList());
3555
3556 jsValueResult(resultGPR, node);
3557
3558 } else {
3559 JSValueOperand base(this, node->child1());
3560 GPRReg baseGPR = base.gpr();
3561 JSValueOperand thisValue(this, node->child2());
3562 GPRReg thisValueGPR = thisValue.gpr();
3563
3564 GPRFlushedCallResult result(this);
3565 GPRReg resultGPR = result.gpr();
3566
3567 flushRegisters();
3568
3569 JITCompiler::JumpList notCellList;
3570 notCellList.append(m_jit.branchIfNotCell(JSValueRegs(baseGPR)));
3571 notCellList.append(m_jit.branchIfNotCell(JSValueRegs(thisValueGPR)));
3572
3573 cachedGetByIdWithThis(node->origin.semantic, baseGPR, thisValueGPR, resultGPR, node->identifierNumber(), notCellList);
3574
3575 jsValueResult(resultGPR, node);
3576 }
3577
3578 break;
3579 }
3580
3581 case GetArrayLength:
3582 compileGetArrayLength(node);
3583 break;
3584
3585 case DeleteById: {
3586 compileDeleteById(node);
3587 break;
3588 }
3589
3590 case DeleteByVal: {
3591 compileDeleteByVal(node);
3592 break;
3593 }
3594
3595 case CheckCell: {
3596 compileCheckCell(node);
3597 break;
3598 }
3599
3600 case CheckNotEmpty: {
3601 compileCheckNotEmpty(node);
3602 break;
3603 }
3604
3605 case AssertNotEmpty: {
3606 if (validationEnabled()) {
3607 JSValueOperand operand(this, node->child1());
3608 GPRReg input = operand.gpr();
3609 auto done = m_jit.branchIfNotEmpty(input);
3610 m_jit.breakpoint();
3611 done.link(&m_jit);
3612 }
3613 noResult(node);
3614 break;
3615 }
3616
3617 case CheckStringIdent:
3618 compileCheckStringIdent(node);
3619 break;
3620
3621 case GetExecutable: {
3622 compileGetExecutable(node);
3623 break;
3624 }
3625
3626 case CheckStructureOrEmpty: {
3627 SpeculateCellOperand cell(this, node->child1());
3628 GPRReg cellGPR = cell.gpr();
3629
3630 GPRReg tempGPR = InvalidGPRReg;
3631 Optional<GPRTemporary> temp;
3632 if (node->structureSet().size() > 1) {
3633 temp.emplace(this);
3634 tempGPR = temp->gpr();
3635 }
3636
3637 MacroAssembler::Jump isEmpty;
3638 if (m_interpreter.forNode(node->child1()).m_type & SpecEmpty)
3639 isEmpty = m_jit.branchIfEmpty(cellGPR);
3640
3641 emitStructureCheck(node, cellGPR, tempGPR);
3642
3643 if (isEmpty.isSet())
3644 isEmpty.link(&m_jit);
3645
3646 noResult(node);
3647 break;
3648 }
3649
3650 case CheckStructure: {
3651 compileCheckStructure(node);
3652 break;
3653 }
3654
3655 case PutStructure: {
3656 RegisteredStructure oldStructure = node->transition()->previous;
3657 RegisteredStructure newStructure = node->transition()->next;
3658
3659 m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node);
3660
3661 SpeculateCellOperand base(this, node->child1());
3662 GPRReg baseGPR = base.gpr();
3663
3664 ASSERT_UNUSED(oldStructure, oldStructure->indexingMode() == newStructure->indexingMode());
3665 ASSERT(oldStructure->typeInfo().type() == newStructure->typeInfo().type());
3666 ASSERT(oldStructure->typeInfo().inlineTypeFlags() == newStructure->typeInfo().inlineTypeFlags());
3667 m_jit.store32(MacroAssembler::TrustedImm32(newStructure->id()), MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()));
3668
3669 noResult(node);
3670 break;
3671 }
3672
3673 case AllocatePropertyStorage:
3674 compileAllocatePropertyStorage(node);
3675 break;
3676
3677 case ReallocatePropertyStorage:
3678 compileReallocatePropertyStorage(node);
3679 break;
3680
3681 case NukeStructureAndSetButterfly:
3682 compileNukeStructureAndSetButterfly(node);
3683 break;
3684
3685 case GetButterfly:
3686 compileGetButterfly(node);
3687 break;
3688
3689 case GetIndexedPropertyStorage: {
3690 compileGetIndexedPropertyStorage(node);
3691 break;
3692 }
3693
3694 case ConstantStoragePointer: {
3695 compileConstantStoragePointer(node);
3696 break;
3697 }
3698
3699 case GetTypedArrayByteOffset: {
3700 compileGetTypedArrayByteOffset(node);
3701 break;
3702 }
3703
3704 case GetPrototypeOf: {
3705 compileGetPrototypeOf(node);
3706 break;
3707 }
3708
3709 case GetByOffset:
3710 case GetGetterSetterByOffset: {
3711 compileGetByOffset(node);
3712 break;
3713 }
3714
3715 case MatchStructure: {
3716 compileMatchStructure(node);
3717 break;
3718 }
3719
3720 case GetGetter: {
3721 compileGetGetter(node);
3722 break;
3723 }
3724
3725 case GetSetter: {
3726 compileGetSetter(node);
3727 break;
3728 }
3729
3730 case PutByOffset: {
3731 compilePutByOffset(node);
3732 break;
3733 }
3734
3735 case PutByIdFlush: {
3736 compilePutByIdFlush(node);
3737 break;
3738 }
3739
3740 case PutById: {
3741 compilePutById(node);
3742 break;
3743 }
3744
3745 case PutByIdWithThis: {
3746 compilePutByIdWithThis(node);
3747 break;
3748 }
3749
3750 case PutByValWithThis: {
3751 JSValueOperand base(this, m_jit.graph().varArgChild(node, 0));
3752 GPRReg baseGPR = base.gpr();
3753 JSValueOperand thisValue(this, m_jit.graph().varArgChild(node, 1));
3754 GPRReg thisValueGPR = thisValue.gpr();
3755 JSValueOperand property(this, m_jit.graph().varArgChild(node, 2));
3756 GPRReg propertyGPR = property.gpr();
3757 JSValueOperand value(this, m_jit.graph().varArgChild(node, 3));
3758 GPRReg valueGPR = value.gpr();
3759
3760 flushRegisters();
3761 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis, NoResult, baseGPR, thisValueGPR, propertyGPR, valueGPR);
3762 m_jit.exceptionCheck();
3763
3764 noResult(node);
3765 break;
3766 }
3767
3768 case PutByIdDirect: {
3769 compilePutByIdDirect(node);
3770 break;
3771 }
3772
3773 case PutGetterById:
3774 case PutSetterById: {
3775 compilePutAccessorById(node);
3776 break;
3777 }
3778
3779 case PutGetterSetterById: {
3780 compilePutGetterSetterById(node);
3781 break;
3782 }
3783
3784 case PutGetterByVal:
3785 case PutSetterByVal: {
3786 compilePutAccessorByVal(node);
3787 break;
3788 }
3789
3790 case DefineDataProperty: {
3791 compileDefineDataProperty(node);
3792 break;
3793 }
3794
3795 case DefineAccessorProperty: {
3796 compileDefineAccessorProperty(node);
3797 break;
3798 }
3799
3800 case GetGlobalLexicalVariable:
3801 case GetGlobalVar: {
3802 compileGetGlobalVariable(node);
3803 break;
3804 }
3805
3806 case PutGlobalVariable: {
3807 compilePutGlobalVariable(node);
3808 break;
3809 }
3810
3811 case PutDynamicVar: {
3812 compilePutDynamicVar(node);
3813 break;
3814 }
3815
3816 case GetDynamicVar: {
3817 compileGetDynamicVar(node);
3818 break;
3819 }
3820
3821 case ResolveScopeForHoistingFuncDeclInEval: {
3822 compileResolveScopeForHoistingFuncDeclInEval(node);
3823 break;
3824 }
3825
3826 case ResolveScope: {
3827 compileResolveScope(node);
3828 break;
3829 }
3830
3831 case NotifyWrite: {
3832 compileNotifyWrite(node);
3833 break;
3834 }
3835
3836 case CheckTypeInfoFlags: {
3837 compileCheckTypeInfoFlags(node);
3838 break;
3839 }
3840
3841 case ParseInt: {
3842 compileParseInt(node);
3843 break;
3844 }
3845
3846 case OverridesHasInstance: {
3847 compileOverridesHasInstance(node);
3848 break;
3849 }
3850
3851 case InstanceOf: {
3852 compileInstanceOf(node);
3853 break;
3854 }
3855
3856 case InstanceOfCustom: {
3857 compileInstanceOfCustom(node);
3858 break;
3859 }
3860
3861 case IsEmpty: {
3862 JSValueOperand value(this, node->child1());
3863 GPRTemporary result(this, Reuse, value);
3864
3865 m_jit.comparePtr(JITCompiler::Equal, value.gpr(), TrustedImm32(JSValue::encode(JSValue())), result.gpr());
3866 m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
3867
3868 jsValueResult(result.gpr(), node, DataFormatJSBoolean);
3869 break;
3870 }
3871
3872 case IsUndefined: {
3873 JSValueOperand value(this, node->child1());
3874 GPRTemporary result(this);
3875 GPRTemporary localGlobalObject(this);
3876 GPRTemporary remoteGlobalObject(this);
3877 GPRTemporary scratch(this);
3878
3879 JITCompiler::Jump isCell = m_jit.branchIfCell(value.jsValueRegs());
3880
3881 m_jit.compare64(JITCompiler::Equal, value.gpr(), TrustedImm32(ValueUndefined), result.gpr());
3882 JITCompiler::Jump done = m_jit.jump();
3883
3884 isCell.link(&m_jit);
3885 JITCompiler::Jump notMasqueradesAsUndefined;
3886 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
3887 m_jit.move(TrustedImm32(0), result.gpr());
3888 notMasqueradesAsUndefined = m_jit.jump();
3889 } else {
3890 JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8(
3891 JITCompiler::NonZero,
3892 JITCompiler::Address(value.gpr(), JSCell::typeInfoFlagsOffset()),
3893 TrustedImm32(MasqueradesAsUndefined));
3894 m_jit.move(TrustedImm32(0), result.gpr());
3895 notMasqueradesAsUndefined = m_jit.jump();
3896
3897 isMasqueradesAsUndefined.link(&m_jit);
3898 GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
3899 GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
3900 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.globalObjectFor(node->origin.semantic)), localGlobalObjectGPR);
3901 m_jit.emitLoadStructure(*m_jit.vm(), value.gpr(), result.gpr(), scratch.gpr());
3902 m_jit.loadPtr(JITCompiler::Address(result.gpr(), Structure::globalObjectOffset()), remoteGlobalObjectGPR);
3903 m_jit.comparePtr(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, result.gpr());
3904 }
3905
3906 notMasqueradesAsUndefined.link(&m_jit);
3907 done.link(&m_jit);
3908 m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
3909 jsValueResult(result.gpr(), node, DataFormatJSBoolean);
3910 break;
3911 }
3912
3913 case IsUndefinedOrNull: {
3914 JSValueOperand value(this, node->child1());
3915 GPRTemporary result(this, Reuse, value);
3916
3917 GPRReg valueGPR = value.gpr();
3918 GPRReg resultGPR = result.gpr();
3919
3920 m_jit.move(valueGPR, resultGPR);
3921 m_jit.and64(CCallHelpers::TrustedImm32(~TagBitUndefined), resultGPR);
3922 m_jit.compare64(CCallHelpers::Equal, resultGPR, CCallHelpers::TrustedImm32(ValueNull), resultGPR);
3923
3924 unblessedBooleanResult(resultGPR, node);
3925 break;
3926 }
3927
3928 case IsBoolean: {
3929 JSValueOperand value(this, node->child1());
3930 GPRTemporary result(this, Reuse, value);
3931
3932 m_jit.move(value.gpr(), result.gpr());
3933 m_jit.xor64(JITCompiler::TrustedImm32(ValueFalse), result.gpr());
3934 m_jit.test64(JITCompiler::Zero, result.gpr(), JITCompiler::TrustedImm32(static_cast<int32_t>(~1)), result.gpr());
3935 m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
3936 jsValueResult(result.gpr(), node, DataFormatJSBoolean);
3937 break;
3938 }
3939
3940 case IsNumber: {
3941 JSValueOperand value(this, node->child1());
3942 GPRTemporary result(this, Reuse, value);
3943
3944 m_jit.test64(JITCompiler::NonZero, value.gpr(), GPRInfo::tagTypeNumberRegister, result.gpr());
3945 m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
3946 jsValueResult(result.gpr(), node, DataFormatJSBoolean);
3947 break;
3948 }
3949
3950 case NumberIsInteger: {
3951 JSValueOperand value(this, node->child1());
3952 GPRTemporary result(this, Reuse, value);
3953
3954 FPRTemporary temp1(this);
3955 FPRTemporary temp2(this);
3956
3957 JSValueRegs valueRegs = JSValueRegs(value.gpr());
3958 GPRReg resultGPR = result.gpr();
3959
3960 FPRReg tempFPR1 = temp1.fpr();
3961 FPRReg tempFPR2 = temp2.fpr();
3962
3963 MacroAssembler::JumpList done;
3964
3965 auto isInt32 = m_jit.branchIfInt32(valueRegs);
3966 auto notNumber = m_jit.branchIfNotDoubleKnownNotInt32(valueRegs);
3967
3968 // We're a double here.
3969 m_jit.unboxDouble(valueRegs.gpr(), resultGPR, tempFPR1);
3970 m_jit.urshift64(TrustedImm32(52), resultGPR);
3971 m_jit.and32(TrustedImm32(0x7ff), resultGPR);
3972 auto notNanNorInfinity = m_jit.branch32(JITCompiler::NotEqual, TrustedImm32(0x7ff), resultGPR);
3973 m_jit.move(TrustedImm32(ValueFalse), resultGPR);
3974 done.append(m_jit.jump());
3975
3976 notNanNorInfinity.link(&m_jit);
3977 m_jit.roundTowardZeroDouble(tempFPR1, tempFPR2);
3978 m_jit.compareDouble(JITCompiler::DoubleEqual, tempFPR1, tempFPR2, resultGPR);
3979 m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
3980 done.append(m_jit.jump());
3981
3982 isInt32.link(&m_jit);
3983 m_jit.move(TrustedImm32(ValueTrue), resultGPR);
3984 done.append(m_jit.jump());
3985
3986 notNumber.link(&m_jit);
3987 m_jit.move(TrustedImm32(ValueFalse), resultGPR);
3988
3989 done.link(&m_jit);
3990 jsValueResult(resultGPR, node, DataFormatJSBoolean);
3991 break;
3992 }
3993
3994 case MapHash: {
3995 switch (node->child1().useKind()) {
3996 case BooleanUse:
3997 case Int32Use:
3998 case SymbolUse:
3999 case ObjectUse: {
4000 JSValueOperand input(this, node->child1(), ManualOperandSpeculation);
4001 GPRTemporary result(this, Reuse, input);
4002 GPRTemporary temp(this);
4003
4004 GPRReg inputGPR = input.gpr();
4005 GPRReg resultGPR = result.gpr();
4006 GPRReg tempGPR = temp.gpr();
4007
4008 speculate(node, node->child1());
4009
4010 m_jit.move(inputGPR, resultGPR);
4011 m_jit.wangsInt64Hash(resultGPR, tempGPR);
4012 int32Result(resultGPR, node);
4013 break;
4014 }
4015 case CellUse:
4016 case StringUse: {
4017 SpeculateCellOperand input(this, node->child1());
4018 GPRTemporary result(this);
4019 Optional<GPRTemporary> temp;
4020
4021 GPRReg tempGPR = InvalidGPRReg;
4022 if (node->child1().useKind() == CellUse) {
4023 temp.emplace(this);
4024 tempGPR = temp->gpr();
4025 }
4026
4027 GPRReg inputGPR = input.gpr();
4028 GPRReg resultGPR = result.gpr();
4029
4030 MacroAssembler::JumpList slowPath;
4031 MacroAssembler::JumpList done;
4032
4033 if (node->child1().useKind() == StringUse)
4034 speculateString(node->child1(), inputGPR);
4035 else {
4036 auto isString = m_jit.branchIfString(inputGPR);
4037 m_jit.move(inputGPR, resultGPR);
4038 m_jit.wangsInt64Hash(resultGPR, tempGPR);
4039 done.append(m_jit.jump());
4040 isString.link(&m_jit);
4041 }
4042
4043 m_jit.loadPtr(MacroAssembler::Address(inputGPR, JSString::offsetOfValue()), resultGPR);
4044 slowPath.append(m_jit.branchIfRopeStringImpl(resultGPR));
4045 m_jit.load32(MacroAssembler::Address(resultGPR, StringImpl::flagsOffset()), resultGPR);
4046 m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), resultGPR);
4047 slowPath.append(m_jit.branchTest32(MacroAssembler::Zero, resultGPR));
4048 done.append(m_jit.jump());
4049
4050 slowPath.link(&m_jit);
4051 silentSpillAllRegisters(resultGPR);
4052 callOperation(operationMapHash, resultGPR, JSValueRegs(inputGPR));
4053 silentFillAllRegisters();
4054 m_jit.exceptionCheck();
4055
4056 done.link(&m_jit);
4057 int32Result(resultGPR, node);
4058 break;
4059 }
4060 default:
4061 RELEASE_ASSERT(node->child1().useKind() == UntypedUse);
4062 break;
4063 }
4064
4065 if (node->child1().useKind() != UntypedUse)
4066 break;
4067
4068 JSValueOperand input(this, node->child1());
4069 GPRTemporary temp(this);
4070 GPRTemporary result(this);
4071
4072 GPRReg inputGPR = input.gpr();
4073 GPRReg resultGPR = result.gpr();
4074 GPRReg tempGPR = temp.gpr();
4075
4076 MacroAssembler::JumpList straightHash;
4077 MacroAssembler::JumpList done;
4078 straightHash.append(m_jit.branchIfNotCell(inputGPR));
4079 MacroAssembler::JumpList slowPath;
4080 straightHash.append(m_jit.branchIfNotString(inputGPR));
4081 m_jit.loadPtr(MacroAssembler::Address(inputGPR, JSString::offsetOfValue()), resultGPR);
4082 slowPath.append(m_jit.branchIfRopeStringImpl(resultGPR));
4083 m_jit.load32(MacroAssembler::Address(resultGPR, StringImpl::flagsOffset()), resultGPR);
4084 m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), resultGPR);
4085 slowPath.append(m_jit.branchTest32(MacroAssembler::Zero, resultGPR));
4086 done.append(m_jit.jump());
4087
4088 straightHash.link(&m_jit);
4089 m_jit.move(inputGPR, resultGPR);
4090 m_jit.wangsInt64Hash(resultGPR, tempGPR);
4091 done.append(m_jit.jump());
4092
4093 slowPath.link(&m_jit);
4094 silentSpillAllRegisters(resultGPR);
4095 callOperation(operationMapHash, resultGPR, JSValueRegs(inputGPR));
4096 silentFillAllRegisters();
4097 m_jit.exceptionCheck();
4098
4099 done.link(&m_jit);
4100 int32Result(resultGPR, node);
4101 break;
4102 }
4103
4104 case NormalizeMapKey: {
4105 compileNormalizeMapKey(node);
4106 break;
4107 }
4108
4109 case GetMapBucket: {
4110 SpeculateCellOperand map(this, node->child1());
4111 JSValueOperand key(this, node->child2(), ManualOperandSpeculation);
4112 SpeculateInt32Operand hash(this, node->child3());
4113 GPRTemporary mask(this);
4114 GPRTemporary index(this);
4115 GPRTemporary buffer(this);
4116 GPRTemporary bucket(this);
4117 GPRTemporary result(this);
4118
4119 GPRReg hashGPR = hash.gpr();
4120 GPRReg mapGPR = map.gpr();
4121 GPRReg maskGPR = mask.gpr();
4122 GPRReg indexGPR = index.gpr();
4123 GPRReg bufferGPR = buffer.gpr();
4124 GPRReg bucketGPR = bucket.gpr();
4125 GPRReg keyGPR = key.gpr();
4126 GPRReg resultGPR = result.gpr();
4127
4128 if (node->child1().useKind() == MapObjectUse)
4129 speculateMapObject(node->child1(), mapGPR);
4130 else if (node->child1().useKind() == SetObjectUse)
4131 speculateSetObject(node->child1(), mapGPR);
4132 else
4133 RELEASE_ASSERT_NOT_REACHED();
4134
4135 if (node->child2().useKind() != UntypedUse)
4136 speculate(node, node->child2());
4137
4138 m_jit.load32(MacroAssembler::Address(mapGPR, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfCapacity()), maskGPR);
4139 m_jit.loadPtr(MacroAssembler::Address(mapGPR, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfBuffer()), bufferGPR);
4140 m_jit.sub32(TrustedImm32(1), maskGPR);
4141 m_jit.move(hashGPR, indexGPR);
4142
4143 MacroAssembler::Label loop = m_jit.label();
4144 MacroAssembler::JumpList done;
4145 MacroAssembler::JumpList slowPathCases;
4146 MacroAssembler::JumpList loopAround;
4147
4148 m_jit.and32(maskGPR, indexGPR);
4149 m_jit.loadPtr(MacroAssembler::BaseIndex(bufferGPR, indexGPR, MacroAssembler::TimesEight), bucketGPR);
4150 m_jit.move(bucketGPR, resultGPR);
4151 auto notPresentInTable = m_jit.branchPtr(MacroAssembler::Equal,
4152 bucketGPR, TrustedImmPtr(bitwise_cast<size_t>(HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::emptyValue())));
4153 loopAround.append(m_jit.branchPtr(MacroAssembler::Equal,
4154 bucketGPR, TrustedImmPtr(bitwise_cast<size_t>(HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::deletedValue()))));
4155
4156 m_jit.load64(MacroAssembler::Address(bucketGPR, HashMapBucket<HashMapBucketDataKey>::offsetOfKey()), bucketGPR);
4157
4158 // Perform Object.is()
4159 switch (node->child2().useKind()) {
4160 case BooleanUse:
4161 case Int32Use:
4162 case SymbolUse:
4163 case ObjectUse: {
4164 done.append(m_jit.branch64(MacroAssembler::Equal, bucketGPR, keyGPR)); // They're definitely the same value, we found the bucket we were looking for!
4165 // Otherwise, loop around.
4166 break;
4167 }
4168 case CellUse: {
4169 done.append(m_jit.branch64(MacroAssembler::Equal, bucketGPR, keyGPR));
4170 loopAround.append(m_jit.branchIfNotCell(JSValueRegs(bucketGPR)));
4171 loopAround.append(m_jit.branchIfNotString(bucketGPR));
4172 loopAround.append(m_jit.branchIfNotString(keyGPR));
4173 // They're both strings.
4174 slowPathCases.append(m_jit.jump());
4175 break;
4176 }
4177 case StringUse: {
4178 done.append(m_jit.branch64(MacroAssembler::Equal, bucketGPR, keyGPR)); // They're definitely the same value, we found the bucket we were looking for!
4179 loopAround.append(m_jit.branchIfNotCell(JSValueRegs(bucketGPR)));
4180 loopAround.append(m_jit.branchIfNotString(bucketGPR));
4181 slowPathCases.append(m_jit.jump());
4182 break;
4183 }
4184 case UntypedUse: {
4185 done.append(m_jit.branch64(MacroAssembler::Equal, bucketGPR, keyGPR)); // They're definitely the same value, we found the bucket we were looking for!
4186 // The input key and bucket's key are already normalized. So if 64-bit compare fails and one is not a cell, they're definitely not equal.
4187 loopAround.append(m_jit.branchIfNotCell(JSValueRegs(bucketGPR)));
4188 // first is a cell here.
4189 loopAround.append(m_jit.branchIfNotCell(JSValueRegs(keyGPR)));
4190 // Both are cells here.
4191 loopAround.append(m_jit.branchIfNotString(bucketGPR));
4192 // The first is a string here.
4193 slowPathCases.append(m_jit.branchIfString(keyGPR));
4194 // The first is a string, but the second is not, we continue to loop around.
4195 loopAround.append(m_jit.jump());
4196 break;
4197 }
4198 default:
4199 RELEASE_ASSERT_NOT_REACHED();
4200 }
4201
4202
4203 if (!loopAround.empty())
4204 loopAround.link(&m_jit);
4205
4206 m_jit.add32(TrustedImm32(1), indexGPR);
4207 m_jit.jump().linkTo(loop, &m_jit);
4208
4209 if (!slowPathCases.empty()) {
4210 slowPathCases.link(&m_jit);
4211 silentSpillAllRegisters(indexGPR);
4212 if (node->child1().useKind() == MapObjectUse)
4213 callOperation(operationJSMapFindBucket, resultGPR, mapGPR, keyGPR, hashGPR);
4214 else
4215 callOperation(operationJSSetFindBucket, resultGPR, mapGPR, keyGPR, hashGPR);
4216 silentFillAllRegisters();
4217 m_jit.exceptionCheck();
4218 done.append(m_jit.jump());
4219 }
4220
4221 notPresentInTable.link(&m_jit);
4222 if (node->child1().useKind() == MapObjectUse)
4223 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->sentinelMapBucket()), resultGPR);
4224 else
4225 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->sentinelSetBucket()), resultGPR);
4226 done.link(&m_jit);
4227 cellResult(resultGPR, node);
4228 break;
4229 }
4230
4231 case GetMapBucketHead:
4232 compileGetMapBucketHead(node);
4233 break;
4234
4235 case GetMapBucketNext:
4236 compileGetMapBucketNext(node);
4237 break;
4238
4239 case LoadKeyFromMapBucket:
4240 compileLoadKeyFromMapBucket(node);
4241 break;
4242
4243 case LoadValueFromMapBucket:
4244 compileLoadValueFromMapBucket(node);
4245 break;
4246
4247 case ExtractValueFromWeakMapGet:
4248 compileExtractValueFromWeakMapGet(node);
4249 break;
4250
4251 case SetAdd:
4252 compileSetAdd(node);
4253 break;
4254
4255 case MapSet:
4256 compileMapSet(node);
4257 break;
4258
4259 case WeakMapGet:
4260 compileWeakMapGet(node);
4261 break;
4262
4263 case WeakSetAdd:
4264 compileWeakSetAdd(node);
4265 break;
4266
4267 case WeakMapSet:
4268 compileWeakMapSet(node);
4269 break;
4270
4271 case StringSlice: {
4272 compileStringSlice(node);
4273 break;
4274 }
4275
4276 case ToLowerCase: {
4277 compileToLowerCase(node);
4278 break;
4279 }
4280
4281 case NumberToStringWithRadix: {
4282 compileNumberToStringWithRadix(node);
4283 break;
4284 }
4285
4286 case NumberToStringWithValidRadixConstant: {
4287 compileNumberToStringWithValidRadixConstant(node);
4288 break;
4289 }
4290
4291 case IsObject: {
4292 compileIsObject(node);
4293 break;
4294 }
4295
4296 case IsObjectOrNull: {
4297 compileIsObjectOrNull(node);
4298 break;
4299 }
4300
4301 case IsFunction: {
4302 compileIsFunction(node);
4303 break;
4304 }
4305
4306 case IsCellWithType: {
4307 compileIsCellWithType(node);
4308 break;
4309 }
4310
4311 case IsTypedArrayView: {
4312 compileIsTypedArrayView(node);
4313 break;
4314 }
4315
4316 case TypeOf: {
4317 compileTypeOf(node);
4318 break;
4319 }
4320
4321 case Flush:
4322 break;
4323
4324 case Call:
4325 case TailCall:
4326 case TailCallInlinedCaller:
4327 case Construct:
4328 case CallVarargs:
4329 case TailCallVarargs:
4330 case TailCallVarargsInlinedCaller:
4331 case CallForwardVarargs:
4332 case ConstructVarargs:
4333 case ConstructForwardVarargs:
4334 case TailCallForwardVarargs:
4335 case TailCallForwardVarargsInlinedCaller:
4336 case CallEval:
4337 case DirectCall:
4338 case DirectConstruct:
4339 case DirectTailCall:
4340 case DirectTailCallInlinedCaller:
4341 emitCall(node);
4342 break;
4343
4344 case LoadVarargs: {
4345 compileLoadVarargs(node);
4346 break;
4347 }
4348
4349 case ForwardVarargs: {
4350 compileForwardVarargs(node);
4351 break;
4352 }
4353
4354 case CreateActivation: {
4355 compileCreateActivation(node);
4356 break;
4357 }
4358
4359 case PushWithScope: {
4360 compilePushWithScope(node);
4361 break;
4362 }
4363
4364 case CreateDirectArguments: {
4365 compileCreateDirectArguments(node);
4366 break;
4367 }
4368
4369 case GetFromArguments: {
4370 compileGetFromArguments(node);
4371 break;
4372 }
4373
4374 case PutToArguments: {
4375 compilePutToArguments(node);
4376 break;
4377 }
4378
4379 case GetArgument: {
4380 compileGetArgument(node);
4381 break;
4382 }
4383
4384 case CreateScopedArguments: {
4385 compileCreateScopedArguments(node);
4386 break;
4387 }
4388
4389 case CreateClonedArguments: {
4390 compileCreateClonedArguments(node);
4391 break;
4392 }
4393 case CreateRest: {
4394 compileCreateRest(node);
4395 break;
4396 }
4397
4398 case NewFunction:
4399 case NewGeneratorFunction:
4400 case NewAsyncGeneratorFunction:
4401 case NewAsyncFunction:
4402 compileNewFunction(node);
4403 break;
4404
4405 case SetFunctionName:
4406 compileSetFunctionName(node);
4407 break;
4408
4409 case InById:
4410 compileInById(node);
4411 break;
4412
4413 case InByVal:
4414 compileInByVal(node);
4415 break;
4416
4417 case HasOwnProperty: {
4418 SpeculateCellOperand object(this, node->child1());
4419 GPRTemporary uniquedStringImpl(this);
4420 GPRTemporary temp(this);
4421 GPRTemporary hash(this);
4422 GPRTemporary structureID(this);
4423 GPRTemporary result(this);
4424
4425 Optional<SpeculateCellOperand> keyAsCell;
4426 Optional<JSValueOperand> keyAsValue;
4427 GPRReg keyGPR;
4428 if (node->child2().useKind() == UntypedUse) {
4429 keyAsValue.emplace(this, node->child2());
4430 keyGPR = keyAsValue->gpr();
4431 } else {
4432 ASSERT(node->child2().useKind() == StringUse || node->child2().useKind() == SymbolUse);
4433 keyAsCell.emplace(this, node->child2());
4434 keyGPR = keyAsCell->gpr();
4435 }
4436
4437 GPRReg objectGPR = object.gpr();
4438 GPRReg implGPR = uniquedStringImpl.gpr();
4439 GPRReg tempGPR = temp.gpr();
4440 GPRReg hashGPR = hash.gpr();
4441 GPRReg structureIDGPR = structureID.gpr();
4442 GPRReg resultGPR = result.gpr();
4443
4444 speculateObject(node->child1());
4445
4446 MacroAssembler::JumpList slowPath;
4447 switch (node->child2().useKind()) {
4448 case SymbolUse: {
4449 speculateSymbol(node->child2(), keyGPR);
4450 m_jit.loadPtr(MacroAssembler::Address(keyGPR, Symbol::offsetOfSymbolImpl()), implGPR);
4451 break;
4452 }
4453 case StringUse: {
4454 speculateString(node->child2(), keyGPR);
4455 m_jit.loadPtr(MacroAssembler::Address(keyGPR, JSString::offsetOfValue()), implGPR);
4456 slowPath.append(m_jit.branchIfRopeStringImpl(implGPR));
4457 slowPath.append(m_jit.branchTest32(
4458 MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
4459 MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
4460 break;
4461 }
4462 case UntypedUse: {
4463 slowPath.append(m_jit.branchIfNotCell(JSValueRegs(keyGPR)));
4464 auto isNotString = m_jit.branchIfNotString(keyGPR);
4465 m_jit.loadPtr(MacroAssembler::Address(keyGPR, JSString::offsetOfValue()), implGPR);
4466 slowPath.append(m_jit.branchIfRopeStringImpl(implGPR));
4467 slowPath.append(m_jit.branchTest32(
4468 MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
4469 MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
4470 auto hasUniquedImpl = m_jit.jump();
4471
4472 isNotString.link(&m_jit);
4473 slowPath.append(m_jit.branchIfNotSymbol(keyGPR));
4474 m_jit.loadPtr(MacroAssembler::Address(keyGPR, Symbol::offsetOfSymbolImpl()), implGPR);
4475
4476 hasUniquedImpl.link(&m_jit);
4477 break;
4478 }
4479 default:
4480 RELEASE_ASSERT_NOT_REACHED();
4481 }
4482
4483 // Note that we don't test if the hash is zero here. AtomicStringImpl's can't have a zero
4484 // hash, however, a SymbolImpl may. But, because this is a cache, we don't care. We only
4485 // ever load the result from the cache if the cache entry matches what we are querying for.
4486 // So we either get super lucky and use zero for the hash and somehow collide with the entity
4487 // we're looking for, or we realize we're comparing against another entity, and go to the
4488 // slow path anyways.
4489 m_jit.load32(MacroAssembler::Address(implGPR, UniquedStringImpl::flagsOffset()), hashGPR);
4490 m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), hashGPR);
4491 m_jit.load32(MacroAssembler::Address(objectGPR, JSCell::structureIDOffset()), structureIDGPR);
4492 m_jit.add32(structureIDGPR, hashGPR);
4493 m_jit.and32(TrustedImm32(HasOwnPropertyCache::mask), hashGPR);
4494 if (hasOneBitSet(sizeof(HasOwnPropertyCache::Entry))) // is a power of 2
4495 m_jit.lshift32(TrustedImm32(getLSBSet(sizeof(HasOwnPropertyCache::Entry))), hashGPR);
4496 else
4497 m_jit.mul32(TrustedImm32(sizeof(HasOwnPropertyCache::Entry)), hashGPR, hashGPR);
4498 ASSERT(m_jit.vm()->hasOwnPropertyCache());
4499 m_jit.move(TrustedImmPtr(m_jit.vm()->hasOwnPropertyCache()), tempGPR);
4500 slowPath.append(m_jit.branchPtr(MacroAssembler::NotEqual,
4501 MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfImpl()), implGPR));
4502 m_jit.load8(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfResult()), resultGPR);
4503 m_jit.load32(MacroAssembler::BaseIndex(tempGPR, hashGPR, MacroAssembler::TimesOne, HasOwnPropertyCache::Entry::offsetOfStructureID()), tempGPR);
4504 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, structureIDGPR));
4505 auto done = m_jit.jump();
4506
4507 slowPath.link(&m_jit);
4508 silentSpillAllRegisters(resultGPR);
4509 callOperation(operationHasOwnProperty, resultGPR, objectGPR, keyGPR);
4510 silentFillAllRegisters();
4511 m_jit.exceptionCheck();
4512
4513 done.link(&m_jit);
4514 m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
4515 jsValueResult(resultGPR, node, DataFormatJSBoolean);
4516 break;
4517 }
4518
4519 case CountExecution:
4520 m_jit.add64(TrustedImm32(1), MacroAssembler::AbsoluteAddress(node->executionCounter()->address()));
4521 break;
4522
4523 case SuperSamplerBegin:
4524 m_jit.add32(TrustedImm32(1), MacroAssembler::AbsoluteAddress(bitwise_cast<void*>(&g_superSamplerCount)));
4525 break;
4526
4527 case SuperSamplerEnd:
4528 m_jit.sub32(TrustedImm32(1), MacroAssembler::AbsoluteAddress(bitwise_cast<void*>(&g_superSamplerCount)));
4529 break;
4530
4531 case ForceOSRExit: {
4532 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
4533 break;
4534 }
4535
4536 case InvalidationPoint:
4537 emitInvalidationPoint(node);
4538 break;
4539
4540 case CheckTraps:
4541 compileCheckTraps(node);
4542 break;
4543
4544 case Phantom:
4545 case Check:
4546 case CheckVarargs:
4547 DFG_NODE_DO_TO_CHILDREN(m_jit.graph(), node, speculate);
4548 noResult(node);
4549 break;
4550
4551 case PhantomLocal:
4552 case LoopHint:
4553 // This is a no-op.
4554 noResult(node);
4555 break;
4556
4557 case Unreachable:
4558 unreachable(node);
4559 break;
4560
4561 case StoreBarrier:
4562 case FencedStoreBarrier: {
4563 compileStoreBarrier(node);
4564 break;
4565 }
4566
4567 case GetEnumerableLength: {
4568 compileGetEnumerableLength(node);
4569 break;
4570 }
4571 case HasGenericProperty: {
4572 compileHasGenericProperty(node);
4573 break;
4574 }
4575 case HasStructureProperty: {
4576 compileHasStructureProperty(node);
4577 break;
4578 }
4579 case HasIndexedProperty: {
4580 compileHasIndexedProperty(node);
4581 break;
4582 }
4583 case GetDirectPname: {
4584 compileGetDirectPname(node);
4585 break;
4586 }
4587 case GetPropertyEnumerator: {
4588 compileGetPropertyEnumerator(node);
4589 break;
4590 }
4591 case GetEnumeratorStructurePname:
4592 case GetEnumeratorGenericPname: {
4593 compileGetEnumeratorPname(node);
4594 break;
4595 }
4596 case ToIndexString: {
4597 compileToIndexString(node);
4598 break;
4599 }
4600 case ProfileType: {
4601 compileProfileType(node);
4602 break;
4603 }
4604 case ProfileControlFlow: {
4605 BasicBlockLocation* basicBlockLocation = node->basicBlockLocation();
4606 basicBlockLocation->emitExecuteCode(m_jit);
4607 noResult(node);
4608 break;
4609 }
4610
4611 case LogShadowChickenPrologue: {
4612 compileLogShadowChickenPrologue(node);
4613 break;
4614 }
4615
4616 case LogShadowChickenTail: {
4617 compileLogShadowChickenTail(node);
4618 break;
4619 }
4620
4621 case MaterializeNewObject:
4622 compileMaterializeNewObject(node);
4623 break;
4624
4625 case CallDOM:
4626 compileCallDOM(node);
4627 break;
4628
4629 case CallDOMGetter:
4630 compileCallDOMGetter(node);
4631 break;
4632
4633 case CheckSubClass:
4634 compileCheckSubClass(node);
4635 break;
4636
4637 case ExtractCatchLocal: {
4638 compileExtractCatchLocal(node);
4639 break;
4640 }
4641
4642 case ClearCatchLocals:
4643 compileClearCatchLocals(node);
4644 break;
4645
4646 case DataViewGetFloat:
4647 case DataViewGetInt: {
4648 SpeculateCellOperand dataView(this, node->child1());
4649 GPRReg dataViewGPR = dataView.gpr();
4650 speculateDataViewObject(node->child1(), dataViewGPR);
4651
4652 SpeculateInt32Operand index(this, node->child2());
4653 GPRReg indexGPR = index.gpr();
4654
4655 GPRTemporary temp1(this);
4656 GPRReg t1 = temp1.gpr();
4657 GPRTemporary temp2(this);
4658 GPRReg t2 = temp2.gpr();
4659
4660 Optional<SpeculateBooleanOperand> isLittleEndianOperand;
4661 if (node->child3())
4662 isLittleEndianOperand.emplace(this, node->child3());
4663 GPRReg isLittleEndianGPR = isLittleEndianOperand ? isLittleEndianOperand->gpr() : InvalidGPRReg;
4664
4665 DataViewData data = node->dataViewData();
4666
4667 m_jit.zeroExtend32ToPtr(indexGPR, t2);
4668 if (data.byteSize > 1)
4669 m_jit.add64(TrustedImm32(data.byteSize - 1), t2);
4670 m_jit.load32(MacroAssembler::Address(dataViewGPR, JSArrayBufferView::offsetOfLength()), t1);
4671 speculationCheck(OutOfBounds, JSValueRegs(), node,
4672 m_jit.branch64(MacroAssembler::AboveOrEqual, t2, t1));
4673
4674 m_jit.loadPtr(JITCompiler::Address(dataViewGPR, JSArrayBufferView::offsetOfVector()), t2);
4675 cageTypedArrayStorage(t2);
4676
4677 m_jit.zeroExtend32ToPtr(indexGPR, t1);
4678 auto baseIndex = JITCompiler::BaseIndex(t2, t1, MacroAssembler::TimesOne);
4679
4680 if (node->op() == DataViewGetInt) {
4681 switch (data.byteSize) {
4682 case 1:
4683 if (data.isSigned)
4684 m_jit.load8SignedExtendTo32(baseIndex, t2);
4685 else
4686 m_jit.load8(baseIndex, t2);
4687 int32Result(t2, node);
4688 break;
4689 case 2: {
4690 auto emitLittleEndianLoad = [&] {
4691 if (data.isSigned)
4692 m_jit.load16SignedExtendTo32(baseIndex, t2);
4693 else
4694 m_jit.load16(baseIndex, t2);
4695 };
4696 auto emitBigEndianLoad = [&] {
4697 m_jit.load16(baseIndex, t2);
4698 m_jit.byteSwap16(t2);
4699 if (data.isSigned)
4700 m_jit.signExtend16To32(t2, t2);
4701 };
4702
4703 if (data.isLittleEndian == FalseTriState)
4704 emitBigEndianLoad();
4705 else if (data.isLittleEndian == TrueTriState)
4706 emitLittleEndianLoad();
4707 else {
4708 RELEASE_ASSERT(isLittleEndianGPR != InvalidGPRReg);
4709 auto isBigEndian = m_jit.branchTest32(MacroAssembler::Zero, isLittleEndianGPR, TrustedImm32(1));
4710 emitLittleEndianLoad();
4711 auto done = m_jit.jump();
4712 isBigEndian.link(&m_jit);
4713 emitBigEndianLoad();
4714 done.link(&m_jit);
4715 }
4716 int32Result(t2, node);
4717 break;
4718 }
4719 case 4: {
4720 m_jit.load32(baseIndex, t2);
4721
4722 if (data.isLittleEndian == FalseTriState)
4723 m_jit.byteSwap32(t2);
4724 else if (data.isLittleEndian == MixedTriState) {
4725 RELEASE_ASSERT(isLittleEndianGPR != InvalidGPRReg);
4726 auto isLittleEndian = m_jit.branchTest32(MacroAssembler::NonZero, isLittleEndianGPR, TrustedImm32(1));
4727 m_jit.byteSwap32(t2);
4728 isLittleEndian.link(&m_jit);
4729 }
4730
4731 if (data.isSigned)
4732 int32Result(t2, node);
4733 else
4734 strictInt52Result(t2, node);
4735 break;
4736 }
4737 default:
4738 RELEASE_ASSERT_NOT_REACHED();
4739 }
4740 } else {
4741 FPRTemporary result(this);
4742 FPRReg resultFPR = result.fpr();
4743
4744 switch (data.byteSize) {
4745 case 4: {
4746 auto emitLittleEndianCode = [&] {
4747 m_jit.loadFloat(baseIndex, resultFPR);
4748 m_jit.convertFloatToDouble(resultFPR, resultFPR);
4749 };
4750
4751 auto emitBigEndianCode = [&] {
4752 m_jit.load32(baseIndex, t2);
4753 m_jit.byteSwap32(t2);
4754 m_jit.move32ToFloat(t2, resultFPR);
4755 m_jit.convertFloatToDouble(resultFPR, resultFPR);
4756 };
4757
4758 if (data.isLittleEndian == TrueTriState)
4759 emitLittleEndianCode();
4760 else if (data.isLittleEndian == FalseTriState)
4761 emitBigEndianCode();
4762 else {
4763 RELEASE_ASSERT(isLittleEndianGPR != InvalidGPRReg);
4764 auto isBigEndian = m_jit.branchTest32(MacroAssembler::Zero, isLittleEndianGPR, TrustedImm32(1));
4765 emitLittleEndianCode();
4766 auto done = m_jit.jump();
4767 isBigEndian.link(&m_jit);
4768 emitBigEndianCode();
4769 done.link(&m_jit);
4770 }
4771
4772 break;
4773 }
4774 case 8: {
4775 auto emitLittleEndianCode = [&] {
4776 m_jit.loadDouble(baseIndex, resultFPR);
4777 };
4778
4779 auto emitBigEndianCode = [&] {
4780 m_jit.load64(baseIndex, t2);
4781 m_jit.byteSwap64(t2);
4782 m_jit.move64ToDouble(t2, resultFPR);
4783 };
4784
4785 if (data.isLittleEndian == TrueTriState)
4786 emitLittleEndianCode();
4787 else if (data.isLittleEndian == FalseTriState)
4788 emitBigEndianCode();
4789 else {
4790 RELEASE_ASSERT(isLittleEndianGPR != InvalidGPRReg);
4791 auto isBigEndian = m_jit.branchTest32(MacroAssembler::Zero, isLittleEndianGPR, TrustedImm32(1));
4792 emitLittleEndianCode();
4793 auto done = m_jit.jump();
4794 isBigEndian.link(&m_jit);
4795 emitBigEndianCode();
4796 done.link(&m_jit);
4797 }
4798
4799 break;
4800 }
4801 default:
4802 RELEASE_ASSERT_NOT_REACHED();
4803 }
4804
4805 doubleResult(resultFPR, node);
4806 }
4807
4808 break;
4809 }
4810
4811 case DataViewSet: {
4812 SpeculateCellOperand dataView(this, m_graph.varArgChild(node, 0));
4813 GPRReg dataViewGPR = dataView.gpr();
4814 speculateDataViewObject(m_graph.varArgChild(node, 0), dataViewGPR);
4815
4816 SpeculateInt32Operand index(this, m_graph.varArgChild(node, 1));
4817 GPRReg indexGPR = index.gpr();
4818
4819 Optional<SpeculateStrictInt52Operand> int52Value;
4820 Optional<SpeculateDoubleOperand> doubleValue;
4821 Optional<SpeculateInt32Operand> int32Value;
4822 Optional<FPRTemporary> fprTemporary;
4823 GPRReg valueGPR = InvalidGPRReg;
4824 FPRReg valueFPR = InvalidFPRReg;
4825 FPRReg tempFPR = InvalidFPRReg;
4826
4827 DataViewData data = node->dataViewData();
4828
4829 Edge& valueEdge = m_graph.varArgChild(node, 2);
4830 switch (valueEdge.useKind()) {
4831 case Int32Use:
4832 int32Value.emplace(this, valueEdge);
4833 valueGPR = int32Value->gpr();
4834 break;
4835 case DoubleRepUse:
4836 doubleValue.emplace(this, valueEdge);
4837 valueFPR = doubleValue->fpr();
4838 if (data.byteSize == 4) {
4839 fprTemporary.emplace(this);
4840 tempFPR = fprTemporary->fpr();
4841 }
4842 break;
4843 case Int52RepUse:
4844 int52Value.emplace(this, valueEdge);
4845 valueGPR = int52Value->gpr();
4846 break;
4847 default:
4848 RELEASE_ASSERT_NOT_REACHED();
4849 }
4850
4851 GPRTemporary temp1(this);
4852 GPRReg t1 = temp1.gpr();
4853 GPRTemporary temp2(this);
4854 GPRReg t2 = temp2.gpr();
4855 GPRTemporary temp3(this);
4856 GPRReg t3 = temp3.gpr();
4857
4858 Optional<SpeculateBooleanOperand> isLittleEndianOperand;
4859 if (m_graph.varArgChild(node, 3))
4860 isLittleEndianOperand.emplace(this, m_graph.varArgChild(node, 3));
4861 GPRReg isLittleEndianGPR = isLittleEndianOperand ? isLittleEndianOperand->gpr() : InvalidGPRReg;
4862
4863 m_jit.zeroExtend32ToPtr(indexGPR, t2);
4864 if (data.byteSize > 1)
4865 m_jit.add64(TrustedImm32(data.byteSize - 1), t2);
4866 m_jit.load32(MacroAssembler::Address(dataViewGPR, JSArrayBufferView::offsetOfLength()), t1);
4867 speculationCheck(OutOfBounds, JSValueRegs(), node,
4868 m_jit.branch64(MacroAssembler::AboveOrEqual, t2, t1));
4869
4870 m_jit.loadPtr(JITCompiler::Address(dataViewGPR, JSArrayBufferView::offsetOfVector()), t2);
4871 cageTypedArrayStorage(t2);
4872
4873 m_jit.zeroExtend32ToPtr(indexGPR, t1);
4874 auto baseIndex = JITCompiler::BaseIndex(t2, t1, MacroAssembler::TimesOne);
4875
4876 if (data.isFloatingPoint) {
4877 RELEASE_ASSERT(valueFPR != InvalidFPRReg);
4878 if (data.byteSize == 4) {
4879 RELEASE_ASSERT(tempFPR != InvalidFPRReg);
4880 m_jit.convertDoubleToFloat(valueFPR, tempFPR);
4881
4882 auto emitLittleEndianCode = [&] {
4883 m_jit.storeFloat(tempFPR, baseIndex);
4884 };
4885
4886 auto emitBigEndianCode = [&] {
4887 m_jit.moveFloatTo32(tempFPR, t3);
4888 m_jit.byteSwap32(t3);
4889 m_jit.store32(t3, baseIndex);
4890 };
4891
4892 if (data.isLittleEndian == FalseTriState)
4893 emitBigEndianCode();
4894 else if (data.isLittleEndian == TrueTriState)
4895 emitLittleEndianCode();
4896 else {
4897 RELEASE_ASSERT(isLittleEndianGPR != InvalidGPRReg);
4898 auto isBigEndian = m_jit.branchTest32(MacroAssembler::Zero, isLittleEndianGPR, TrustedImm32(1));
4899 emitLittleEndianCode();
4900 auto done = m_jit.jump();
4901 isBigEndian.link(&m_jit);
4902 emitBigEndianCode();
4903 done.link(&m_jit);
4904 }
4905 } else {
4906 RELEASE_ASSERT(data.byteSize == 8);
4907 RELEASE_ASSERT(valueFPR != InvalidFPRReg);
4908
4909 auto emitLittleEndianCode = [&] {
4910 m_jit.storeDouble(valueFPR, baseIndex);
4911 };
4912 auto emitBigEndianCode = [&] {
4913 m_jit.moveDoubleTo64(valueFPR, t3);
4914 m_jit.byteSwap64(t3);
4915 m_jit.store64(t3, baseIndex);
4916 };
4917
4918 if (data.isLittleEndian == FalseTriState)
4919 emitBigEndianCode();
4920 else if (data.isLittleEndian == TrueTriState)
4921 emitLittleEndianCode();
4922 else {
4923 RELEASE_ASSERT(isLittleEndianGPR != InvalidGPRReg);
4924 auto isBigEndian = m_jit.branchTest32(MacroAssembler::Zero, isLittleEndianGPR, TrustedImm32(1));
4925 emitLittleEndianCode();
4926 auto done = m_jit.jump();
4927 isBigEndian.link(&m_jit);
4928 emitBigEndianCode();
4929 done.link(&m_jit);
4930 }
4931 }
4932 } else {
4933 switch (data.byteSize) {
4934 case 1:
4935 RELEASE_ASSERT(valueEdge.useKind() == Int32Use);
4936 RELEASE_ASSERT(valueGPR != InvalidGPRReg);
4937 m_jit.store8(valueGPR, baseIndex);
4938 break;
4939 case 2: {
4940 RELEASE_ASSERT(valueEdge.useKind() == Int32Use);
4941 RELEASE_ASSERT(valueGPR != InvalidGPRReg);
4942
4943 auto emitLittleEndianCode = [&] {
4944 m_jit.store16(valueGPR, baseIndex);
4945 };
4946 auto emitBigEndianCode = [&] {
4947 m_jit.move(valueGPR, t3);
4948 m_jit.byteSwap16(t3);
4949 m_jit.store16(t3, baseIndex);
4950 };
4951
4952 if (data.isLittleEndian == FalseTriState)
4953 emitBigEndianCode();
4954 else if (data.isLittleEndian == TrueTriState)
4955 emitLittleEndianCode();
4956 else {
4957 RELEASE_ASSERT(isLittleEndianGPR != InvalidGPRReg);
4958 auto isBigEndian = m_jit.branchTest32(MacroAssembler::Zero, isLittleEndianGPR, TrustedImm32(1));
4959 emitLittleEndianCode();
4960 auto done = m_jit.jump();
4961 isBigEndian.link(&m_jit);
4962 emitBigEndianCode();
4963 done.link(&m_jit);
4964 }
4965 break;
4966 }
4967 case 4: {
4968 RELEASE_ASSERT(valueEdge.useKind() == Int32Use || valueEdge.useKind() == Int52RepUse);
4969
4970 auto emitLittleEndianCode = [&] {
4971 m_jit.store32(valueGPR, baseIndex);
4972 };
4973
4974 auto emitBigEndianCode = [&] {
4975 m_jit.zeroExtend32ToPtr(valueGPR, t3);
4976 m_jit.byteSwap32(t3);
4977 m_jit.store32(t3, baseIndex);
4978 };
4979
4980 if (data.isLittleEndian == FalseTriState)
4981 emitBigEndianCode();
4982 else if (data.isLittleEndian == TrueTriState)
4983 emitLittleEndianCode();
4984 else {
4985 RELEASE_ASSERT(isLittleEndianGPR != InvalidGPRReg);
4986 auto isBigEndian = m_jit.branchTest32(MacroAssembler::Zero, isLittleEndianGPR, TrustedImm32(1));
4987 emitLittleEndianCode();
4988 auto done = m_jit.jump();
4989 isBigEndian.link(&m_jit);
4990 emitBigEndianCode();
4991 done.link(&m_jit);
4992 }
4993
4994 break;
4995 }
4996 default:
4997 RELEASE_ASSERT_NOT_REACHED();
4998 }
4999 }
5000
5001 noResult(node);
5002 break;
5003 }
5004
5005#if ENABLE(FTL_JIT)
5006 case CheckTierUpInLoop: {
5007 MacroAssembler::Jump callTierUp = m_jit.branchAdd32(
5008 MacroAssembler::PositiveOrZero,
5009 TrustedImm32(Options::ftlTierUpCounterIncrementForLoop()),
5010 MacroAssembler::AbsoluteAddress(&m_jit.jitCode()->tierUpCounter.m_counter));
5011
5012 MacroAssembler::Label toNextOperation = m_jit.label();
5013
5014 Vector<SilentRegisterSavePlan> savePlans;
5015 silentSpillAllRegistersImpl(false, savePlans, InvalidGPRReg);
5016 unsigned bytecodeIndex = node->origin.semantic.bytecodeIndex();
5017
5018 addSlowPathGeneratorLambda([=]() {
5019 callTierUp.link(&m_jit);
5020
5021 silentSpill(savePlans);
5022 callOperation(triggerTierUpNowInLoop, TrustedImm32(bytecodeIndex));
5023 silentFill(savePlans);
5024
5025 m_jit.jump().linkTo(toNextOperation, &m_jit);
5026 });
5027 break;
5028 }
5029
5030 case CheckTierUpAtReturn: {
5031 MacroAssembler::Jump done = m_jit.branchAdd32(
5032 MacroAssembler::Signed,
5033 TrustedImm32(Options::ftlTierUpCounterIncrementForReturn()),
5034 MacroAssembler::AbsoluteAddress(&m_jit.jitCode()->tierUpCounter.m_counter));
5035
5036 silentSpillAllRegisters(InvalidGPRReg);
5037 callOperation(triggerTierUpNow);
5038 silentFillAllRegisters();
5039
5040 done.link(&m_jit);
5041 break;
5042 }
5043
5044 case CheckTierUpAndOSREnter: {
5045 ASSERT(!node->origin.semantic.inlineCallFrame());
5046
5047 GPRTemporary temp(this);
5048 GPRReg tempGPR = temp.gpr();
5049
5050 unsigned bytecodeIndex = node->origin.semantic.bytecodeIndex();
5051 auto triggerIterator = m_jit.jitCode()->tierUpEntryTriggers.find(bytecodeIndex);
5052 DFG_ASSERT(m_jit.graph(), node, triggerIterator != m_jit.jitCode()->tierUpEntryTriggers.end());
5053 JITCode::TriggerReason* forceEntryTrigger = &(m_jit.jitCode()->tierUpEntryTriggers.find(bytecodeIndex)->value);
5054 static_assert(!static_cast<uint8_t>(JITCode::TriggerReason::DontTrigger), "the JIT code assumes non-zero means 'enter'");
5055 static_assert(sizeof(JITCode::TriggerReason) == 1, "branchTest8 assumes this size");
5056
5057 MacroAssembler::Jump forceOSREntry = m_jit.branchTest8(MacroAssembler::NonZero, MacroAssembler::AbsoluteAddress(forceEntryTrigger));
5058 MacroAssembler::Jump overflowedCounter = m_jit.branchAdd32(
5059 MacroAssembler::PositiveOrZero,
5060 TrustedImm32(Options::ftlTierUpCounterIncrementForLoop()),
5061 MacroAssembler::AbsoluteAddress(&m_jit.jitCode()->tierUpCounter.m_counter));
5062 MacroAssembler::Label toNextOperation = m_jit.label();
5063
5064 Vector<SilentRegisterSavePlan> savePlans;
5065 silentSpillAllRegistersImpl(false, savePlans, tempGPR);
5066
5067 unsigned streamIndex = m_stream->size();
5068 m_jit.jitCode()->bytecodeIndexToStreamIndex.add(bytecodeIndex, streamIndex);
5069
5070 addSlowPathGeneratorLambda([=]() {
5071 forceOSREntry.link(&m_jit);
5072 overflowedCounter.link(&m_jit);
5073
5074 silentSpill(savePlans);
5075 callOperation(triggerOSREntryNow, tempGPR, TrustedImm32(bytecodeIndex));
5076
5077 if (savePlans.isEmpty())
5078 m_jit.branchTestPtr(MacroAssembler::Zero, tempGPR).linkTo(toNextOperation, &m_jit);
5079 else {
5080 MacroAssembler::Jump osrEnter = m_jit.branchTestPtr(MacroAssembler::NonZero, tempGPR);
5081 silentFill(savePlans);
5082 m_jit.jump().linkTo(toNextOperation, &m_jit);
5083 osrEnter.link(&m_jit);
5084 }
5085 m_jit.emitRestoreCalleeSaves();
5086 m_jit.jump(tempGPR, GPRInfo::callFrameRegister);
5087 });
5088 break;
5089 }
5090
5091#else // ENABLE(FTL_JIT)
5092 case CheckTierUpInLoop:
5093 case CheckTierUpAtReturn:
5094 case CheckTierUpAndOSREnter:
5095 DFG_CRASH(m_jit.graph(), node, "Unexpected tier-up node");
5096 break;
5097#endif // ENABLE(FTL_JIT)
5098
5099 case FilterCallLinkStatus:
5100 case FilterGetByIdStatus:
5101 case FilterPutByIdStatus:
5102 case FilterInByIdStatus:
5103 m_interpreter.filterICStatus(node);
5104 noResult(node);
5105 break;
5106
5107 case LastNodeType:
5108 case EntrySwitch:
5109 case InitializeEntrypointArguments:
5110 case Phi:
5111 case Upsilon:
5112 case ExtractOSREntryLocal:
5113 case CheckInBounds:
5114 case ArithIMul:
5115 case MultiGetByOffset:
5116 case MultiPutByOffset:
5117 case FiatInt52:
5118 case CheckBadCell:
5119 case BottomValue:
5120 case PhantomNewObject:
5121 case PhantomNewFunction:
5122 case PhantomNewGeneratorFunction:
5123 case PhantomNewAsyncFunction:
5124 case PhantomNewAsyncGeneratorFunction:
5125 case PhantomCreateActivation:
5126 case PhantomNewRegexp:
5127 case GetMyArgumentByVal:
5128 case GetMyArgumentByValOutOfBounds:
5129 case GetVectorLength:
5130 case PutHint:
5131 case CheckStructureImmediate:
5132 case MaterializeCreateActivation:
5133 case PutStack:
5134 case KillStack:
5135 case GetStack:
5136 case PhantomCreateRest:
5137 case PhantomSpread:
5138 case PhantomNewArrayWithSpread:
5139 case PhantomNewArrayBuffer:
5140 case IdentityWithProfile:
5141 case CPUIntrinsic:
5142 DFG_CRASH(m_jit.graph(), node, "Unexpected node");
5143 break;
5144 }
5145
5146 if (!m_compileOkay)
5147 return;
5148
5149 if (node->hasResult() && node->mustGenerate())
5150 use(node);
5151}
5152
5153void SpeculativeJIT::moveTrueTo(GPRReg gpr)
5154{
5155 m_jit.move(TrustedImm32(ValueTrue), gpr);
5156}
5157
5158void SpeculativeJIT::moveFalseTo(GPRReg gpr)
5159{
5160 m_jit.move(TrustedImm32(ValueFalse), gpr);
5161}
5162
5163void SpeculativeJIT::blessBoolean(GPRReg gpr)
5164{
5165 m_jit.or32(TrustedImm32(ValueFalse), gpr);
5166}
5167
5168void SpeculativeJIT::convertAnyInt(Edge valueEdge, GPRReg resultGPR)
5169{
5170 JSValueOperand value(this, valueEdge, ManualOperandSpeculation);
5171 GPRReg valueGPR = value.gpr();
5172
5173 JITCompiler::Jump notInt32 = m_jit.branchIfNotInt32(valueGPR);
5174
5175 m_jit.signExtend32ToPtr(valueGPR, resultGPR);
5176 JITCompiler::Jump done = m_jit.jump();
5177
5178 notInt32.link(&m_jit);
5179 silentSpillAllRegisters(resultGPR);
5180 callOperation(operationConvertBoxedDoubleToInt52, resultGPR, valueGPR);
5181 silentFillAllRegisters();
5182
5183 DFG_TYPE_CHECK(
5184 JSValueRegs(valueGPR), valueEdge, SpecInt32Only | SpecAnyIntAsDouble,
5185 m_jit.branch64(
5186 JITCompiler::Equal, resultGPR,
5187 JITCompiler::TrustedImm64(JSValue::notInt52)));
5188 done.link(&m_jit);
5189}
5190
5191void SpeculativeJIT::speculateAnyInt(Edge edge)
5192{
5193 if (!needsTypeCheck(edge, SpecInt32Only | SpecAnyIntAsDouble))
5194 return;
5195
5196 GPRTemporary temp(this);
5197 convertAnyInt(edge, temp.gpr());
5198}
5199
5200void SpeculativeJIT::speculateInt32(Edge edge, JSValueRegs regs)
5201{
5202 DFG_TYPE_CHECK(regs, edge, SpecInt32Only, m_jit.branchIfNotInt32(regs));
5203}
5204
5205void SpeculativeJIT::speculateDoubleRepAnyInt(Edge edge)
5206{
5207 if (!needsTypeCheck(edge, SpecAnyIntAsDouble))
5208 return;
5209
5210 SpeculateDoubleOperand value(this, edge);
5211 FPRReg valueFPR = value.fpr();
5212
5213 flushRegisters();
5214 GPRFlushedCallResult result(this);
5215 GPRReg resultGPR = result.gpr();
5216 callOperation(operationConvertDoubleToInt52, resultGPR, valueFPR);
5217
5218 DFG_TYPE_CHECK(
5219 JSValueRegs(), edge, SpecAnyIntAsDouble,
5220 m_jit.branch64(
5221 JITCompiler::Equal, resultGPR,
5222 JITCompiler::TrustedImm64(JSValue::notInt52)));
5223}
5224
5225void SpeculativeJIT::compileArithRandom(Node* node)
5226{
5227 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
5228 GPRTemporary temp1(this);
5229 GPRTemporary temp2(this);
5230 GPRTemporary temp3(this);
5231 FPRTemporary result(this);
5232 m_jit.emitRandomThunk(globalObject, temp1.gpr(), temp2.gpr(), temp3.gpr(), result.fpr());
5233 doubleResult(result.fpr(), node);
5234}
5235
5236#endif
5237
5238} } // namespace JSC::DFG
5239
5240#endif
5241