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 "BinarySwitch.h"
32#include "DFGAbstractInterpreterInlines.h"
33#include "DFGArrayifySlowPathGenerator.h"
34#include "DFGCallArrayAllocatorSlowPathGenerator.h"
35#include "DFGCallCreateDirectArgumentsSlowPathGenerator.h"
36#include "DFGCapabilities.h"
37#include "DFGMayExit.h"
38#include "DFGOSRExitFuzz.h"
39#include "DFGSaneStringGetByValSlowPathGenerator.h"
40#include "DFGSlowPathGenerator.h"
41#include "DFGSnippetParams.h"
42#include "DirectArguments.h"
43#include "DisallowMacroScratchRegisterUsage.h"
44#include "JITAddGenerator.h"
45#include "JITBitAndGenerator.h"
46#include "JITBitOrGenerator.h"
47#include "JITBitXorGenerator.h"
48#include "JITDivGenerator.h"
49#include "JITLeftShiftGenerator.h"
50#include "JITMulGenerator.h"
51#include "JITRightShiftGenerator.h"
52#include "JITSubGenerator.h"
53#include "JSAsyncFunction.h"
54#include "JSAsyncGeneratorFunction.h"
55#include "JSCInlines.h"
56#include "JSFixedArray.h"
57#include "JSGeneratorFunction.h"
58#include "JSImmutableButterfly.h"
59#include "JSLexicalEnvironment.h"
60#include "JSPropertyNameEnumerator.h"
61#include "LinkBuffer.h"
62#include "RegExpObject.h"
63#include "ScopedArguments.h"
64#include "ScratchRegisterAllocator.h"
65#include "SuperSampler.h"
66#include "TypeProfilerLog.h"
67#include "WeakMapImpl.h"
68#include <wtf/BitVector.h>
69#include <wtf/Box.h>
70#include <wtf/MathExtras.h>
71
72namespace JSC { namespace DFG {
73
74SpeculativeJIT::SpeculativeJIT(JITCompiler& jit)
75 : m_jit(jit)
76 , m_graph(m_jit.graph())
77 , m_currentNode(0)
78 , m_lastGeneratedNode(LastNodeType)
79 , m_indexInBlock(0)
80 , m_generationInfo(m_jit.graph().frameRegisterCount())
81 , m_compileOkay(true)
82 , m_state(m_jit.graph())
83 , m_interpreter(m_jit.graph(), m_state)
84 , m_stream(&jit.jitCode()->variableEventStream)
85 , m_minifiedGraph(&jit.jitCode()->minifiedDFG)
86{
87}
88
89SpeculativeJIT::~SpeculativeJIT()
90{
91}
92
93void SpeculativeJIT::emitAllocateRawObject(GPRReg resultGPR, RegisteredStructure structure, GPRReg storageGPR, unsigned numElements, unsigned vectorLength)
94{
95 ASSERT(!isCopyOnWrite(structure->indexingMode()));
96 IndexingType indexingType = structure->indexingType();
97 bool hasIndexingHeader = hasIndexedProperties(indexingType);
98
99 unsigned inlineCapacity = structure->inlineCapacity();
100 unsigned outOfLineCapacity = structure->outOfLineCapacity();
101
102 GPRTemporary scratch(this);
103 GPRTemporary scratch2(this);
104 GPRReg scratchGPR = scratch.gpr();
105 GPRReg scratch2GPR = scratch2.gpr();
106
107 ASSERT(vectorLength >= numElements);
108 vectorLength = Butterfly::optimalContiguousVectorLength(structure.get(), vectorLength);
109
110 JITCompiler::JumpList slowCases;
111
112 size_t size = 0;
113 if (hasIndexingHeader)
114 size += vectorLength * sizeof(JSValue) + sizeof(IndexingHeader);
115 size += outOfLineCapacity * sizeof(JSValue);
116
117 m_jit.move(TrustedImmPtr(nullptr), storageGPR);
118
119 if (size) {
120 if (Allocator allocator = m_jit.vm()->jsValueGigacageAuxiliarySpace.allocatorForNonVirtual(size, AllocatorForMode::AllocatorIfExists)) {
121 m_jit.emitAllocate(storageGPR, JITAllocator::constant(allocator), scratchGPR, scratch2GPR, slowCases);
122
123 m_jit.addPtr(
124 TrustedImm32(outOfLineCapacity * sizeof(JSValue) + sizeof(IndexingHeader)),
125 storageGPR);
126
127 if (hasIndexingHeader)
128 m_jit.store32(TrustedImm32(vectorLength), MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
129 } else
130 slowCases.append(m_jit.jump());
131 }
132
133 size_t allocationSize = JSFinalObject::allocationSize(inlineCapacity);
134 Allocator allocator = allocatorForNonVirtualConcurrently<JSFinalObject>(*m_jit.vm(), allocationSize, AllocatorForMode::AllocatorIfExists);
135 if (allocator) {
136 emitAllocateJSObject(resultGPR, JITAllocator::constant(allocator), scratchGPR, TrustedImmPtr(structure), storageGPR, scratch2GPR, slowCases);
137 m_jit.emitInitializeInlineStorage(resultGPR, structure->inlineCapacity());
138 } else
139 slowCases.append(m_jit.jump());
140
141 // I want a slow path that also loads out the storage pointer, and that's
142 // what this custom CallArrayAllocatorSlowPathGenerator gives me. It's a lot
143 // of work for a very small piece of functionality. :-/
144 addSlowPathGenerator(std::make_unique<CallArrayAllocatorSlowPathGenerator>(
145 slowCases, this, operationNewRawObject, resultGPR, storageGPR,
146 structure, vectorLength));
147
148 if (numElements < vectorLength) {
149#if USE(JSVALUE64)
150 if (hasDouble(structure->indexingType()))
151 m_jit.move(TrustedImm64(bitwise_cast<int64_t>(PNaN)), scratchGPR);
152 else
153 m_jit.move(TrustedImm64(JSValue::encode(JSValue())), scratchGPR);
154 for (unsigned i = numElements; i < vectorLength; ++i)
155 m_jit.store64(scratchGPR, MacroAssembler::Address(storageGPR, sizeof(double) * i));
156#else
157 EncodedValueDescriptor value;
158 if (hasDouble(structure->indexingType()))
159 value.asInt64 = JSValue::encode(JSValue(JSValue::EncodeAsDouble, PNaN));
160 else
161 value.asInt64 = JSValue::encode(JSValue());
162 for (unsigned i = numElements; i < vectorLength; ++i) {
163 m_jit.store32(TrustedImm32(value.asBits.tag), MacroAssembler::Address(storageGPR, sizeof(double) * i + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
164 m_jit.store32(TrustedImm32(value.asBits.payload), MacroAssembler::Address(storageGPR, sizeof(double) * i + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
165 }
166#endif
167 }
168
169 if (hasIndexingHeader)
170 m_jit.store32(TrustedImm32(numElements), MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
171
172 m_jit.emitInitializeOutOfLineStorage(storageGPR, structure->outOfLineCapacity());
173
174 m_jit.mutatorFence(*m_jit.vm());
175}
176
177void SpeculativeJIT::emitGetLength(InlineCallFrame* inlineCallFrame, GPRReg lengthGPR, bool includeThis)
178{
179 if (inlineCallFrame && !inlineCallFrame->isVarargs())
180 m_jit.move(TrustedImm32(inlineCallFrame->argumentCountIncludingThis - !includeThis), lengthGPR);
181 else {
182 VirtualRegister argumentCountRegister = m_jit.argumentCount(inlineCallFrame);
183 m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), lengthGPR);
184 if (!includeThis)
185 m_jit.sub32(TrustedImm32(1), lengthGPR);
186 }
187}
188
189void SpeculativeJIT::emitGetLength(CodeOrigin origin, GPRReg lengthGPR, bool includeThis)
190{
191 emitGetLength(origin.inlineCallFrame(), lengthGPR, includeThis);
192}
193
194void SpeculativeJIT::emitGetCallee(CodeOrigin origin, GPRReg calleeGPR)
195{
196 auto* inlineCallFrame = origin.inlineCallFrame();
197 if (inlineCallFrame) {
198 if (inlineCallFrame->isClosureCall) {
199 m_jit.loadPtr(
200 JITCompiler::addressFor(inlineCallFrame->calleeRecovery.virtualRegister()),
201 calleeGPR);
202 } else {
203 m_jit.move(
204 TrustedImmPtr::weakPointer(m_jit.graph(), inlineCallFrame->calleeRecovery.constant().asCell()),
205 calleeGPR);
206 }
207 } else
208 m_jit.loadPtr(JITCompiler::addressFor(CallFrameSlot::callee), calleeGPR);
209}
210
211void SpeculativeJIT::emitGetArgumentStart(CodeOrigin origin, GPRReg startGPR)
212{
213 m_jit.addPtr(
214 TrustedImm32(
215 JITCompiler::argumentsStart(origin).offset() * static_cast<int>(sizeof(Register))),
216 GPRInfo::callFrameRegister, startGPR);
217}
218
219MacroAssembler::Jump SpeculativeJIT::emitOSRExitFuzzCheck()
220{
221 if (!Options::useOSRExitFuzz()
222 || !canUseOSRExitFuzzing(m_jit.graph().baselineCodeBlockFor(m_origin.semantic))
223 || !doOSRExitFuzzing())
224 return MacroAssembler::Jump();
225
226 MacroAssembler::Jump result;
227
228 m_jit.pushToSave(GPRInfo::regT0);
229 m_jit.load32(&g_numberOfOSRExitFuzzChecks, GPRInfo::regT0);
230 m_jit.add32(TrustedImm32(1), GPRInfo::regT0);
231 m_jit.store32(GPRInfo::regT0, &g_numberOfOSRExitFuzzChecks);
232 unsigned atOrAfter = Options::fireOSRExitFuzzAtOrAfter();
233 unsigned at = Options::fireOSRExitFuzzAt();
234 if (at || atOrAfter) {
235 unsigned threshold;
236 MacroAssembler::RelationalCondition condition;
237 if (atOrAfter) {
238 threshold = atOrAfter;
239 condition = MacroAssembler::Below;
240 } else {
241 threshold = at;
242 condition = MacroAssembler::NotEqual;
243 }
244 MacroAssembler::Jump ok = m_jit.branch32(
245 condition, GPRInfo::regT0, MacroAssembler::TrustedImm32(threshold));
246 m_jit.popToRestore(GPRInfo::regT0);
247 result = m_jit.jump();
248 ok.link(&m_jit);
249 }
250 m_jit.popToRestore(GPRInfo::regT0);
251
252 return result;
253}
254
255void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail)
256{
257 if (!m_compileOkay)
258 return;
259 JITCompiler::Jump fuzzJump = emitOSRExitFuzzCheck();
260 if (fuzzJump.isSet()) {
261 JITCompiler::JumpList jumpsToFail;
262 jumpsToFail.append(fuzzJump);
263 jumpsToFail.append(jumpToFail);
264 m_jit.appendExitInfo(jumpsToFail);
265 } else
266 m_jit.appendExitInfo(jumpToFail);
267 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(m_currentNode, node), this, m_stream->size()));
268}
269
270void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, const MacroAssembler::JumpList& jumpsToFail)
271{
272 if (!m_compileOkay)
273 return;
274 JITCompiler::Jump fuzzJump = emitOSRExitFuzzCheck();
275 if (fuzzJump.isSet()) {
276 JITCompiler::JumpList myJumpsToFail;
277 myJumpsToFail.append(jumpsToFail);
278 myJumpsToFail.append(fuzzJump);
279 m_jit.appendExitInfo(myJumpsToFail);
280 } else
281 m_jit.appendExitInfo(jumpsToFail);
282 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(m_currentNode, node), this, m_stream->size()));
283}
284
285OSRExitJumpPlaceholder SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node)
286{
287 if (!m_compileOkay)
288 return OSRExitJumpPlaceholder();
289 unsigned index = m_jit.jitCode()->osrExit.size();
290 m_jit.appendExitInfo();
291 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(m_currentNode, node), this, m_stream->size()));
292 return OSRExitJumpPlaceholder(index);
293}
294
295OSRExitJumpPlaceholder SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse)
296{
297 return speculationCheck(kind, jsValueSource, nodeUse.node());
298}
299
300void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail)
301{
302 speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail);
303}
304
305void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, const MacroAssembler::JumpList& jumpsToFail)
306{
307 speculationCheck(kind, jsValueSource, nodeUse.node(), jumpsToFail);
308}
309
310void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
311{
312 if (!m_compileOkay)
313 return;
314 unsigned recoveryIndex = m_jit.jitCode()->appendSpeculationRecovery(recovery);
315 m_jit.appendExitInfo(jumpToFail);
316 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(m_currentNode, node), this, m_stream->size(), recoveryIndex));
317}
318
319void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
320{
321 speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail, recovery);
322}
323
324void SpeculativeJIT::emitInvalidationPoint(Node* node)
325{
326 if (!m_compileOkay)
327 return;
328 OSRExitCompilationInfo& info = m_jit.appendExitInfo(JITCompiler::JumpList());
329 m_jit.jitCode()->appendOSRExit(OSRExit(
330 UncountableInvalidation, JSValueSource(), MethodOfGettingAValueProfile(),
331 this, m_stream->size()));
332 info.m_replacementSource = m_jit.watchpointLabel();
333 ASSERT(info.m_replacementSource.isSet());
334 noResult(node);
335}
336
337void SpeculativeJIT::unreachable(Node* node)
338{
339 m_compileOkay = false;
340 m_jit.abortWithReason(DFGUnreachableNode, node->op());
341}
342
343void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, Node* node)
344{
345 if (!m_compileOkay)
346 return;
347 speculationCheck(kind, jsValueRegs, node, m_jit.jump());
348 m_compileOkay = false;
349 if (verboseCompilationEnabled())
350 dataLog("Bailing compilation.\n");
351}
352
353void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, Edge nodeUse)
354{
355 terminateSpeculativeExecution(kind, jsValueRegs, nodeUse.node());
356}
357
358void SpeculativeJIT::typeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail, ExitKind exitKind)
359{
360 ASSERT(needsTypeCheck(edge, typesPassedThrough));
361 m_interpreter.filter(edge, typesPassedThrough);
362 speculationCheck(exitKind, source, edge.node(), jumpToFail);
363}
364
365RegisterSet SpeculativeJIT::usedRegisters()
366{
367 RegisterSet result;
368
369 for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
370 GPRReg gpr = GPRInfo::toRegister(i);
371 if (m_gprs.isInUse(gpr))
372 result.set(gpr);
373 }
374 for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
375 FPRReg fpr = FPRInfo::toRegister(i);
376 if (m_fprs.isInUse(fpr))
377 result.set(fpr);
378 }
379
380 // FIXME: This is overly conservative. We could subtract out those callee-saves that we
381 // actually saved.
382 // https://bugs.webkit.org/show_bug.cgi?id=185686
383 result.merge(RegisterSet::stubUnavailableRegisters());
384
385 return result;
386}
387
388void SpeculativeJIT::addSlowPathGenerator(std::unique_ptr<SlowPathGenerator> slowPathGenerator)
389{
390 m_slowPathGenerators.append(WTFMove(slowPathGenerator));
391}
392
393void SpeculativeJIT::addSlowPathGeneratorLambda(Function<void()>&& lambda)
394{
395 m_slowPathLambdas.append(SlowPathLambda{ WTFMove(lambda), m_currentNode, static_cast<unsigned>(m_stream->size()) });
396}
397
398void SpeculativeJIT::runSlowPathGenerators(PCToCodeOriginMapBuilder& pcToCodeOriginMapBuilder)
399{
400 for (auto& slowPathGenerator : m_slowPathGenerators) {
401 pcToCodeOriginMapBuilder.appendItem(m_jit.labelIgnoringWatchpoints(), slowPathGenerator->origin().semantic);
402 slowPathGenerator->generate(this);
403 }
404 for (auto& slowPathLambda : m_slowPathLambdas) {
405 Node* currentNode = slowPathLambda.currentNode;
406 m_currentNode = currentNode;
407 m_outOfLineStreamIndex = slowPathLambda.streamIndex;
408 pcToCodeOriginMapBuilder.appendItem(m_jit.labelIgnoringWatchpoints(), currentNode->origin.semantic);
409 slowPathLambda.generator();
410 m_outOfLineStreamIndex = WTF::nullopt;
411 }
412}
413
414void SpeculativeJIT::clearGenerationInfo()
415{
416 for (unsigned i = 0; i < m_generationInfo.size(); ++i)
417 m_generationInfo[i] = GenerationInfo();
418 m_gprs = RegisterBank<GPRInfo>();
419 m_fprs = RegisterBank<FPRInfo>();
420}
421
422SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForGPR(VirtualRegister spillMe, GPRReg source)
423{
424 GenerationInfo& info = generationInfoFromVirtualRegister(spillMe);
425 Node* node = info.node();
426 DataFormat registerFormat = info.registerFormat();
427 ASSERT(registerFormat != DataFormatNone);
428 ASSERT(registerFormat != DataFormatDouble);
429
430 SilentSpillAction spillAction;
431 SilentFillAction fillAction;
432
433 if (!info.needsSpill())
434 spillAction = DoNothingForSpill;
435 else {
436#if USE(JSVALUE64)
437 ASSERT(info.gpr() == source);
438 if (registerFormat == DataFormatInt32)
439 spillAction = Store32Payload;
440 else if (registerFormat == DataFormatCell || registerFormat == DataFormatStorage)
441 spillAction = StorePtr;
442 else if (registerFormat == DataFormatInt52 || registerFormat == DataFormatStrictInt52)
443 spillAction = Store64;
444 else {
445 ASSERT(registerFormat & DataFormatJS);
446 spillAction = Store64;
447 }
448#elif USE(JSVALUE32_64)
449 if (registerFormat & DataFormatJS) {
450 ASSERT(info.tagGPR() == source || info.payloadGPR() == source);
451 spillAction = source == info.tagGPR() ? Store32Tag : Store32Payload;
452 } else {
453 ASSERT(info.gpr() == source);
454 spillAction = Store32Payload;
455 }
456#endif
457 }
458
459 if (registerFormat == DataFormatInt32) {
460 ASSERT(info.gpr() == source);
461 ASSERT(isJSInt32(info.registerFormat()));
462 if (node->hasConstant()) {
463 ASSERT(node->isInt32Constant());
464 fillAction = SetInt32Constant;
465 } else
466 fillAction = Load32Payload;
467 } else if (registerFormat == DataFormatBoolean) {
468#if USE(JSVALUE64)
469 RELEASE_ASSERT_NOT_REACHED();
470#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
471 fillAction = DoNothingForFill;
472#endif
473#elif USE(JSVALUE32_64)
474 ASSERT(info.gpr() == source);
475 if (node->hasConstant()) {
476 ASSERT(node->isBooleanConstant());
477 fillAction = SetBooleanConstant;
478 } else
479 fillAction = Load32Payload;
480#endif
481 } else if (registerFormat == DataFormatCell) {
482 ASSERT(info.gpr() == source);
483 if (node->hasConstant()) {
484 DFG_ASSERT(m_jit.graph(), m_currentNode, node->isCellConstant());
485 node->asCell(); // To get the assertion.
486 fillAction = SetCellConstant;
487 } else {
488#if USE(JSVALUE64)
489 fillAction = LoadPtr;
490#else
491 fillAction = Load32Payload;
492#endif
493 }
494 } else if (registerFormat == DataFormatStorage) {
495 ASSERT(info.gpr() == source);
496 fillAction = LoadPtr;
497 } else if (registerFormat == DataFormatInt52) {
498 if (node->hasConstant())
499 fillAction = SetInt52Constant;
500 else if (info.spillFormat() == DataFormatInt52)
501 fillAction = Load64;
502 else if (info.spillFormat() == DataFormatStrictInt52)
503 fillAction = Load64ShiftInt52Left;
504 else if (info.spillFormat() == DataFormatNone)
505 fillAction = Load64;
506 else {
507 RELEASE_ASSERT_NOT_REACHED();
508#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
509 fillAction = Load64; // Make GCC happy.
510#endif
511 }
512 } else if (registerFormat == DataFormatStrictInt52) {
513 if (node->hasConstant())
514 fillAction = SetStrictInt52Constant;
515 else if (info.spillFormat() == DataFormatInt52)
516 fillAction = Load64ShiftInt52Right;
517 else if (info.spillFormat() == DataFormatStrictInt52)
518 fillAction = Load64;
519 else if (info.spillFormat() == DataFormatNone)
520 fillAction = Load64;
521 else {
522 RELEASE_ASSERT_NOT_REACHED();
523#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
524 fillAction = Load64; // Make GCC happy.
525#endif
526 }
527 } else {
528 ASSERT(registerFormat & DataFormatJS);
529#if USE(JSVALUE64)
530 ASSERT(info.gpr() == source);
531 if (node->hasConstant()) {
532 if (node->isCellConstant())
533 fillAction = SetTrustedJSConstant;
534 else
535 fillAction = SetJSConstant;
536 } else if (info.spillFormat() == DataFormatInt32) {
537 ASSERT(registerFormat == DataFormatJSInt32);
538 fillAction = Load32PayloadBoxInt;
539 } else
540 fillAction = Load64;
541#else
542 ASSERT(info.tagGPR() == source || info.payloadGPR() == source);
543 if (node->hasConstant())
544 fillAction = info.tagGPR() == source ? SetJSConstantTag : SetJSConstantPayload;
545 else if (info.payloadGPR() == source)
546 fillAction = Load32Payload;
547 else { // Fill the Tag
548 switch (info.spillFormat()) {
549 case DataFormatInt32:
550 ASSERT(registerFormat == DataFormatJSInt32);
551 fillAction = SetInt32Tag;
552 break;
553 case DataFormatCell:
554 ASSERT(registerFormat == DataFormatJSCell);
555 fillAction = SetCellTag;
556 break;
557 case DataFormatBoolean:
558 ASSERT(registerFormat == DataFormatJSBoolean);
559 fillAction = SetBooleanTag;
560 break;
561 default:
562 fillAction = Load32Tag;
563 break;
564 }
565 }
566#endif
567 }
568
569 return SilentRegisterSavePlan(spillAction, fillAction, node, source);
570}
571
572SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForFPR(VirtualRegister spillMe, FPRReg source)
573{
574 GenerationInfo& info = generationInfoFromVirtualRegister(spillMe);
575 Node* node = info.node();
576 ASSERT(info.registerFormat() == DataFormatDouble);
577
578 SilentSpillAction spillAction;
579 SilentFillAction fillAction;
580
581 if (!info.needsSpill())
582 spillAction = DoNothingForSpill;
583 else {
584 ASSERT(!node->hasConstant());
585 ASSERT(info.spillFormat() == DataFormatNone);
586 ASSERT(info.fpr() == source);
587 spillAction = StoreDouble;
588 }
589
590#if USE(JSVALUE64)
591 if (node->hasConstant()) {
592 node->asNumber(); // To get the assertion.
593 fillAction = SetDoubleConstant;
594 } else {
595 ASSERT(info.spillFormat() == DataFormatNone || info.spillFormat() == DataFormatDouble);
596 fillAction = LoadDouble;
597 }
598#elif USE(JSVALUE32_64)
599 ASSERT(info.registerFormat() == DataFormatDouble);
600 if (node->hasConstant()) {
601 node->asNumber(); // To get the assertion.
602 fillAction = SetDoubleConstant;
603 } else
604 fillAction = LoadDouble;
605#endif
606
607 return SilentRegisterSavePlan(spillAction, fillAction, node, source);
608}
609
610void SpeculativeJIT::silentSpill(const SilentRegisterSavePlan& plan)
611{
612 switch (plan.spillAction()) {
613 case DoNothingForSpill:
614 break;
615 case Store32Tag:
616 m_jit.store32(plan.gpr(), JITCompiler::tagFor(plan.node()->virtualRegister()));
617 break;
618 case Store32Payload:
619 m_jit.store32(plan.gpr(), JITCompiler::payloadFor(plan.node()->virtualRegister()));
620 break;
621 case StorePtr:
622 m_jit.storePtr(plan.gpr(), JITCompiler::addressFor(plan.node()->virtualRegister()));
623 break;
624#if USE(JSVALUE64)
625 case Store64:
626 m_jit.store64(plan.gpr(), JITCompiler::addressFor(plan.node()->virtualRegister()));
627 break;
628#endif
629 case StoreDouble:
630 m_jit.storeDouble(plan.fpr(), JITCompiler::addressFor(plan.node()->virtualRegister()));
631 break;
632 default:
633 RELEASE_ASSERT_NOT_REACHED();
634 }
635}
636
637void SpeculativeJIT::silentFill(const SilentRegisterSavePlan& plan)
638{
639 switch (plan.fillAction()) {
640 case DoNothingForFill:
641 break;
642 case SetInt32Constant:
643 m_jit.move(Imm32(plan.node()->asInt32()), plan.gpr());
644 break;
645#if USE(JSVALUE64)
646 case SetInt52Constant:
647 m_jit.move(Imm64(plan.node()->asAnyInt() << JSValue::int52ShiftAmount), plan.gpr());
648 break;
649 case SetStrictInt52Constant:
650 m_jit.move(Imm64(plan.node()->asAnyInt()), plan.gpr());
651 break;
652#endif // USE(JSVALUE64)
653 case SetBooleanConstant:
654 m_jit.move(TrustedImm32(plan.node()->asBoolean()), plan.gpr());
655 break;
656 case SetCellConstant:
657 ASSERT(plan.node()->constant()->value().isCell());
658 m_jit.move(TrustedImmPtr(plan.node()->constant()), plan.gpr());
659 break;
660#if USE(JSVALUE64)
661 case SetTrustedJSConstant:
662 m_jit.move(valueOfJSConstantAsImm64(plan.node()).asTrustedImm64(), plan.gpr());
663 break;
664 case SetJSConstant:
665 m_jit.move(valueOfJSConstantAsImm64(plan.node()), plan.gpr());
666 break;
667 case SetDoubleConstant:
668 m_jit.moveDouble(Imm64(reinterpretDoubleToInt64(plan.node()->asNumber())), plan.fpr());
669 break;
670 case Load32PayloadBoxInt:
671 m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr());
672 m_jit.or64(GPRInfo::tagTypeNumberRegister, plan.gpr());
673 break;
674 case Load32PayloadConvertToInt52:
675 m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr());
676 m_jit.signExtend32ToPtr(plan.gpr(), plan.gpr());
677 m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), plan.gpr());
678 break;
679 case Load32PayloadSignExtend:
680 m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr());
681 m_jit.signExtend32ToPtr(plan.gpr(), plan.gpr());
682 break;
683#else
684 case SetJSConstantTag:
685 m_jit.move(Imm32(plan.node()->asJSValue().tag()), plan.gpr());
686 break;
687 case SetJSConstantPayload:
688 m_jit.move(Imm32(plan.node()->asJSValue().payload()), plan.gpr());
689 break;
690 case SetInt32Tag:
691 m_jit.move(TrustedImm32(JSValue::Int32Tag), plan.gpr());
692 break;
693 case SetCellTag:
694 m_jit.move(TrustedImm32(JSValue::CellTag), plan.gpr());
695 break;
696 case SetBooleanTag:
697 m_jit.move(TrustedImm32(JSValue::BooleanTag), plan.gpr());
698 break;
699 case SetDoubleConstant:
700 m_jit.loadDouble(TrustedImmPtr(m_jit.addressOfDoubleConstant(plan.node())), plan.fpr());
701 break;
702#endif
703 case Load32Tag:
704 m_jit.load32(JITCompiler::tagFor(plan.node()->virtualRegister()), plan.gpr());
705 break;
706 case Load32Payload:
707 m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr());
708 break;
709 case LoadPtr:
710 m_jit.loadPtr(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr());
711 break;
712#if USE(JSVALUE64)
713 case Load64:
714 m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr());
715 break;
716 case Load64ShiftInt52Right:
717 m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr());
718 m_jit.rshift64(TrustedImm32(JSValue::int52ShiftAmount), plan.gpr());
719 break;
720 case Load64ShiftInt52Left:
721 m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr());
722 m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), plan.gpr());
723 break;
724#endif
725 case LoadDouble:
726 m_jit.loadDouble(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.fpr());
727 break;
728 default:
729 RELEASE_ASSERT_NOT_REACHED();
730 }
731}
732
733JITCompiler::JumpList SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode)
734{
735 JITCompiler::JumpList result;
736
737 IndexingType indexingModeMask = IsArray | IndexingShapeMask;
738 if (arrayMode.action() == Array::Write)
739 indexingModeMask |= CopyOnWrite;
740
741 switch (arrayMode.type()) {
742 case Array::Int32:
743 case Array::Double:
744 case Array::Contiguous:
745 case Array::Undecided:
746 case Array::ArrayStorage: {
747 IndexingType shape = arrayMode.shapeMask();
748 switch (arrayMode.arrayClass()) {
749 case Array::OriginalArray:
750 case Array::OriginalCopyOnWriteArray:
751 RELEASE_ASSERT_NOT_REACHED();
752 return result;
753
754 case Array::Array:
755 m_jit.and32(TrustedImm32(indexingModeMask), tempGPR);
756 result.append(m_jit.branch32(
757 MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | shape)));
758 return result;
759
760 case Array::NonArray:
761 case Array::OriginalNonArray:
762 m_jit.and32(TrustedImm32(indexingModeMask), tempGPR);
763 result.append(m_jit.branch32(
764 MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape)));
765 return result;
766
767 case Array::PossiblyArray:
768 m_jit.and32(TrustedImm32(indexingModeMask & ~IsArray), tempGPR);
769 result.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape)));
770 return result;
771 }
772
773 RELEASE_ASSERT_NOT_REACHED();
774 return result;
775 }
776
777 case Array::SlowPutArrayStorage: {
778 ASSERT(!arrayMode.isJSArrayWithOriginalStructure());
779
780 switch (arrayMode.arrayClass()) {
781 case Array::OriginalArray:
782 case Array::OriginalCopyOnWriteArray:
783 RELEASE_ASSERT_NOT_REACHED();
784 return result;
785
786 case Array::Array:
787 result.append(
788 m_jit.branchTest32(
789 MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(IsArray)));
790 break;
791
792 case Array::NonArray:
793 case Array::OriginalNonArray:
794 result.append(
795 m_jit.branchTest32(
796 MacroAssembler::NonZero, tempGPR, MacroAssembler::TrustedImm32(IsArray)));
797 break;
798
799 case Array::PossiblyArray:
800 break;
801 }
802
803 m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR);
804 m_jit.sub32(TrustedImm32(ArrayStorageShape), tempGPR);
805 result.append(
806 m_jit.branch32(
807 MacroAssembler::Above, tempGPR,
808 TrustedImm32(SlowPutArrayStorageShape - ArrayStorageShape)));
809 return result;
810 }
811 default:
812 CRASH();
813 break;
814 }
815
816 return result;
817}
818
819void SpeculativeJIT::checkArray(Node* node)
820{
821 ASSERT(node->arrayMode().isSpecific());
822 ASSERT(!node->arrayMode().doesConversion());
823
824 SpeculateCellOperand base(this, node->child1());
825 GPRReg baseReg = base.gpr();
826
827 if (node->arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))) {
828 noResult(m_currentNode);
829 return;
830 }
831
832 switch (node->arrayMode().type()) {
833 case Array::AnyTypedArray:
834 case Array::String:
835 RELEASE_ASSERT_NOT_REACHED(); // Should have been a Phantom(String:)
836 return;
837 case Array::Int32:
838 case Array::Double:
839 case Array::Contiguous:
840 case Array::Undecided:
841 case Array::ArrayStorage:
842 case Array::SlowPutArrayStorage: {
843 GPRTemporary temp(this);
844 GPRReg tempGPR = temp.gpr();
845 m_jit.load8(MacroAssembler::Address(baseReg, JSCell::indexingTypeAndMiscOffset()), tempGPR);
846 speculationCheck(
847 BadIndexingType, JSValueSource::unboxedCell(baseReg), 0,
848 jumpSlowForUnwantedArrayMode(tempGPR, node->arrayMode()));
849
850 noResult(m_currentNode);
851 return;
852 }
853 case Array::DirectArguments:
854 speculateCellTypeWithoutTypeFiltering(node->child1(), baseReg, DirectArgumentsType);
855 noResult(m_currentNode);
856 return;
857 case Array::ScopedArguments:
858 speculateCellTypeWithoutTypeFiltering(node->child1(), baseReg, ScopedArgumentsType);
859 noResult(m_currentNode);
860 return;
861 default:
862 speculateCellTypeWithoutTypeFiltering(
863 node->child1(), baseReg,
864 typeForTypedArrayType(node->arrayMode().typedArrayType()));
865 noResult(m_currentNode);
866 return;
867 }
868}
869
870void SpeculativeJIT::arrayify(Node* node, GPRReg baseReg, GPRReg propertyReg)
871{
872 ASSERT(node->arrayMode().doesConversion());
873
874 GPRTemporary temp(this);
875 GPRTemporary structure;
876 GPRReg tempGPR = temp.gpr();
877 GPRReg structureGPR = InvalidGPRReg;
878
879 if (node->op() != ArrayifyToStructure) {
880 GPRTemporary realStructure(this);
881 structure.adopt(realStructure);
882 structureGPR = structure.gpr();
883 }
884
885 // We can skip all that comes next if we already have array storage.
886 MacroAssembler::JumpList slowPath;
887
888 if (node->op() == ArrayifyToStructure) {
889 ASSERT(!isCopyOnWrite(node->structure()->indexingMode()));
890 ASSERT((node->structure()->indexingType() & IndexingShapeMask) == node->arrayMode().shapeMask());
891 slowPath.append(m_jit.branchWeakStructure(
892 JITCompiler::NotEqual,
893 JITCompiler::Address(baseReg, JSCell::structureIDOffset()),
894 node->structure()));
895 } else {
896 m_jit.load8(
897 MacroAssembler::Address(baseReg, JSCell::indexingTypeAndMiscOffset()), tempGPR);
898
899 slowPath.append(jumpSlowForUnwantedArrayMode(tempGPR, node->arrayMode()));
900 }
901
902 addSlowPathGenerator(std::make_unique<ArrayifySlowPathGenerator>(
903 slowPath, this, node, baseReg, propertyReg, tempGPR, structureGPR));
904
905 noResult(m_currentNode);
906}
907
908void SpeculativeJIT::arrayify(Node* node)
909{
910 ASSERT(node->arrayMode().isSpecific());
911
912 SpeculateCellOperand base(this, node->child1());
913
914 if (!node->child2()) {
915 arrayify(node, base.gpr(), InvalidGPRReg);
916 return;
917 }
918
919 SpeculateInt32Operand property(this, node->child2());
920
921 arrayify(node, base.gpr(), property.gpr());
922}
923
924GPRReg SpeculativeJIT::fillStorage(Edge edge)
925{
926 VirtualRegister virtualRegister = edge->virtualRegister();
927 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
928
929 switch (info.registerFormat()) {
930 case DataFormatNone: {
931 if (info.spillFormat() == DataFormatStorage) {
932 GPRReg gpr = allocate();
933 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
934 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
935 info.fillStorage(*m_stream, gpr);
936 return gpr;
937 }
938
939 // Must be a cell; fill it as a cell and then return the pointer.
940 return fillSpeculateCell(edge);
941 }
942
943 case DataFormatStorage: {
944 GPRReg gpr = info.gpr();
945 m_gprs.lock(gpr);
946 return gpr;
947 }
948
949 default:
950 return fillSpeculateCell(edge);
951 }
952}
953
954void SpeculativeJIT::useChildren(Node* node)
955{
956 if (node->flags() & NodeHasVarArgs) {
957 for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++) {
958 if (!!m_jit.graph().m_varArgChildren[childIdx])
959 use(m_jit.graph().m_varArgChildren[childIdx]);
960 }
961 } else {
962 Edge child1 = node->child1();
963 if (!child1) {
964 ASSERT(!node->child2() && !node->child3());
965 return;
966 }
967 use(child1);
968
969 Edge child2 = node->child2();
970 if (!child2) {
971 ASSERT(!node->child3());
972 return;
973 }
974 use(child2);
975
976 Edge child3 = node->child3();
977 if (!child3)
978 return;
979 use(child3);
980 }
981}
982
983void SpeculativeJIT::compileGetById(Node* node, AccessType accessType)
984{
985 ASSERT(accessType == AccessType::Get || accessType == AccessType::GetDirect || accessType == AccessType::TryGet);
986
987 switch (node->child1().useKind()) {
988 case CellUse: {
989 SpeculateCellOperand base(this, node->child1());
990 JSValueRegsTemporary result(this, Reuse, base);
991
992 JSValueRegs baseRegs = JSValueRegs::payloadOnly(base.gpr());
993 JSValueRegs resultRegs = result.regs();
994
995 base.use();
996
997 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), NeedToSpill, accessType);
998
999 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
1000 break;
1001 }
1002
1003 case UntypedUse: {
1004 JSValueOperand base(this, node->child1());
1005 JSValueRegsTemporary result(this, Reuse, base);
1006
1007 JSValueRegs baseRegs = base.jsValueRegs();
1008 JSValueRegs resultRegs = result.regs();
1009
1010 base.use();
1011
1012 JITCompiler::Jump notCell = m_jit.branchIfNotCell(baseRegs);
1013
1014 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, NeedToSpill, accessType);
1015
1016 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
1017 break;
1018 }
1019
1020 default:
1021 DFG_CRASH(m_jit.graph(), node, "Bad use kind");
1022 break;
1023 }
1024}
1025
1026void SpeculativeJIT::compileGetByIdFlush(Node* node, AccessType accessType)
1027{
1028 switch (node->child1().useKind()) {
1029 case CellUse: {
1030 SpeculateCellOperand base(this, node->child1());
1031 JSValueRegs baseRegs = JSValueRegs::payloadOnly(base.gpr());
1032
1033 JSValueRegsFlushedCallResult result(this);
1034 JSValueRegs resultRegs = result.regs();
1035
1036 base.use();
1037
1038 flushRegisters();
1039
1040 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), DontSpill, accessType);
1041
1042 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
1043 break;
1044 }
1045
1046 case UntypedUse: {
1047 JSValueOperand base(this, node->child1());
1048 JSValueRegs baseRegs = base.jsValueRegs();
1049
1050 JSValueRegsFlushedCallResult result(this);
1051 JSValueRegs resultRegs = result.regs();
1052
1053 base.use();
1054
1055 flushRegisters();
1056
1057 JITCompiler::Jump notCell = m_jit.branchIfNotCell(baseRegs);
1058
1059 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, DontSpill, accessType);
1060
1061 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
1062 break;
1063 }
1064
1065 default:
1066 DFG_CRASH(m_jit.graph(), node, "Bad use kind");
1067 break;
1068 }
1069}
1070
1071void SpeculativeJIT::compileInById(Node* node)
1072{
1073 SpeculateCellOperand base(this, node->child1());
1074 JSValueRegsTemporary result(this, Reuse, base, PayloadWord);
1075
1076 GPRReg baseGPR = base.gpr();
1077 JSValueRegs resultRegs = result.regs();
1078
1079 base.use();
1080
1081 CodeOrigin codeOrigin = node->origin.semantic;
1082 CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
1083 RegisterSet usedRegisters = this->usedRegisters();
1084 JITInByIdGenerator gen(
1085 m_jit.codeBlock(), codeOrigin, callSite, usedRegisters, identifierUID(node->identifierNumber()),
1086 JSValueRegs::payloadOnly(baseGPR), resultRegs);
1087 gen.generateFastPath(m_jit);
1088
1089 auto slowPath = slowPathCall(
1090 gen.slowPathJump(), this, operationInByIdOptimize,
1091 NeedToSpill, ExceptionCheckRequirement::CheckNeeded,
1092 resultRegs, gen.stubInfo(), CCallHelpers::CellValue(baseGPR), identifierUID(node->identifierNumber()));
1093
1094 m_jit.addInById(gen, slowPath.get());
1095 addSlowPathGenerator(WTFMove(slowPath));
1096
1097 blessedBooleanResult(resultRegs.payloadGPR(), node, UseChildrenCalledExplicitly);
1098}
1099
1100void SpeculativeJIT::compileInByVal(Node* node)
1101{
1102 SpeculateCellOperand base(this, node->child1());
1103 JSValueOperand key(this, node->child2());
1104
1105 GPRReg baseGPR = base.gpr();
1106 JSValueRegs regs = key.jsValueRegs();
1107
1108 base.use();
1109 key.use();
1110
1111 flushRegisters();
1112 JSValueRegsFlushedCallResult result(this);
1113 JSValueRegs resultRegs = result.regs();
1114 callOperation(operationInByVal, resultRegs, baseGPR, regs);
1115 m_jit.exceptionCheck();
1116 blessedBooleanResult(resultRegs.payloadGPR(), node, UseChildrenCalledExplicitly);
1117}
1118
1119void SpeculativeJIT::compileDeleteById(Node* node)
1120{
1121 JSValueOperand value(this, node->child1());
1122 GPRFlushedCallResult result(this);
1123
1124 JSValueRegs valueRegs = value.jsValueRegs();
1125 GPRReg resultGPR = result.gpr();
1126
1127 value.use();
1128
1129 flushRegisters();
1130 callOperation(operationDeleteById, resultGPR, valueRegs, identifierUID(node->identifierNumber()));
1131 m_jit.exceptionCheck();
1132
1133 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
1134}
1135
1136void SpeculativeJIT::compileDeleteByVal(Node* node)
1137{
1138 JSValueOperand base(this, node->child1());
1139 JSValueOperand key(this, node->child2());
1140 GPRFlushedCallResult result(this);
1141
1142 JSValueRegs baseRegs = base.jsValueRegs();
1143 JSValueRegs keyRegs = key.jsValueRegs();
1144 GPRReg resultGPR = result.gpr();
1145
1146 base.use();
1147 key.use();
1148
1149 flushRegisters();
1150 callOperation(operationDeleteByVal, resultGPR, baseRegs, keyRegs);
1151 m_jit.exceptionCheck();
1152
1153 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
1154}
1155
1156void SpeculativeJIT::compilePushWithScope(Node* node)
1157{
1158 SpeculateCellOperand currentScope(this, node->child1());
1159 GPRReg currentScopeGPR = currentScope.gpr();
1160
1161 GPRFlushedCallResult result(this);
1162 GPRReg resultGPR = result.gpr();
1163
1164 auto objectEdge = node->child2();
1165 if (objectEdge.useKind() == ObjectUse) {
1166 SpeculateCellOperand object(this, objectEdge);
1167 GPRReg objectGPR = object.gpr();
1168 speculateObject(objectEdge, objectGPR);
1169
1170 flushRegisters();
1171 callOperation(operationPushWithScopeObject, resultGPR, currentScopeGPR, objectGPR);
1172 // No exception check here as we did not have to call toObject().
1173 } else {
1174 ASSERT(objectEdge.useKind() == UntypedUse);
1175 JSValueOperand object(this, objectEdge);
1176 JSValueRegs objectRegs = object.jsValueRegs();
1177
1178 flushRegisters();
1179 callOperation(operationPushWithScope, resultGPR, currentScopeGPR, objectRegs);
1180 m_jit.exceptionCheck();
1181 }
1182
1183 cellResult(resultGPR, node);
1184}
1185
1186bool SpeculativeJIT::nonSpeculativeStrictEq(Node* node, bool invert)
1187{
1188 unsigned branchIndexInBlock = detectPeepHoleBranch();
1189 if (branchIndexInBlock != UINT_MAX) {
1190 Node* branchNode = m_block->at(branchIndexInBlock);
1191
1192 ASSERT(node->adjustedRefCount() == 1);
1193
1194 nonSpeculativePeepholeStrictEq(node, branchNode, invert);
1195
1196 m_indexInBlock = branchIndexInBlock;
1197 m_currentNode = branchNode;
1198
1199 return true;
1200 }
1201
1202 nonSpeculativeNonPeepholeStrictEq(node, invert);
1203
1204 return false;
1205}
1206
1207static const char* dataFormatString(DataFormat format)
1208{
1209 // These values correspond to the DataFormat enum.
1210 const char* strings[] = {
1211 "[ ]",
1212 "[ i]",
1213 "[ d]",
1214 "[ c]",
1215 "Err!",
1216 "Err!",
1217 "Err!",
1218 "Err!",
1219 "[J ]",
1220 "[Ji]",
1221 "[Jd]",
1222 "[Jc]",
1223 "Err!",
1224 "Err!",
1225 "Err!",
1226 "Err!",
1227 };
1228 return strings[format];
1229}
1230
1231void SpeculativeJIT::dump(const char* label)
1232{
1233 if (label)
1234 dataLogF("<%s>\n", label);
1235
1236 dataLogF(" gprs:\n");
1237 m_gprs.dump();
1238 dataLogF(" fprs:\n");
1239 m_fprs.dump();
1240 dataLogF(" VirtualRegisters:\n");
1241 for (unsigned i = 0; i < m_generationInfo.size(); ++i) {
1242 GenerationInfo& info = m_generationInfo[i];
1243 if (info.alive())
1244 dataLogF(" % 3d:%s%s", i, dataFormatString(info.registerFormat()), dataFormatString(info.spillFormat()));
1245 else
1246 dataLogF(" % 3d:[__][__]", i);
1247 if (info.registerFormat() == DataFormatDouble)
1248 dataLogF(":fpr%d\n", info.fpr());
1249 else if (info.registerFormat() != DataFormatNone
1250#if USE(JSVALUE32_64)
1251 && !(info.registerFormat() & DataFormatJS)
1252#endif
1253 ) {
1254 ASSERT(info.gpr() != InvalidGPRReg);
1255 dataLogF(":%s\n", GPRInfo::debugName(info.gpr()));
1256 } else
1257 dataLogF("\n");
1258 }
1259 if (label)
1260 dataLogF("</%s>\n", label);
1261}
1262
1263GPRTemporary::GPRTemporary()
1264 : m_jit(0)
1265 , m_gpr(InvalidGPRReg)
1266{
1267}
1268
1269GPRTemporary::GPRTemporary(SpeculativeJIT* jit)
1270 : m_jit(jit)
1271 , m_gpr(InvalidGPRReg)
1272{
1273 m_gpr = m_jit->allocate();
1274}
1275
1276GPRTemporary::GPRTemporary(SpeculativeJIT* jit, GPRReg specific)
1277 : m_jit(jit)
1278 , m_gpr(InvalidGPRReg)
1279{
1280 m_gpr = m_jit->allocate(specific);
1281}
1282
1283#if USE(JSVALUE32_64)
1284GPRTemporary::GPRTemporary(
1285 SpeculativeJIT* jit, ReuseTag, JSValueOperand& op1, WhichValueWord which)
1286 : m_jit(jit)
1287 , m_gpr(InvalidGPRReg)
1288{
1289 if (!op1.isDouble() && m_jit->canReuse(op1.node()))
1290 m_gpr = m_jit->reuse(op1.gpr(which));
1291 else
1292 m_gpr = m_jit->allocate();
1293}
1294#else // USE(JSVALUE32_64)
1295GPRTemporary::GPRTemporary(SpeculativeJIT* jit, ReuseTag, JSValueOperand& op1, WhichValueWord)
1296 : GPRTemporary(jit, Reuse, op1)
1297{
1298}
1299#endif
1300
1301JSValueRegsTemporary::JSValueRegsTemporary() { }
1302
1303JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit)
1304#if USE(JSVALUE64)
1305 : m_gpr(jit)
1306#else
1307 : m_payloadGPR(jit)
1308 , m_tagGPR(jit)
1309#endif
1310{
1311}
1312
1313#if USE(JSVALUE64)
1314template<typename T>
1315JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, T& operand, WhichValueWord)
1316 : m_gpr(jit, Reuse, operand)
1317{
1318}
1319#else
1320template<typename T>
1321JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, T& operand, WhichValueWord resultWord)
1322{
1323 if (resultWord == PayloadWord) {
1324 m_payloadGPR = GPRTemporary(jit, Reuse, operand);
1325 m_tagGPR = GPRTemporary(jit);
1326 } else {
1327 m_payloadGPR = GPRTemporary(jit);
1328 m_tagGPR = GPRTemporary(jit, Reuse, operand);
1329 }
1330}
1331#endif
1332
1333#if USE(JSVALUE64)
1334JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, JSValueOperand& operand)
1335{
1336 m_gpr = GPRTemporary(jit, Reuse, operand);
1337}
1338#else
1339JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, JSValueOperand& operand)
1340{
1341 if (jit->canReuse(operand.node())) {
1342 m_payloadGPR = GPRTemporary(jit, Reuse, operand, PayloadWord);
1343 m_tagGPR = GPRTemporary(jit, Reuse, operand, TagWord);
1344 } else {
1345 m_payloadGPR = GPRTemporary(jit);
1346 m_tagGPR = GPRTemporary(jit);
1347 }
1348}
1349#endif
1350
1351JSValueRegsTemporary::~JSValueRegsTemporary() { }
1352
1353JSValueRegs JSValueRegsTemporary::regs()
1354{
1355#if USE(JSVALUE64)
1356 return JSValueRegs(m_gpr.gpr());
1357#else
1358 return JSValueRegs(m_tagGPR.gpr(), m_payloadGPR.gpr());
1359#endif
1360}
1361
1362void GPRTemporary::adopt(GPRTemporary& other)
1363{
1364 ASSERT(!m_jit);
1365 ASSERT(m_gpr == InvalidGPRReg);
1366 ASSERT(other.m_jit);
1367 ASSERT(other.m_gpr != InvalidGPRReg);
1368 m_jit = other.m_jit;
1369 m_gpr = other.m_gpr;
1370 other.m_jit = 0;
1371 other.m_gpr = InvalidGPRReg;
1372}
1373
1374FPRTemporary::FPRTemporary(FPRTemporary&& other)
1375{
1376 ASSERT(other.m_jit);
1377 ASSERT(other.m_fpr != InvalidFPRReg);
1378 m_jit = other.m_jit;
1379 m_fpr = other.m_fpr;
1380
1381 other.m_jit = nullptr;
1382}
1383
1384FPRTemporary::FPRTemporary(SpeculativeJIT* jit)
1385 : m_jit(jit)
1386 , m_fpr(InvalidFPRReg)
1387{
1388 m_fpr = m_jit->fprAllocate();
1389}
1390
1391FPRTemporary::FPRTemporary(SpeculativeJIT* jit, SpeculateDoubleOperand& op1)
1392 : m_jit(jit)
1393 , m_fpr(InvalidFPRReg)
1394{
1395 if (m_jit->canReuse(op1.node()))
1396 m_fpr = m_jit->reuse(op1.fpr());
1397 else
1398 m_fpr = m_jit->fprAllocate();
1399}
1400
1401FPRTemporary::FPRTemporary(SpeculativeJIT* jit, SpeculateDoubleOperand& op1, SpeculateDoubleOperand& op2)
1402 : m_jit(jit)
1403 , m_fpr(InvalidFPRReg)
1404{
1405 if (m_jit->canReuse(op1.node()))
1406 m_fpr = m_jit->reuse(op1.fpr());
1407 else if (m_jit->canReuse(op2.node()))
1408 m_fpr = m_jit->reuse(op2.fpr());
1409 else if (m_jit->canReuse(op1.node(), op2.node()) && op1.fpr() == op2.fpr())
1410 m_fpr = m_jit->reuse(op1.fpr());
1411 else
1412 m_fpr = m_jit->fprAllocate();
1413}
1414
1415#if USE(JSVALUE32_64)
1416FPRTemporary::FPRTemporary(SpeculativeJIT* jit, JSValueOperand& op1)
1417 : m_jit(jit)
1418 , m_fpr(InvalidFPRReg)
1419{
1420 if (op1.isDouble() && m_jit->canReuse(op1.node()))
1421 m_fpr = m_jit->reuse(op1.fpr());
1422 else
1423 m_fpr = m_jit->fprAllocate();
1424}
1425#endif
1426
1427void SpeculativeJIT::compilePeepHoleDoubleBranch(Node* node, Node* branchNode, JITCompiler::DoubleCondition condition)
1428{
1429 BasicBlock* taken = branchNode->branchData()->taken.block;
1430 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1431
1432 if (taken == nextBlock()) {
1433 condition = MacroAssembler::invert(condition);
1434 std::swap(taken, notTaken);
1435 }
1436
1437 SpeculateDoubleOperand op1(this, node->child1());
1438 SpeculateDoubleOperand op2(this, node->child2());
1439
1440 branchDouble(condition, op1.fpr(), op2.fpr(), taken);
1441 jump(notTaken);
1442}
1443
1444void SpeculativeJIT::compilePeepHoleObjectEquality(Node* node, Node* branchNode)
1445{
1446 BasicBlock* taken = branchNode->branchData()->taken.block;
1447 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1448
1449 MacroAssembler::RelationalCondition condition = MacroAssembler::Equal;
1450
1451 if (taken == nextBlock()) {
1452 condition = MacroAssembler::NotEqual;
1453 BasicBlock* tmp = taken;
1454 taken = notTaken;
1455 notTaken = tmp;
1456 }
1457
1458 SpeculateCellOperand op1(this, node->child1());
1459 SpeculateCellOperand op2(this, node->child2());
1460
1461 GPRReg op1GPR = op1.gpr();
1462 GPRReg op2GPR = op2.gpr();
1463
1464 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
1465 if (m_state.forNode(node->child1()).m_type & ~SpecObject) {
1466 speculationCheck(
1467 BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), m_jit.branchIfNotObject(op1GPR));
1468 }
1469 if (m_state.forNode(node->child2()).m_type & ~SpecObject) {
1470 speculationCheck(
1471 BadType, JSValueSource::unboxedCell(op2GPR), node->child2(), m_jit.branchIfNotObject(op2GPR));
1472 }
1473 } else {
1474 if (m_state.forNode(node->child1()).m_type & ~SpecObject) {
1475 speculationCheck(
1476 BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
1477 m_jit.branchIfNotObject(op1GPR));
1478 }
1479 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
1480 m_jit.branchTest8(
1481 MacroAssembler::NonZero,
1482 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
1483 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1484
1485 if (m_state.forNode(node->child2()).m_type & ~SpecObject) {
1486 speculationCheck(
1487 BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
1488 m_jit.branchIfNotObject(op2GPR));
1489 }
1490 speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
1491 m_jit.branchTest8(
1492 MacroAssembler::NonZero,
1493 MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()),
1494 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1495 }
1496
1497 branchPtr(condition, op1GPR, op2GPR, taken);
1498 jump(notTaken);
1499}
1500
1501void SpeculativeJIT::compilePeepHoleBooleanBranch(Node* node, Node* branchNode, JITCompiler::RelationalCondition condition)
1502{
1503 BasicBlock* taken = branchNode->branchData()->taken.block;
1504 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1505
1506 // The branch instruction will branch to the taken block.
1507 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
1508 if (taken == nextBlock()) {
1509 condition = JITCompiler::invert(condition);
1510 BasicBlock* tmp = taken;
1511 taken = notTaken;
1512 notTaken = tmp;
1513 }
1514
1515 if (node->child1()->isInt32Constant()) {
1516 int32_t imm = node->child1()->asInt32();
1517 SpeculateBooleanOperand op2(this, node->child2());
1518 branch32(condition, JITCompiler::Imm32(imm), op2.gpr(), taken);
1519 } else if (node->child2()->isInt32Constant()) {
1520 SpeculateBooleanOperand op1(this, node->child1());
1521 int32_t imm = node->child2()->asInt32();
1522 branch32(condition, op1.gpr(), JITCompiler::Imm32(imm), taken);
1523 } else {
1524 SpeculateBooleanOperand op1(this, node->child1());
1525 SpeculateBooleanOperand op2(this, node->child2());
1526 branch32(condition, op1.gpr(), op2.gpr(), taken);
1527 }
1528
1529 jump(notTaken);
1530}
1531
1532void SpeculativeJIT::compileStringSlice(Node* node)
1533{
1534 SpeculateCellOperand string(this, node->child1());
1535
1536 GPRReg stringGPR = string.gpr();
1537
1538 speculateString(node->child1(), stringGPR);
1539
1540 SpeculateInt32Operand start(this, node->child2());
1541 GPRReg startGPR = start.gpr();
1542
1543 Optional<SpeculateInt32Operand> end;
1544 Optional<GPRReg> endGPR;
1545 if (node->child3()) {
1546 end.emplace(this, node->child3());
1547 endGPR.emplace(end->gpr());
1548 }
1549
1550 GPRTemporary temp(this);
1551 GPRTemporary temp2(this);
1552 GPRTemporary startIndex(this);
1553
1554 GPRReg tempGPR = temp.gpr();
1555 GPRReg temp2GPR = temp2.gpr();
1556 GPRReg startIndexGPR = startIndex.gpr();
1557
1558 m_jit.loadPtr(CCallHelpers::Address(stringGPR, JSString::offsetOfValue()), tempGPR);
1559 auto isRope = m_jit.branchIfRopeStringImpl(tempGPR);
1560 {
1561 m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), temp2GPR);
1562
1563 emitPopulateSliceIndex(node->child2(), startGPR, temp2GPR, startIndexGPR);
1564
1565 if (node->child3())
1566 emitPopulateSliceIndex(node->child3(), endGPR.value(), temp2GPR, tempGPR);
1567 else
1568 m_jit.move(temp2GPR, tempGPR);
1569 }
1570
1571 CCallHelpers::JumpList doneCases;
1572 CCallHelpers::JumpList slowCases;
1573
1574 auto nonEmptyCase = m_jit.branch32(MacroAssembler::Below, startIndexGPR, tempGPR);
1575 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(&vm())), tempGPR);
1576 doneCases.append(m_jit.jump());
1577
1578 nonEmptyCase.link(&m_jit);
1579 m_jit.sub32(startIndexGPR, tempGPR); // the size of the sliced string.
1580 slowCases.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(1)));
1581
1582 // Refill StringImpl* here.
1583 m_jit.loadPtr(MacroAssembler::Address(stringGPR, JSString::offsetOfValue()), temp2GPR);
1584 m_jit.loadPtr(MacroAssembler::Address(temp2GPR, StringImpl::dataOffset()), tempGPR);
1585
1586 // Load the character into scratchReg
1587 m_jit.zeroExtend32ToPtr(startIndexGPR, startIndexGPR);
1588 auto is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(temp2GPR, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
1589
1590 m_jit.load8(MacroAssembler::BaseIndex(tempGPR, startIndexGPR, MacroAssembler::TimesOne, 0), tempGPR);
1591 auto cont8Bit = m_jit.jump();
1592
1593 is16Bit.link(&m_jit);
1594 m_jit.load16(MacroAssembler::BaseIndex(tempGPR, startIndexGPR, MacroAssembler::TimesTwo, 0), tempGPR);
1595
1596 auto bigCharacter = m_jit.branch32(MacroAssembler::Above, tempGPR, TrustedImm32(maxSingleCharacterString));
1597
1598 // 8 bit string values don't need the isASCII check.
1599 cont8Bit.link(&m_jit);
1600
1601 m_jit.lshift32(MacroAssembler::TrustedImm32(sizeof(void*) == 4 ? 2 : 3), tempGPR);
1602 m_jit.addPtr(TrustedImmPtr(m_jit.vm()->smallStrings.singleCharacterStrings()), tempGPR);
1603 m_jit.loadPtr(tempGPR, tempGPR);
1604
1605 addSlowPathGenerator(slowPathCall(bigCharacter, this, operationSingleCharacterString, tempGPR, tempGPR));
1606
1607 addSlowPathGenerator(slowPathCall(slowCases, this, operationStringSubstr, tempGPR, stringGPR, startIndexGPR, tempGPR));
1608
1609 if (endGPR)
1610 addSlowPathGenerator(slowPathCall(isRope, this, operationStringSlice, tempGPR, stringGPR, startGPR, *endGPR));
1611 else
1612 addSlowPathGenerator(slowPathCall(isRope, this, operationStringSlice, tempGPR, stringGPR, startGPR, TrustedImm32(std::numeric_limits<int32_t>::max())));
1613
1614 doneCases.link(&m_jit);
1615 cellResult(tempGPR, node);
1616}
1617
1618void SpeculativeJIT::compileToLowerCase(Node* node)
1619{
1620 ASSERT(node->op() == ToLowerCase);
1621 SpeculateCellOperand string(this, node->child1());
1622 GPRTemporary temp(this);
1623 GPRTemporary index(this);
1624 GPRTemporary charReg(this);
1625 GPRTemporary length(this);
1626
1627 GPRReg stringGPR = string.gpr();
1628 GPRReg tempGPR = temp.gpr();
1629 GPRReg indexGPR = index.gpr();
1630 GPRReg charGPR = charReg.gpr();
1631 GPRReg lengthGPR = length.gpr();
1632
1633 speculateString(node->child1(), stringGPR);
1634
1635 CCallHelpers::JumpList slowPath;
1636
1637 m_jit.move(TrustedImmPtr(nullptr), indexGPR);
1638
1639 m_jit.loadPtr(MacroAssembler::Address(stringGPR, JSString::offsetOfValue()), tempGPR);
1640 slowPath.append(m_jit.branchIfRopeStringImpl(tempGPR));
1641 slowPath.append(m_jit.branchTest32(
1642 MacroAssembler::Zero, MacroAssembler::Address(tempGPR, StringImpl::flagsOffset()),
1643 MacroAssembler::TrustedImm32(StringImpl::flagIs8Bit())));
1644 m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), lengthGPR);
1645 m_jit.loadPtr(MacroAssembler::Address(tempGPR, StringImpl::dataOffset()), tempGPR);
1646
1647 auto loopStart = m_jit.label();
1648 auto loopDone = m_jit.branch32(CCallHelpers::AboveOrEqual, indexGPR, lengthGPR);
1649 m_jit.load8(MacroAssembler::BaseIndex(tempGPR, indexGPR, MacroAssembler::TimesOne), charGPR);
1650 slowPath.append(m_jit.branchTest32(CCallHelpers::NonZero, charGPR, TrustedImm32(~0x7F)));
1651 m_jit.sub32(TrustedImm32('A'), charGPR);
1652 slowPath.append(m_jit.branch32(CCallHelpers::BelowOrEqual, charGPR, TrustedImm32('Z' - 'A')));
1653
1654 m_jit.add32(TrustedImm32(1), indexGPR);
1655 m_jit.jump().linkTo(loopStart, &m_jit);
1656
1657 slowPath.link(&m_jit);
1658 silentSpillAllRegisters(lengthGPR);
1659 callOperation(operationToLowerCase, lengthGPR, stringGPR, indexGPR);
1660 silentFillAllRegisters();
1661 m_jit.exceptionCheck();
1662 auto done = m_jit.jump();
1663
1664 loopDone.link(&m_jit);
1665 m_jit.move(stringGPR, lengthGPR);
1666
1667 done.link(&m_jit);
1668 cellResult(lengthGPR, node);
1669}
1670
1671void SpeculativeJIT::compilePeepHoleInt32Branch(Node* node, Node* branchNode, JITCompiler::RelationalCondition condition)
1672{
1673 BasicBlock* taken = branchNode->branchData()->taken.block;
1674 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1675
1676 // The branch instruction will branch to the taken block.
1677 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
1678 if (taken == nextBlock()) {
1679 condition = JITCompiler::invert(condition);
1680 BasicBlock* tmp = taken;
1681 taken = notTaken;
1682 notTaken = tmp;
1683 }
1684
1685 if (node->child1()->isInt32Constant()) {
1686 int32_t imm = node->child1()->asInt32();
1687 SpeculateInt32Operand op2(this, node->child2());
1688 branch32(condition, JITCompiler::Imm32(imm), op2.gpr(), taken);
1689 } else if (node->child2()->isInt32Constant()) {
1690 SpeculateInt32Operand op1(this, node->child1());
1691 int32_t imm = node->child2()->asInt32();
1692 branch32(condition, op1.gpr(), JITCompiler::Imm32(imm), taken);
1693 } else {
1694 SpeculateInt32Operand op1(this, node->child1());
1695 SpeculateInt32Operand op2(this, node->child2());
1696 branch32(condition, op1.gpr(), op2.gpr(), taken);
1697 }
1698
1699 jump(notTaken);
1700}
1701
1702// Returns true if the compare is fused with a subsequent branch.
1703bool SpeculativeJIT::compilePeepHoleBranch(Node* node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_JITOperation_EJJ operation)
1704{
1705 // Fused compare & branch.
1706 unsigned branchIndexInBlock = detectPeepHoleBranch();
1707 if (branchIndexInBlock != UINT_MAX) {
1708 Node* branchNode = m_block->at(branchIndexInBlock);
1709
1710 // detectPeepHoleBranch currently only permits the branch to be the very next node,
1711 // so can be no intervening nodes to also reference the compare.
1712 ASSERT(node->adjustedRefCount() == 1);
1713
1714 if (node->isBinaryUseKind(Int32Use))
1715 compilePeepHoleInt32Branch(node, branchNode, condition);
1716#if USE(JSVALUE64)
1717 else if (node->isBinaryUseKind(Int52RepUse))
1718 compilePeepHoleInt52Branch(node, branchNode, condition);
1719#endif // USE(JSVALUE64)
1720 else if (node->isBinaryUseKind(StringUse) || node->isBinaryUseKind(StringIdentUse)) {
1721 // Use non-peephole comparison, for now.
1722 return false;
1723 } else if (node->isBinaryUseKind(DoubleRepUse))
1724 compilePeepHoleDoubleBranch(node, branchNode, doubleCondition);
1725 else if (node->op() == CompareEq) {
1726 if (node->isBinaryUseKind(BooleanUse))
1727 compilePeepHoleBooleanBranch(node, branchNode, condition);
1728 else if (node->isBinaryUseKind(SymbolUse))
1729 compilePeepHoleSymbolEquality(node, branchNode);
1730 else if (node->isBinaryUseKind(ObjectUse))
1731 compilePeepHoleObjectEquality(node, branchNode);
1732 else if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse))
1733 compilePeepHoleObjectToObjectOrOtherEquality(node->child1(), node->child2(), branchNode);
1734 else if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse))
1735 compilePeepHoleObjectToObjectOrOtherEquality(node->child2(), node->child1(), branchNode);
1736 else if (!needsTypeCheck(node->child1(), SpecOther))
1737 nonSpeculativePeepholeBranchNullOrUndefined(node->child2(), branchNode);
1738 else if (!needsTypeCheck(node->child2(), SpecOther))
1739 nonSpeculativePeepholeBranchNullOrUndefined(node->child1(), branchNode);
1740 else {
1741 nonSpeculativePeepholeBranch(node, branchNode, condition, operation);
1742 return true;
1743 }
1744 } else {
1745 nonSpeculativePeepholeBranch(node, branchNode, condition, operation);
1746 return true;
1747 }
1748
1749 use(node->child1());
1750 use(node->child2());
1751 m_indexInBlock = branchIndexInBlock;
1752 m_currentNode = branchNode;
1753 return true;
1754 }
1755 return false;
1756}
1757
1758void SpeculativeJIT::noticeOSRBirth(Node* node)
1759{
1760 if (!node->hasVirtualRegister())
1761 return;
1762
1763 VirtualRegister virtualRegister = node->virtualRegister();
1764 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
1765
1766 info.noticeOSRBirth(*m_stream, node, virtualRegister);
1767}
1768
1769void SpeculativeJIT::compileMovHint(Node* node)
1770{
1771 ASSERT(node->containsMovHint() && node->op() != ZombieHint);
1772
1773 Node* child = node->child1().node();
1774 noticeOSRBirth(child);
1775
1776 m_stream->appendAndLog(VariableEvent::movHint(MinifiedID(child), node->unlinkedLocal()));
1777}
1778
1779void SpeculativeJIT::bail(AbortReason reason)
1780{
1781 if (verboseCompilationEnabled())
1782 dataLog("Bailing compilation.\n");
1783 m_compileOkay = true;
1784 m_jit.abortWithReason(reason, m_lastGeneratedNode);
1785 clearGenerationInfo();
1786}
1787
1788void SpeculativeJIT::compileCurrentBlock()
1789{
1790 ASSERT(m_compileOkay);
1791
1792 if (!m_block)
1793 return;
1794
1795 ASSERT(m_block->isReachable);
1796
1797 m_jit.blockHeads()[m_block->index] = m_jit.label();
1798
1799 if (!m_block->intersectionOfCFAHasVisited) {
1800 // Don't generate code for basic blocks that are unreachable according to CFA.
1801 // But to be sure that nobody has generated a jump to this block, drop in a
1802 // breakpoint here.
1803 m_jit.abortWithReason(DFGUnreachableBasicBlock);
1804 return;
1805 }
1806
1807 if (m_block->isCatchEntrypoint) {
1808 m_jit.addPtr(CCallHelpers::TrustedImm32(-(m_jit.graph().frameRegisterCount() * sizeof(Register))), GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
1809 if (Options::zeroStackFrame())
1810 m_jit.clearStackFrame(GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister, GPRInfo::regT0, m_jit.graph().frameRegisterCount() * sizeof(Register));
1811 m_jit.emitSaveCalleeSaves();
1812 m_jit.emitMaterializeTagCheckRegisters();
1813 m_jit.emitPutToCallFrameHeader(m_jit.codeBlock(), CallFrameSlot::codeBlock);
1814 }
1815
1816 m_stream->appendAndLog(VariableEvent::reset());
1817
1818 m_jit.jitAssertHasValidCallFrame();
1819 m_jit.jitAssertTagsInPlace();
1820 m_jit.jitAssertArgumentCountSane();
1821
1822 m_state.reset();
1823 m_state.beginBasicBlock(m_block);
1824
1825 for (size_t i = m_block->variablesAtHead.size(); i--;) {
1826 int operand = m_block->variablesAtHead.operandForIndex(i);
1827 Node* node = m_block->variablesAtHead[i];
1828 if (!node)
1829 continue; // No need to record dead SetLocal's.
1830
1831 VariableAccessData* variable = node->variableAccessData();
1832 DataFormat format;
1833 if (!node->refCount())
1834 continue; // No need to record dead SetLocal's.
1835 format = dataFormatFor(variable->flushFormat());
1836 m_stream->appendAndLog(
1837 VariableEvent::setLocal(
1838 VirtualRegister(operand),
1839 variable->machineLocal(),
1840 format));
1841 }
1842
1843 m_origin = NodeOrigin();
1844
1845 for (m_indexInBlock = 0; m_indexInBlock < m_block->size(); ++m_indexInBlock) {
1846 m_currentNode = m_block->at(m_indexInBlock);
1847
1848 // We may have hit a contradiction that the CFA was aware of but that the JIT
1849 // didn't cause directly.
1850 if (!m_state.isValid()) {
1851 bail(DFGBailedAtTopOfBlock);
1852 return;
1853 }
1854
1855 m_interpreter.startExecuting();
1856 m_interpreter.executeKnownEdgeTypes(m_currentNode);
1857 m_jit.setForNode(m_currentNode);
1858 m_origin = m_currentNode->origin;
1859 m_lastGeneratedNode = m_currentNode->op();
1860
1861 ASSERT(m_currentNode->shouldGenerate());
1862
1863 if (verboseCompilationEnabled()) {
1864 dataLogF(
1865 "SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x",
1866 (int)m_currentNode->index(),
1867 m_currentNode->origin.semantic.bytecodeIndex(), m_jit.debugOffset());
1868 dataLog("\n");
1869 }
1870
1871 if (Options::validateDFGExceptionHandling() && (mayExit(m_jit.graph(), m_currentNode) != DoesNotExit || m_currentNode->isTerminal()))
1872 m_jit.jitReleaseAssertNoException(*m_jit.vm());
1873
1874 m_jit.pcToCodeOriginMapBuilder().appendItem(m_jit.labelIgnoringWatchpoints(), m_origin.semantic);
1875
1876 compile(m_currentNode);
1877
1878 if (belongsInMinifiedGraph(m_currentNode->op()))
1879 m_minifiedGraph->append(MinifiedNode::fromNode(m_currentNode));
1880
1881#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
1882 m_jit.clearRegisterAllocationOffsets();
1883#endif
1884
1885 if (!m_compileOkay) {
1886 bail(DFGBailedAtEndOfNode);
1887 return;
1888 }
1889
1890 // Make sure that the abstract state is rematerialized for the next node.
1891 m_interpreter.executeEffects(m_indexInBlock);
1892 }
1893
1894 // Perform the most basic verification that children have been used correctly.
1895 if (!ASSERT_DISABLED) {
1896 for (auto& info : m_generationInfo)
1897 RELEASE_ASSERT(!info.alive());
1898 }
1899}
1900
1901// If we are making type predictions about our arguments then
1902// we need to check that they are correct on function entry.
1903void SpeculativeJIT::checkArgumentTypes()
1904{
1905 ASSERT(!m_currentNode);
1906 m_origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), true);
1907
1908 auto& arguments = m_jit.graph().m_rootToArguments.find(m_jit.graph().block(0))->value;
1909 for (int i = 0; i < m_jit.codeBlock()->numParameters(); ++i) {
1910 Node* node = arguments[i];
1911 if (!node) {
1912 // The argument is dead. We don't do any checks for such arguments.
1913 continue;
1914 }
1915
1916 ASSERT(node->op() == SetArgumentDefinitely);
1917 ASSERT(node->shouldGenerate());
1918
1919 VariableAccessData* variableAccessData = node->variableAccessData();
1920 FlushFormat format = variableAccessData->flushFormat();
1921
1922 if (format == FlushedJSValue)
1923 continue;
1924
1925 VirtualRegister virtualRegister = variableAccessData->local();
1926
1927 JSValueSource valueSource = JSValueSource(JITCompiler::addressFor(virtualRegister));
1928
1929#if USE(JSVALUE64)
1930 switch (format) {
1931 case FlushedInt32: {
1932 speculationCheck(BadType, valueSource, node, m_jit.branch64(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister));
1933 break;
1934 }
1935 case FlushedBoolean: {
1936 GPRTemporary temp(this);
1937 m_jit.load64(JITCompiler::addressFor(virtualRegister), temp.gpr());
1938 m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), temp.gpr());
1939 speculationCheck(BadType, valueSource, node, m_jit.branchTest64(MacroAssembler::NonZero, temp.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
1940 break;
1941 }
1942 case FlushedCell: {
1943 speculationCheck(BadType, valueSource, node, m_jit.branchTest64(MacroAssembler::NonZero, JITCompiler::addressFor(virtualRegister), GPRInfo::tagMaskRegister));
1944 break;
1945 }
1946 default:
1947 RELEASE_ASSERT_NOT_REACHED();
1948 break;
1949 }
1950#else
1951 switch (format) {
1952 case FlushedInt32: {
1953 speculationCheck(BadType, valueSource, node, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)));
1954 break;
1955 }
1956 case FlushedBoolean: {
1957 speculationCheck(BadType, valueSource, node, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)));
1958 break;
1959 }
1960 case FlushedCell: {
1961 speculationCheck(BadType, valueSource, node, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag)));
1962 break;
1963 }
1964 default:
1965 RELEASE_ASSERT_NOT_REACHED();
1966 break;
1967 }
1968#endif
1969 }
1970
1971 m_origin = NodeOrigin();
1972}
1973
1974bool SpeculativeJIT::compile()
1975{
1976 checkArgumentTypes();
1977
1978 ASSERT(!m_currentNode);
1979 for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().numBlocks(); ++blockIndex) {
1980 m_jit.setForBlockIndex(blockIndex);
1981 m_block = m_jit.graph().block(blockIndex);
1982 compileCurrentBlock();
1983 }
1984 linkBranches();
1985 return true;
1986}
1987
1988void SpeculativeJIT::createOSREntries()
1989{
1990 for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().numBlocks(); ++blockIndex) {
1991 BasicBlock* block = m_jit.graph().block(blockIndex);
1992 if (!block)
1993 continue;
1994 if (block->isOSRTarget || block->isCatchEntrypoint) {
1995 // Currently we don't have OSR entry trampolines. We could add them
1996 // here if need be.
1997 m_osrEntryHeads.append(m_jit.blockHeads()[blockIndex]);
1998 }
1999 }
2000}
2001
2002void SpeculativeJIT::linkOSREntries(LinkBuffer& linkBuffer)
2003{
2004 unsigned osrEntryIndex = 0;
2005 for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().numBlocks(); ++blockIndex) {
2006 BasicBlock* block = m_jit.graph().block(blockIndex);
2007 if (!block)
2008 continue;
2009 if (!block->isOSRTarget && !block->isCatchEntrypoint)
2010 continue;
2011 if (block->isCatchEntrypoint) {
2012 auto& argumentsVector = m_jit.graph().m_rootToArguments.find(block)->value;
2013 Vector<FlushFormat> argumentFormats;
2014 argumentFormats.reserveInitialCapacity(argumentsVector.size());
2015 for (Node* setArgument : argumentsVector) {
2016 if (setArgument) {
2017 FlushFormat flushFormat = setArgument->variableAccessData()->flushFormat();
2018 ASSERT(flushFormat == FlushedInt32 || flushFormat == FlushedCell || flushFormat == FlushedBoolean || flushFormat == FlushedJSValue);
2019 argumentFormats.uncheckedAppend(flushFormat);
2020 } else
2021 argumentFormats.uncheckedAppend(DeadFlush);
2022 }
2023 m_jit.noticeCatchEntrypoint(*block, m_osrEntryHeads[osrEntryIndex++], linkBuffer, WTFMove(argumentFormats));
2024 } else {
2025 ASSERT(block->isOSRTarget);
2026 m_jit.noticeOSREntry(*block, m_osrEntryHeads[osrEntryIndex++], linkBuffer);
2027 }
2028 }
2029
2030 m_jit.jitCode()->finalizeOSREntrypoints();
2031 m_jit.jitCode()->common.finalizeCatchEntrypoints();
2032
2033 ASSERT(osrEntryIndex == m_osrEntryHeads.size());
2034
2035 if (verboseCompilationEnabled()) {
2036 DumpContext dumpContext;
2037 dataLog("OSR Entries:\n");
2038 for (OSREntryData& entryData : m_jit.jitCode()->osrEntry)
2039 dataLog(" ", inContext(entryData, &dumpContext), "\n");
2040 if (!dumpContext.isEmpty())
2041 dumpContext.dump(WTF::dataFile());
2042 }
2043}
2044
2045void SpeculativeJIT::compileCheckTraps(Node* node)
2046{
2047 ASSERT(Options::usePollingTraps());
2048 GPRTemporary unused(this);
2049 GPRReg unusedGPR = unused.gpr();
2050
2051 JITCompiler::Jump needTrapHandling = m_jit.branchTest8(JITCompiler::NonZero,
2052 JITCompiler::AbsoluteAddress(m_jit.vm()->needTrapHandlingAddress()));
2053
2054 addSlowPathGenerator(slowPathCall(needTrapHandling, this, operationHandleTraps, unusedGPR));
2055 noResult(node);
2056}
2057
2058void SpeculativeJIT::compileDoublePutByVal(Node* node, SpeculateCellOperand& base, SpeculateStrictInt32Operand& property)
2059{
2060 Edge child3 = m_jit.graph().varArgChild(node, 2);
2061 Edge child4 = m_jit.graph().varArgChild(node, 3);
2062
2063 ArrayMode arrayMode = node->arrayMode();
2064
2065 GPRReg baseReg = base.gpr();
2066 GPRReg propertyReg = property.gpr();
2067
2068 SpeculateDoubleOperand value(this, child3);
2069
2070 FPRReg valueReg = value.fpr();
2071
2072 DFG_TYPE_CHECK(
2073 JSValueRegs(), child3, SpecFullRealNumber,
2074 m_jit.branchIfNaN(valueReg));
2075
2076 if (!m_compileOkay)
2077 return;
2078
2079 StorageOperand storage(this, child4);
2080 GPRReg storageReg = storage.gpr();
2081
2082 if (node->op() == PutByValAlias) {
2083 // Store the value to the array.
2084 GPRReg propertyReg = property.gpr();
2085 FPRReg valueReg = value.fpr();
2086 m_jit.storeDouble(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight));
2087
2088 noResult(m_currentNode);
2089 return;
2090 }
2091
2092 GPRTemporary temporary;
2093 GPRReg temporaryReg = temporaryRegisterForPutByVal(temporary, node);
2094
2095 MacroAssembler::Jump slowCase;
2096
2097 if (arrayMode.isInBounds()) {
2098 speculationCheck(
2099 OutOfBounds, JSValueRegs(), 0,
2100 m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2101 } else {
2102 MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
2103
2104 slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength()));
2105
2106 if (!arrayMode.isOutOfBounds())
2107 speculationCheck(OutOfBounds, JSValueRegs(), 0, slowCase);
2108
2109 m_jit.add32(TrustedImm32(1), propertyReg, temporaryReg);
2110 m_jit.store32(temporaryReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
2111
2112 inBounds.link(&m_jit);
2113 }
2114
2115 m_jit.storeDouble(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight));
2116
2117 base.use();
2118 property.use();
2119 value.use();
2120 storage.use();
2121
2122 if (arrayMode.isOutOfBounds()) {
2123 addSlowPathGenerator(
2124 slowPathCall(
2125 slowCase, this,
2126 m_jit.isStrictModeFor(node->origin.semantic)
2127 ? (node->op() == PutByValDirect ? operationPutDoubleByValDirectBeyondArrayBoundsStrict : operationPutDoubleByValBeyondArrayBoundsStrict)
2128 : (node->op() == PutByValDirect ? operationPutDoubleByValDirectBeyondArrayBoundsNonStrict : operationPutDoubleByValBeyondArrayBoundsNonStrict),
2129 NoResult, baseReg, propertyReg, valueReg));
2130 }
2131
2132 noResult(m_currentNode, UseChildrenCalledExplicitly);
2133}
2134
2135void SpeculativeJIT::compileGetCharCodeAt(Node* node)
2136{
2137 SpeculateCellOperand string(this, node->child1());
2138 SpeculateStrictInt32Operand index(this, node->child2());
2139 StorageOperand storage(this, node->child3());
2140
2141 GPRReg stringReg = string.gpr();
2142 GPRReg indexReg = index.gpr();
2143 GPRReg storageReg = storage.gpr();
2144
2145 ASSERT(speculationChecked(m_state.forNode(node->child1()).m_type, SpecString));
2146
2147 GPRTemporary scratch(this);
2148 GPRReg scratchReg = scratch.gpr();
2149
2150 m_jit.loadPtr(MacroAssembler::Address(stringReg, JSString::offsetOfValue()), scratchReg);
2151
2152 // unsigned comparison so we can filter out negative indices and indices that are too large
2153 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, indexReg, CCallHelpers::Address(scratchReg, StringImpl::lengthMemoryOffset())));
2154
2155 // Load the character into scratchReg
2156 JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
2157
2158 m_jit.load8(MacroAssembler::BaseIndex(storageReg, indexReg, MacroAssembler::TimesOne, 0), scratchReg);
2159 JITCompiler::Jump cont8Bit = m_jit.jump();
2160
2161 is16Bit.link(&m_jit);
2162
2163 m_jit.load16(MacroAssembler::BaseIndex(storageReg, indexReg, MacroAssembler::TimesTwo, 0), scratchReg);
2164
2165 cont8Bit.link(&m_jit);
2166
2167 int32Result(scratchReg, m_currentNode);
2168}
2169
2170void SpeculativeJIT::compileGetByValOnString(Node* node)
2171{
2172 SpeculateCellOperand base(this, m_graph.child(node, 0));
2173 SpeculateStrictInt32Operand property(this, m_graph.child(node, 1));
2174 StorageOperand storage(this, m_graph.child(node, 2));
2175 GPRReg baseReg = base.gpr();
2176 GPRReg propertyReg = property.gpr();
2177 GPRReg storageReg = storage.gpr();
2178
2179 GPRTemporary scratch(this);
2180 GPRReg scratchReg = scratch.gpr();
2181#if USE(JSVALUE32_64)
2182 GPRTemporary resultTag;
2183 GPRReg resultTagReg = InvalidGPRReg;
2184 if (node->arrayMode().isOutOfBounds()) {
2185 GPRTemporary realResultTag(this);
2186 resultTag.adopt(realResultTag);
2187 resultTagReg = resultTag.gpr();
2188 }
2189#endif
2190
2191 ASSERT(ArrayMode(Array::String, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.child(node, 0))));
2192
2193 // unsigned comparison so we can filter out negative indices and indices that are too large
2194 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), scratchReg);
2195 JITCompiler::Jump outOfBounds = m_jit.branch32(
2196 MacroAssembler::AboveOrEqual, propertyReg,
2197 MacroAssembler::Address(scratchReg, StringImpl::lengthMemoryOffset()));
2198 if (node->arrayMode().isInBounds())
2199 speculationCheck(OutOfBounds, JSValueRegs(), 0, outOfBounds);
2200
2201 // Load the character into scratchReg
2202 JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
2203
2204 m_jit.load8(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne, 0), scratchReg);
2205 JITCompiler::Jump cont8Bit = m_jit.jump();
2206
2207 is16Bit.link(&m_jit);
2208
2209 m_jit.load16(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo, 0), scratchReg);
2210
2211 JITCompiler::Jump bigCharacter =
2212 m_jit.branch32(MacroAssembler::Above, scratchReg, TrustedImm32(maxSingleCharacterString));
2213
2214 // 8 bit string values don't need the isASCII check.
2215 cont8Bit.link(&m_jit);
2216
2217 m_jit.lshift32(MacroAssembler::TrustedImm32(sizeof(void*) == 4 ? 2 : 3), scratchReg);
2218 m_jit.addPtr(TrustedImmPtr(m_jit.vm()->smallStrings.singleCharacterStrings()), scratchReg);
2219 m_jit.loadPtr(scratchReg, scratchReg);
2220
2221 addSlowPathGenerator(
2222 slowPathCall(
2223 bigCharacter, this, operationSingleCharacterString, scratchReg, scratchReg));
2224
2225 if (node->arrayMode().isOutOfBounds()) {
2226#if USE(JSVALUE32_64)
2227 m_jit.move(TrustedImm32(JSValue::CellTag), resultTagReg);
2228#endif
2229
2230 JSGlobalObject* globalObject = m_jit.globalObjectFor(node->origin.semantic);
2231 bool prototypeChainIsSane = false;
2232 if (globalObject->stringPrototypeChainIsSane()) {
2233 // FIXME: This could be captured using a Speculation mode that means "out-of-bounds
2234 // loads return a trivial value". Something like SaneChainOutOfBounds. This should
2235 // speculate that we don't take negative out-of-bounds, or better yet, it should rely
2236 // on a stringPrototypeChainIsSane() guaranteeing that the prototypes have no negative
2237 // indexed properties either.
2238 // https://bugs.webkit.org/show_bug.cgi?id=144668
2239 m_jit.graph().registerAndWatchStructureTransition(globalObject->stringPrototype()->structure(*m_jit.vm()));
2240 m_jit.graph().registerAndWatchStructureTransition(globalObject->objectPrototype()->structure(*m_jit.vm()));
2241 prototypeChainIsSane = globalObject->stringPrototypeChainIsSane();
2242 }
2243 if (prototypeChainIsSane) {
2244#if USE(JSVALUE64)
2245 addSlowPathGenerator(std::make_unique<SaneStringGetByValSlowPathGenerator>(
2246 outOfBounds, this, JSValueRegs(scratchReg), baseReg, propertyReg));
2247#else
2248 addSlowPathGenerator(std::make_unique<SaneStringGetByValSlowPathGenerator>(
2249 outOfBounds, this, JSValueRegs(resultTagReg, scratchReg),
2250 baseReg, propertyReg));
2251#endif
2252 } else {
2253#if USE(JSVALUE64)
2254 addSlowPathGenerator(
2255 slowPathCall(
2256 outOfBounds, this, operationGetByValStringInt,
2257 scratchReg, baseReg, propertyReg));
2258#else
2259 addSlowPathGenerator(
2260 slowPathCall(
2261 outOfBounds, this, operationGetByValStringInt,
2262 JSValueRegs(resultTagReg, scratchReg), baseReg, propertyReg));
2263#endif
2264 }
2265
2266#if USE(JSVALUE64)
2267 jsValueResult(scratchReg, m_currentNode);
2268#else
2269 jsValueResult(resultTagReg, scratchReg, m_currentNode);
2270#endif
2271 } else
2272 cellResult(scratchReg, m_currentNode);
2273}
2274
2275void SpeculativeJIT::compileFromCharCode(Node* node)
2276{
2277 Edge& child = node->child1();
2278 if (child.useKind() == UntypedUse) {
2279 JSValueOperand opr(this, child);
2280 JSValueRegs oprRegs = opr.jsValueRegs();
2281
2282 flushRegisters();
2283 JSValueRegsFlushedCallResult result(this);
2284 JSValueRegs resultRegs = result.regs();
2285 callOperation(operationStringFromCharCodeUntyped, resultRegs, oprRegs);
2286 m_jit.exceptionCheck();
2287
2288 jsValueResult(resultRegs, node);
2289 return;
2290 }
2291
2292 SpeculateStrictInt32Operand property(this, child);
2293 GPRReg propertyReg = property.gpr();
2294 GPRTemporary smallStrings(this);
2295 GPRTemporary scratch(this);
2296 GPRReg scratchReg = scratch.gpr();
2297 GPRReg smallStringsReg = smallStrings.gpr();
2298
2299 JITCompiler::JumpList slowCases;
2300 slowCases.append(m_jit.branch32(MacroAssembler::Above, propertyReg, TrustedImm32(maxSingleCharacterString)));
2301 m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.singleCharacterStrings()), smallStringsReg);
2302 m_jit.loadPtr(MacroAssembler::BaseIndex(smallStringsReg, propertyReg, MacroAssembler::ScalePtr, 0), scratchReg);
2303
2304 slowCases.append(m_jit.branchTest32(MacroAssembler::Zero, scratchReg));
2305 addSlowPathGenerator(slowPathCall(slowCases, this, operationStringFromCharCode, scratchReg, propertyReg));
2306 cellResult(scratchReg, m_currentNode);
2307}
2308
2309GeneratedOperandType SpeculativeJIT::checkGeneratedTypeForToInt32(Node* node)
2310{
2311 VirtualRegister virtualRegister = node->virtualRegister();
2312 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
2313
2314 switch (info.registerFormat()) {
2315 case DataFormatStorage:
2316 RELEASE_ASSERT_NOT_REACHED();
2317
2318 case DataFormatBoolean:
2319 case DataFormatCell:
2320 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
2321 return GeneratedOperandTypeUnknown;
2322
2323 case DataFormatNone:
2324 case DataFormatJSCell:
2325 case DataFormatJS:
2326 case DataFormatJSBoolean:
2327 case DataFormatJSDouble:
2328 return GeneratedOperandJSValue;
2329
2330 case DataFormatJSInt32:
2331 case DataFormatInt32:
2332 return GeneratedOperandInteger;
2333
2334 default:
2335 RELEASE_ASSERT_NOT_REACHED();
2336 return GeneratedOperandTypeUnknown;
2337 }
2338}
2339
2340void SpeculativeJIT::compileValueToInt32(Node* node)
2341{
2342 switch (node->child1().useKind()) {
2343#if USE(JSVALUE64)
2344 case Int52RepUse: {
2345 SpeculateStrictInt52Operand op1(this, node->child1());
2346 GPRTemporary result(this, Reuse, op1);
2347 GPRReg op1GPR = op1.gpr();
2348 GPRReg resultGPR = result.gpr();
2349 m_jit.zeroExtend32ToPtr(op1GPR, resultGPR);
2350 int32Result(resultGPR, node, DataFormatInt32);
2351 return;
2352 }
2353#endif // USE(JSVALUE64)
2354
2355 case DoubleRepUse: {
2356 GPRTemporary result(this);
2357 SpeculateDoubleOperand op1(this, node->child1());
2358 FPRReg fpr = op1.fpr();
2359 GPRReg gpr = result.gpr();
2360#if CPU(ARM64)
2361 if (MacroAssemblerARM64::supportsDoubleToInt32ConversionUsingJavaScriptSemantics())
2362 m_jit.convertDoubleToInt32UsingJavaScriptSemantics(fpr, gpr);
2363 else
2364#endif
2365 {
2366 JITCompiler::Jump notTruncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateFailed);
2367 addSlowPathGenerator(slowPathCall(notTruncatedToInteger, this,
2368 hasSensibleDoubleToInt() ? operationToInt32SensibleSlow : operationToInt32, NeedToSpill, ExceptionCheckRequirement::CheckNotNeeded, gpr, fpr));
2369 }
2370 int32Result(gpr, node);
2371 return;
2372 }
2373
2374 case NumberUse:
2375 case NotCellUse: {
2376 switch (checkGeneratedTypeForToInt32(node->child1().node())) {
2377 case GeneratedOperandInteger: {
2378 SpeculateInt32Operand op1(this, node->child1(), ManualOperandSpeculation);
2379 GPRTemporary result(this, Reuse, op1);
2380 m_jit.move(op1.gpr(), result.gpr());
2381 int32Result(result.gpr(), node, op1.format());
2382 return;
2383 }
2384 case GeneratedOperandJSValue: {
2385 GPRTemporary result(this);
2386#if USE(JSVALUE64)
2387 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
2388
2389 GPRReg gpr = op1.gpr();
2390 GPRReg resultGpr = result.gpr();
2391 FPRTemporary tempFpr(this);
2392 FPRReg fpr = tempFpr.fpr();
2393
2394 JITCompiler::Jump isInteger = m_jit.branchIfInt32(gpr);
2395 JITCompiler::JumpList converted;
2396
2397 if (node->child1().useKind() == NumberUse) {
2398 DFG_TYPE_CHECK(
2399 JSValueRegs(gpr), node->child1(), SpecBytecodeNumber,
2400 m_jit.branchIfNotNumber(gpr));
2401 } else {
2402 JITCompiler::Jump isNumber = m_jit.branchIfNumber(gpr);
2403
2404 DFG_TYPE_CHECK(
2405 JSValueRegs(gpr), node->child1(), ~SpecCellCheck, m_jit.branchIfCell(JSValueRegs(gpr)));
2406
2407 // It's not a cell: so true turns into 1 and all else turns into 0.
2408 m_jit.compare64(JITCompiler::Equal, gpr, TrustedImm32(ValueTrue), resultGpr);
2409 converted.append(m_jit.jump());
2410
2411 isNumber.link(&m_jit);
2412 }
2413
2414 // First, if we get here we have a double encoded as a JSValue
2415 unboxDouble(gpr, resultGpr, fpr);
2416#if CPU(ARM64)
2417 if (MacroAssemblerARM64::supportsDoubleToInt32ConversionUsingJavaScriptSemantics())
2418 m_jit.convertDoubleToInt32UsingJavaScriptSemantics(fpr, resultGpr);
2419 else
2420#endif
2421 {
2422 silentSpillAllRegisters(resultGpr);
2423 callOperation(operationToInt32, resultGpr, fpr);
2424 silentFillAllRegisters();
2425 }
2426
2427 converted.append(m_jit.jump());
2428
2429 isInteger.link(&m_jit);
2430 m_jit.zeroExtend32ToPtr(gpr, resultGpr);
2431
2432 converted.link(&m_jit);
2433#else
2434 Node* childNode = node->child1().node();
2435 VirtualRegister virtualRegister = childNode->virtualRegister();
2436 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
2437
2438 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
2439
2440 GPRReg payloadGPR = op1.payloadGPR();
2441 GPRReg resultGpr = result.gpr();
2442
2443 JITCompiler::JumpList converted;
2444
2445 if (info.registerFormat() == DataFormatJSInt32)
2446 m_jit.move(payloadGPR, resultGpr);
2447 else {
2448 GPRReg tagGPR = op1.tagGPR();
2449 FPRTemporary tempFpr(this);
2450 FPRReg fpr = tempFpr.fpr();
2451 FPRTemporary scratch(this);
2452
2453 JITCompiler::Jump isInteger = m_jit.branchIfInt32(tagGPR);
2454
2455 if (node->child1().useKind() == NumberUse) {
2456 DFG_TYPE_CHECK(
2457 op1.jsValueRegs(), node->child1(), SpecBytecodeNumber,
2458 m_jit.branch32(
2459 MacroAssembler::AboveOrEqual, tagGPR,
2460 TrustedImm32(JSValue::LowestTag)));
2461 } else {
2462 JITCompiler::Jump isNumber = m_jit.branch32(MacroAssembler::Below, tagGPR, TrustedImm32(JSValue::LowestTag));
2463
2464 DFG_TYPE_CHECK(
2465 op1.jsValueRegs(), node->child1(), ~SpecCell,
2466 m_jit.branchIfCell(op1.jsValueRegs()));
2467
2468 // It's not a cell: so true turns into 1 and all else turns into 0.
2469 JITCompiler::Jump isBoolean = m_jit.branchIfBoolean(tagGPR, InvalidGPRReg);
2470 m_jit.move(TrustedImm32(0), resultGpr);
2471 converted.append(m_jit.jump());
2472
2473 isBoolean.link(&m_jit);
2474 m_jit.move(payloadGPR, resultGpr);
2475 converted.append(m_jit.jump());
2476
2477 isNumber.link(&m_jit);
2478 }
2479
2480 unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr());
2481
2482 silentSpillAllRegisters(resultGpr);
2483 callOperation(operationToInt32, resultGpr, fpr);
2484 silentFillAllRegisters();
2485
2486 converted.append(m_jit.jump());
2487
2488 isInteger.link(&m_jit);
2489 m_jit.move(payloadGPR, resultGpr);
2490
2491 converted.link(&m_jit);
2492 }
2493#endif
2494 int32Result(resultGpr, node);
2495 return;
2496 }
2497 case GeneratedOperandTypeUnknown:
2498 RELEASE_ASSERT(!m_compileOkay);
2499 return;
2500 }
2501 RELEASE_ASSERT_NOT_REACHED();
2502 return;
2503 }
2504
2505 default:
2506 ASSERT(!m_compileOkay);
2507 return;
2508 }
2509}
2510
2511void SpeculativeJIT::compileUInt32ToNumber(Node* node)
2512{
2513 if (doesOverflow(node->arithMode())) {
2514 if (enableInt52()) {
2515 SpeculateInt32Operand op1(this, node->child1());
2516 GPRTemporary result(this, Reuse, op1);
2517 m_jit.zeroExtend32ToPtr(op1.gpr(), result.gpr());
2518 strictInt52Result(result.gpr(), node);
2519 return;
2520 }
2521 SpeculateInt32Operand op1(this, node->child1());
2522 FPRTemporary result(this);
2523
2524 GPRReg inputGPR = op1.gpr();
2525 FPRReg outputFPR = result.fpr();
2526
2527 m_jit.convertInt32ToDouble(inputGPR, outputFPR);
2528
2529 JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, inputGPR, TrustedImm32(0));
2530 m_jit.addDouble(JITCompiler::AbsoluteAddress(&AssemblyHelpers::twoToThe32), outputFPR);
2531 positive.link(&m_jit);
2532
2533 doubleResult(outputFPR, node);
2534 return;
2535 }
2536
2537 RELEASE_ASSERT(node->arithMode() == Arith::CheckOverflow);
2538
2539 SpeculateInt32Operand op1(this, node->child1());
2540 GPRTemporary result(this);
2541
2542 m_jit.move(op1.gpr(), result.gpr());
2543
2544 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, result.gpr(), TrustedImm32(0)));
2545
2546 int32Result(result.gpr(), node, op1.format());
2547}
2548
2549void SpeculativeJIT::compileDoubleAsInt32(Node* node)
2550{
2551 SpeculateDoubleOperand op1(this, node->child1());
2552 FPRTemporary scratch(this);
2553 GPRTemporary result(this);
2554
2555 FPRReg valueFPR = op1.fpr();
2556 FPRReg scratchFPR = scratch.fpr();
2557 GPRReg resultGPR = result.gpr();
2558
2559 JITCompiler::JumpList failureCases;
2560 RELEASE_ASSERT(shouldCheckOverflow(node->arithMode()));
2561 m_jit.branchConvertDoubleToInt32(
2562 valueFPR, resultGPR, failureCases, scratchFPR,
2563 shouldCheckNegativeZero(node->arithMode()));
2564 speculationCheck(Overflow, JSValueRegs(), 0, failureCases);
2565
2566 int32Result(resultGPR, node);
2567}
2568
2569void SpeculativeJIT::compileDoubleRep(Node* node)
2570{
2571 switch (node->child1().useKind()) {
2572 case RealNumberUse: {
2573 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
2574 FPRTemporary result(this);
2575
2576 JSValueRegs op1Regs = op1.jsValueRegs();
2577 FPRReg resultFPR = result.fpr();
2578
2579#if USE(JSVALUE64)
2580 GPRTemporary temp(this);
2581 GPRReg tempGPR = temp.gpr();
2582 m_jit.unboxDoubleWithoutAssertions(op1Regs.gpr(), tempGPR, resultFPR);
2583#else
2584 FPRTemporary temp(this);
2585 FPRReg tempFPR = temp.fpr();
2586 unboxDouble(op1Regs.tagGPR(), op1Regs.payloadGPR(), resultFPR, tempFPR);
2587#endif
2588
2589 JITCompiler::Jump done = m_jit.branchIfNotNaN(resultFPR);
2590
2591 DFG_TYPE_CHECK(
2592 op1Regs, node->child1(), SpecBytecodeRealNumber, m_jit.branchIfNotInt32(op1Regs));
2593 m_jit.convertInt32ToDouble(op1Regs.payloadGPR(), resultFPR);
2594
2595 done.link(&m_jit);
2596
2597 doubleResult(resultFPR, node);
2598 return;
2599 }
2600
2601 case NotCellUse:
2602 case NumberUse: {
2603 SpeculatedType possibleTypes = m_state.forNode(node->child1()).m_type;
2604 if (isInt32Speculation(possibleTypes)) {
2605 SpeculateInt32Operand op1(this, node->child1(), ManualOperandSpeculation);
2606 FPRTemporary result(this);
2607 m_jit.convertInt32ToDouble(op1.gpr(), result.fpr());
2608 doubleResult(result.fpr(), node);
2609 return;
2610 }
2611
2612 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
2613 FPRTemporary result(this);
2614
2615#if USE(JSVALUE64)
2616 GPRTemporary temp(this);
2617
2618 GPRReg op1GPR = op1.gpr();
2619 GPRReg tempGPR = temp.gpr();
2620 FPRReg resultFPR = result.fpr();
2621 JITCompiler::JumpList done;
2622
2623 JITCompiler::Jump isInteger = m_jit.branchIfInt32(op1GPR);
2624
2625 if (node->child1().useKind() == NotCellUse) {
2626 JITCompiler::Jump isNumber = m_jit.branchIfNumber(op1GPR);
2627 JITCompiler::Jump isUndefined = m_jit.branchIfUndefined(op1GPR);
2628
2629 static const double zero = 0;
2630 m_jit.loadDouble(TrustedImmPtr(&zero), resultFPR);
2631
2632 JITCompiler::Jump isNull = m_jit.branchIfNull(op1GPR);
2633 done.append(isNull);
2634
2635 DFG_TYPE_CHECK(JSValueRegs(op1GPR), node->child1(), ~SpecCellCheck,
2636 m_jit.branchTest64(JITCompiler::Zero, op1GPR, TrustedImm32(static_cast<int32_t>(TagBitBool))));
2637
2638 JITCompiler::Jump isFalse = m_jit.branch64(JITCompiler::Equal, op1GPR, TrustedImm64(ValueFalse));
2639 static const double one = 1;
2640 m_jit.loadDouble(TrustedImmPtr(&one), resultFPR);
2641 done.append(m_jit.jump());
2642 done.append(isFalse);
2643
2644 isUndefined.link(&m_jit);
2645 static const double NaN = PNaN;
2646 m_jit.loadDouble(TrustedImmPtr(&NaN), resultFPR);
2647 done.append(m_jit.jump());
2648
2649 isNumber.link(&m_jit);
2650 } else if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) {
2651 typeCheck(
2652 JSValueRegs(op1GPR), node->child1(), SpecBytecodeNumber,
2653 m_jit.branchIfNotNumber(op1GPR));
2654 }
2655
2656 unboxDouble(op1GPR, tempGPR, resultFPR);
2657 done.append(m_jit.jump());
2658
2659 isInteger.link(&m_jit);
2660 m_jit.convertInt32ToDouble(op1GPR, resultFPR);
2661 done.link(&m_jit);
2662#else // USE(JSVALUE64) -> this is the 32_64 case
2663 FPRTemporary temp(this);
2664
2665 GPRReg op1TagGPR = op1.tagGPR();
2666 GPRReg op1PayloadGPR = op1.payloadGPR();
2667 FPRReg tempFPR = temp.fpr();
2668 FPRReg resultFPR = result.fpr();
2669 JITCompiler::JumpList done;
2670
2671 JITCompiler::Jump isInteger = m_jit.branchIfInt32(op1TagGPR);
2672
2673 if (node->child1().useKind() == NotCellUse) {
2674 JITCompiler::Jump isNumber = m_jit.branch32(JITCompiler::Below, op1TagGPR, JITCompiler::TrustedImm32(JSValue::LowestTag + 1));
2675 JITCompiler::Jump isUndefined = m_jit.branchIfUndefined(op1TagGPR);
2676
2677 static const double zero = 0;
2678 m_jit.loadDouble(TrustedImmPtr(&zero), resultFPR);
2679
2680 JITCompiler::Jump isNull = m_jit.branchIfNull(op1TagGPR);
2681 done.append(isNull);
2682
2683 DFG_TYPE_CHECK(JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), ~SpecCell, m_jit.branchIfNotBoolean(op1TagGPR, InvalidGPRReg));
2684
2685 JITCompiler::Jump isFalse = m_jit.branchTest32(JITCompiler::Zero, op1PayloadGPR, TrustedImm32(1));
2686 static const double one = 1;
2687 m_jit.loadDouble(TrustedImmPtr(&one), resultFPR);
2688 done.append(m_jit.jump());
2689 done.append(isFalse);
2690
2691 isUndefined.link(&m_jit);
2692 static const double NaN = PNaN;
2693 m_jit.loadDouble(TrustedImmPtr(&NaN), resultFPR);
2694 done.append(m_jit.jump());
2695
2696 isNumber.link(&m_jit);
2697 } else if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) {
2698 // This check fails with Int32Tag, but it is OK since Int32 case is already excluded.
2699 typeCheck(
2700 JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecBytecodeNumber,
2701 m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)));
2702 }
2703
2704 unboxDouble(op1TagGPR, op1PayloadGPR, resultFPR, tempFPR);
2705 done.append(m_jit.jump());
2706
2707 isInteger.link(&m_jit);
2708 m_jit.convertInt32ToDouble(op1PayloadGPR, resultFPR);
2709 done.link(&m_jit);
2710#endif // USE(JSVALUE64)
2711
2712 doubleResult(resultFPR, node);
2713 return;
2714 }
2715
2716#if USE(JSVALUE64)
2717 case Int52RepUse: {
2718 SpeculateStrictInt52Operand value(this, node->child1());
2719 FPRTemporary result(this);
2720
2721 GPRReg valueGPR = value.gpr();
2722 FPRReg resultFPR = result.fpr();
2723
2724 m_jit.convertInt64ToDouble(valueGPR, resultFPR);
2725
2726 doubleResult(resultFPR, node);
2727 return;
2728 }
2729#endif // USE(JSVALUE64)
2730
2731 default:
2732 RELEASE_ASSERT_NOT_REACHED();
2733 return;
2734 }
2735}
2736
2737void SpeculativeJIT::compileValueRep(Node* node)
2738{
2739 switch (node->child1().useKind()) {
2740 case DoubleRepUse: {
2741 SpeculateDoubleOperand value(this, node->child1());
2742 JSValueRegsTemporary result(this);
2743
2744 FPRReg valueFPR = value.fpr();
2745 JSValueRegs resultRegs = result.regs();
2746
2747 // It's very tempting to in-place filter the value to indicate that it's not impure NaN
2748 // anymore. Unfortunately, this would be unsound. If it's a GetLocal or if the value was
2749 // subject to a prior SetLocal, filtering the value would imply that the corresponding
2750 // local was purified.
2751 if (needsTypeCheck(node->child1(), ~SpecDoubleImpureNaN))
2752 m_jit.purifyNaN(valueFPR);
2753
2754 boxDouble(valueFPR, resultRegs);
2755
2756 jsValueResult(resultRegs, node);
2757 return;
2758 }
2759
2760#if USE(JSVALUE64)
2761 case Int52RepUse: {
2762 SpeculateStrictInt52Operand value(this, node->child1());
2763 GPRTemporary result(this);
2764
2765 GPRReg valueGPR = value.gpr();
2766 GPRReg resultGPR = result.gpr();
2767
2768 boxInt52(valueGPR, resultGPR, DataFormatStrictInt52);
2769
2770 jsValueResult(resultGPR, node);
2771 return;
2772 }
2773#endif // USE(JSVALUE64)
2774
2775 default:
2776 RELEASE_ASSERT_NOT_REACHED();
2777 return;
2778 }
2779}
2780
2781static double clampDoubleToByte(double d)
2782{
2783 d += 0.5;
2784 if (!(d > 0))
2785 d = 0;
2786 else if (d > 255)
2787 d = 255;
2788 return d;
2789}
2790
2791static void compileClampIntegerToByte(JITCompiler& jit, GPRReg result)
2792{
2793 MacroAssembler::Jump inBounds = jit.branch32(MacroAssembler::BelowOrEqual, result, JITCompiler::TrustedImm32(0xff));
2794 MacroAssembler::Jump tooBig = jit.branch32(MacroAssembler::GreaterThan, result, JITCompiler::TrustedImm32(0xff));
2795 jit.xorPtr(result, result);
2796 MacroAssembler::Jump clamped = jit.jump();
2797 tooBig.link(&jit);
2798 jit.move(JITCompiler::TrustedImm32(255), result);
2799 clamped.link(&jit);
2800 inBounds.link(&jit);
2801}
2802
2803static void compileClampDoubleToByte(JITCompiler& jit, GPRReg result, FPRReg source, FPRReg scratch)
2804{
2805 // Unordered compare so we pick up NaN
2806 static const double zero = 0;
2807 static const double byteMax = 255;
2808 static const double half = 0.5;
2809 jit.loadDouble(JITCompiler::TrustedImmPtr(&zero), scratch);
2810 MacroAssembler::Jump tooSmall = jit.branchDouble(MacroAssembler::DoubleLessThanOrEqualOrUnordered, source, scratch);
2811 jit.loadDouble(JITCompiler::TrustedImmPtr(&byteMax), scratch);
2812 MacroAssembler::Jump tooBig = jit.branchDouble(MacroAssembler::DoubleGreaterThan, source, scratch);
2813
2814 jit.loadDouble(JITCompiler::TrustedImmPtr(&half), scratch);
2815 // FIXME: This should probably just use a floating point round!
2816 // https://bugs.webkit.org/show_bug.cgi?id=72054
2817 jit.addDouble(source, scratch);
2818 jit.truncateDoubleToInt32(scratch, result);
2819 MacroAssembler::Jump truncatedInt = jit.jump();
2820
2821 tooSmall.link(&jit);
2822 jit.xorPtr(result, result);
2823 MacroAssembler::Jump zeroed = jit.jump();
2824
2825 tooBig.link(&jit);
2826 jit.move(JITCompiler::TrustedImm32(255), result);
2827
2828 truncatedInt.link(&jit);
2829 zeroed.link(&jit);
2830
2831}
2832
2833JITCompiler::Jump SpeculativeJIT::jumpForTypedArrayOutOfBounds(Node* node, GPRReg baseGPR, GPRReg indexGPR)
2834{
2835 if (node->op() == PutByValAlias)
2836 return JITCompiler::Jump();
2837 JSArrayBufferView* view = m_jit.graph().tryGetFoldableView(
2838 m_state.forNode(m_jit.graph().child(node, 0)).m_value, node->arrayMode());
2839 if (view) {
2840 uint32_t length = view->length();
2841 Node* indexNode = m_jit.graph().child(node, 1).node();
2842 if (indexNode->isInt32Constant() && indexNode->asUInt32() < length)
2843 return JITCompiler::Jump();
2844 return m_jit.branch32(
2845 MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Imm32(length));
2846 }
2847 return m_jit.branch32(
2848 MacroAssembler::AboveOrEqual, indexGPR,
2849 MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfLength()));
2850}
2851
2852void SpeculativeJIT::emitTypedArrayBoundsCheck(Node* node, GPRReg baseGPR, GPRReg indexGPR)
2853{
2854 JITCompiler::Jump jump = jumpForTypedArrayOutOfBounds(node, baseGPR, indexGPR);
2855 if (!jump.isSet())
2856 return;
2857 speculationCheck(OutOfBounds, JSValueRegs(), 0, jump);
2858}
2859
2860JITCompiler::Jump SpeculativeJIT::jumpForTypedArrayIsNeuteredIfOutOfBounds(Node* node, GPRReg base, JITCompiler::Jump outOfBounds)
2861{
2862 JITCompiler::Jump done;
2863 if (outOfBounds.isSet()) {
2864 done = m_jit.jump();
2865 if (node->arrayMode().isInBounds())
2866 speculationCheck(OutOfBounds, JSValueSource(), 0, outOfBounds);
2867 else {
2868 outOfBounds.link(&m_jit);
2869
2870 JITCompiler::Jump notWasteful = m_jit.branch32(
2871 MacroAssembler::NotEqual,
2872 MacroAssembler::Address(base, JSArrayBufferView::offsetOfMode()),
2873 TrustedImm32(WastefulTypedArray));
2874
2875 JITCompiler::Jump hasNullVector;
2876#if !GIGACAGE_ENABLED && CPU(ARM64E)
2877 {
2878 GPRReg scratch = m_jit.scratchRegister();
2879 DisallowMacroScratchRegisterUsage disallowScratch(m_jit);
2880
2881 m_jit.loadPtr(MacroAssembler::Address(base, JSArrayBufferView::offsetOfVector()), scratch);
2882 m_jit.removeArrayPtrTag(scratch);
2883 hasNullVector = m_jit.branchTestPtr(MacroAssembler::Zero, scratch);
2884 }
2885#else // !GIGACAGE_ENABLED && CPU(ARM64E)
2886 hasNullVector = m_jit.branchTestPtr(
2887 MacroAssembler::Zero,
2888 MacroAssembler::Address(base, JSArrayBufferView::offsetOfVector()));
2889#endif
2890 speculationCheck(Uncountable, JSValueSource(), node, hasNullVector);
2891 notWasteful.link(&m_jit);
2892 }
2893 }
2894 return done;
2895}
2896
2897void SpeculativeJIT::loadFromIntTypedArray(GPRReg storageReg, GPRReg propertyReg, GPRReg resultReg, TypedArrayType type)
2898{
2899 switch (elementSize(type)) {
2900 case 1:
2901 if (isSigned(type))
2902 m_jit.load8SignedExtendTo32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne), resultReg);
2903 else
2904 m_jit.load8(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne), resultReg);
2905 break;
2906 case 2:
2907 if (isSigned(type))
2908 m_jit.load16SignedExtendTo32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo), resultReg);
2909 else
2910 m_jit.load16(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo), resultReg);
2911 break;
2912 case 4:
2913 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesFour), resultReg);
2914 break;
2915 default:
2916 CRASH();
2917 }
2918}
2919
2920void SpeculativeJIT::setIntTypedArrayLoadResult(Node* node, GPRReg resultReg, TypedArrayType type, bool canSpeculate)
2921{
2922 if (elementSize(type) < 4 || isSigned(type)) {
2923 int32Result(resultReg, node);
2924 return;
2925 }
2926
2927 ASSERT(elementSize(type) == 4 && !isSigned(type));
2928 if (node->shouldSpeculateInt32() && canSpeculate) {
2929 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, resultReg, TrustedImm32(0)));
2930 int32Result(resultReg, node);
2931 return;
2932 }
2933
2934#if USE(JSVALUE64)
2935 if (node->shouldSpeculateInt52()) {
2936 ASSERT(enableInt52());
2937 m_jit.zeroExtend32ToPtr(resultReg, resultReg);
2938 strictInt52Result(resultReg, node);
2939 return;
2940 }
2941#endif
2942
2943 FPRTemporary fresult(this);
2944 m_jit.convertInt32ToDouble(resultReg, fresult.fpr());
2945 JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, resultReg, TrustedImm32(0));
2946 m_jit.addDouble(JITCompiler::AbsoluteAddress(&AssemblyHelpers::twoToThe32), fresult.fpr());
2947 positive.link(&m_jit);
2948 doubleResult(fresult.fpr(), node);
2949}
2950
2951void SpeculativeJIT::compileGetByValOnIntTypedArray(Node* node, TypedArrayType type)
2952{
2953 ASSERT(isInt(type));
2954
2955 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
2956 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
2957 StorageOperand storage(this, m_graph.varArgChild(node, 2));
2958
2959 GPRReg baseReg = base.gpr();
2960 GPRReg propertyReg = property.gpr();
2961 GPRReg storageReg = storage.gpr();
2962
2963 GPRTemporary result(this);
2964 GPRReg resultReg = result.gpr();
2965
2966 ASSERT(node->arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.varArgChild(node, 0))));
2967
2968 emitTypedArrayBoundsCheck(node, baseReg, propertyReg);
2969 loadFromIntTypedArray(storageReg, propertyReg, resultReg, type);
2970 bool canSpeculate = true;
2971 setIntTypedArrayLoadResult(node, resultReg, type, canSpeculate);
2972}
2973
2974bool SpeculativeJIT::getIntTypedArrayStoreOperand(
2975 GPRTemporary& value,
2976 GPRReg property,
2977#if USE(JSVALUE32_64)
2978 GPRTemporary& propertyTag,
2979 GPRTemporary& valueTag,
2980#endif
2981 Edge valueUse, JITCompiler::JumpList& slowPathCases, bool isClamped)
2982{
2983 bool isAppropriateConstant = false;
2984 if (valueUse->isConstant()) {
2985 JSValue jsValue = valueUse->asJSValue();
2986 SpeculatedType expectedType = typeFilterFor(valueUse.useKind());
2987 SpeculatedType actualType = speculationFromValue(jsValue);
2988 isAppropriateConstant = (expectedType | actualType) == expectedType;
2989 }
2990
2991 if (isAppropriateConstant) {
2992 JSValue jsValue = valueUse->asJSValue();
2993 if (!jsValue.isNumber()) {
2994 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
2995 return false;
2996 }
2997 double d = jsValue.asNumber();
2998 if (isClamped)
2999 d = clampDoubleToByte(d);
3000 GPRTemporary scratch(this);
3001 GPRReg scratchReg = scratch.gpr();
3002 m_jit.move(Imm32(toInt32(d)), scratchReg);
3003 value.adopt(scratch);
3004 } else {
3005 switch (valueUse.useKind()) {
3006 case Int32Use: {
3007 SpeculateInt32Operand valueOp(this, valueUse);
3008 GPRTemporary scratch(this);
3009 GPRReg scratchReg = scratch.gpr();
3010 m_jit.move(valueOp.gpr(), scratchReg);
3011 if (isClamped)
3012 compileClampIntegerToByte(m_jit, scratchReg);
3013 value.adopt(scratch);
3014 break;
3015 }
3016
3017#if USE(JSVALUE64)
3018 case Int52RepUse: {
3019 SpeculateStrictInt52Operand valueOp(this, valueUse);
3020 GPRTemporary scratch(this);
3021 GPRReg scratchReg = scratch.gpr();
3022 m_jit.move(valueOp.gpr(), scratchReg);
3023 if (isClamped) {
3024 MacroAssembler::Jump inBounds = m_jit.branch64(
3025 MacroAssembler::BelowOrEqual, scratchReg, JITCompiler::TrustedImm64(0xff));
3026 MacroAssembler::Jump tooBig = m_jit.branch64(
3027 MacroAssembler::GreaterThan, scratchReg, JITCompiler::TrustedImm64(0xff));
3028 m_jit.move(TrustedImm32(0), scratchReg);
3029 MacroAssembler::Jump clamped = m_jit.jump();
3030 tooBig.link(&m_jit);
3031 m_jit.move(JITCompiler::TrustedImm32(255), scratchReg);
3032 clamped.link(&m_jit);
3033 inBounds.link(&m_jit);
3034 }
3035 value.adopt(scratch);
3036 break;
3037 }
3038#endif // USE(JSVALUE64)
3039
3040 case DoubleRepUse: {
3041 RELEASE_ASSERT(!isAtomicsIntrinsic(m_currentNode->op()));
3042 if (isClamped) {
3043 SpeculateDoubleOperand valueOp(this, valueUse);
3044 GPRTemporary result(this);
3045 FPRTemporary floatScratch(this);
3046 FPRReg fpr = valueOp.fpr();
3047 GPRReg gpr = result.gpr();
3048 compileClampDoubleToByte(m_jit, gpr, fpr, floatScratch.fpr());
3049 value.adopt(result);
3050 } else {
3051#if USE(JSVALUE32_64)
3052 GPRTemporary realPropertyTag(this);
3053 propertyTag.adopt(realPropertyTag);
3054 GPRReg propertyTagGPR = propertyTag.gpr();
3055
3056 GPRTemporary realValueTag(this);
3057 valueTag.adopt(realValueTag);
3058 GPRReg valueTagGPR = valueTag.gpr();
3059#endif
3060 SpeculateDoubleOperand valueOp(this, valueUse);
3061 GPRTemporary result(this);
3062 FPRReg fpr = valueOp.fpr();
3063 GPRReg gpr = result.gpr();
3064 MacroAssembler::Jump notNaN = m_jit.branchIfNotNaN(fpr);
3065 m_jit.xorPtr(gpr, gpr);
3066 MacroAssembler::JumpList fixed(m_jit.jump());
3067 notNaN.link(&m_jit);
3068
3069 fixed.append(m_jit.branchTruncateDoubleToInt32(
3070 fpr, gpr, MacroAssembler::BranchIfTruncateSuccessful));
3071
3072#if USE(JSVALUE64)
3073 m_jit.or64(GPRInfo::tagTypeNumberRegister, property);
3074 boxDouble(fpr, gpr);
3075#else
3076 UNUSED_PARAM(property);
3077 m_jit.move(TrustedImm32(JSValue::Int32Tag), propertyTagGPR);
3078 boxDouble(fpr, valueTagGPR, gpr);
3079#endif
3080 slowPathCases.append(m_jit.jump());
3081
3082 fixed.link(&m_jit);
3083 value.adopt(result);
3084 }
3085 break;
3086 }
3087
3088 default:
3089 RELEASE_ASSERT_NOT_REACHED();
3090 break;
3091 }
3092 }
3093 return true;
3094}
3095
3096void SpeculativeJIT::compilePutByValForIntTypedArray(GPRReg base, GPRReg property, Node* node, TypedArrayType type)
3097{
3098 ASSERT(isInt(type));
3099
3100 StorageOperand storage(this, m_jit.graph().varArgChild(node, 3));
3101 GPRReg storageReg = storage.gpr();
3102
3103 Edge valueUse = m_jit.graph().varArgChild(node, 2);
3104
3105 GPRTemporary value;
3106#if USE(JSVALUE32_64)
3107 GPRTemporary propertyTag;
3108 GPRTemporary valueTag;
3109#endif
3110
3111 JITCompiler::JumpList slowPathCases;
3112
3113 bool result = getIntTypedArrayStoreOperand(
3114 value, property,
3115#if USE(JSVALUE32_64)
3116 propertyTag, valueTag,
3117#endif
3118 valueUse, slowPathCases, isClamped(type));
3119 if (!result) {
3120 noResult(node);
3121 return;
3122 }
3123
3124 GPRReg valueGPR = value.gpr();
3125#if USE(JSVALUE32_64)
3126 GPRReg propertyTagGPR = propertyTag.gpr();
3127 GPRReg valueTagGPR = valueTag.gpr();
3128#endif
3129
3130 ASSERT_UNUSED(valueGPR, valueGPR != property);
3131 ASSERT(valueGPR != base);
3132 ASSERT(valueGPR != storageReg);
3133 JITCompiler::Jump outOfBounds = jumpForTypedArrayOutOfBounds(node, base, property);
3134
3135 switch (elementSize(type)) {
3136 case 1:
3137 m_jit.store8(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesOne));
3138 break;
3139 case 2:
3140 m_jit.store16(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesTwo));
3141 break;
3142 case 4:
3143 m_jit.store32(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesFour));
3144 break;
3145 default:
3146 CRASH();
3147 }
3148
3149 JITCompiler::Jump done = jumpForTypedArrayIsNeuteredIfOutOfBounds(node, base, outOfBounds);
3150 if (done.isSet())
3151 done.link(&m_jit);
3152
3153 if (!slowPathCases.empty()) {
3154#if USE(JSVALUE64)
3155 if (node->op() == PutByValDirect) {
3156 addSlowPathGenerator(slowPathCall(
3157 slowPathCases, this,
3158 m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValDirectStrict : operationPutByValDirectNonStrict,
3159 NoResult, base, property, valueGPR));
3160 } else {
3161 addSlowPathGenerator(slowPathCall(
3162 slowPathCases, this,
3163 m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValStrict : operationPutByValNonStrict,
3164 NoResult, base, property, valueGPR));
3165 }
3166#else // not USE(JSVALUE64)
3167 if (node->op() == PutByValDirect) {
3168 addSlowPathGenerator(slowPathCall(
3169 slowPathCases, this,
3170 m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValDirectCellStrict : operationPutByValDirectCellNonStrict,
3171 NoResult, base, JSValueRegs(propertyTagGPR, property), JSValueRegs(valueTagGPR, valueGPR)));
3172 } else {
3173 addSlowPathGenerator(slowPathCall(
3174 slowPathCases, this,
3175 m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValCellStrict : operationPutByValCellNonStrict,
3176 NoResult, base, JSValueRegs(propertyTagGPR, property), JSValueRegs(valueTagGPR, valueGPR)));
3177 }
3178#endif
3179 }
3180
3181 noResult(node);
3182}
3183
3184void SpeculativeJIT::compileGetByValOnFloatTypedArray(Node* node, TypedArrayType type)
3185{
3186 ASSERT(isFloat(type));
3187
3188 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
3189 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
3190 StorageOperand storage(this, m_graph.varArgChild(node, 2));
3191
3192 GPRReg baseReg = base.gpr();
3193 GPRReg propertyReg = property.gpr();
3194 GPRReg storageReg = storage.gpr();
3195
3196 ASSERT(node->arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.varArgChild(node, 0))));
3197
3198 FPRTemporary result(this);
3199 FPRReg resultReg = result.fpr();
3200 emitTypedArrayBoundsCheck(node, baseReg, propertyReg);
3201 switch (elementSize(type)) {
3202 case 4:
3203 m_jit.loadFloat(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesFour), resultReg);
3204 m_jit.convertFloatToDouble(resultReg, resultReg);
3205 break;
3206 case 8: {
3207 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg);
3208 break;
3209 }
3210 default:
3211 RELEASE_ASSERT_NOT_REACHED();
3212 }
3213
3214 doubleResult(resultReg, node);
3215}
3216
3217void SpeculativeJIT::compilePutByValForFloatTypedArray(GPRReg base, GPRReg property, Node* node, TypedArrayType type)
3218{
3219 ASSERT(isFloat(type));
3220
3221 StorageOperand storage(this, m_jit.graph().varArgChild(node, 3));
3222 GPRReg storageReg = storage.gpr();
3223
3224 Edge baseUse = m_jit.graph().varArgChild(node, 0);
3225 Edge valueUse = m_jit.graph().varArgChild(node, 2);
3226
3227 SpeculateDoubleOperand valueOp(this, valueUse);
3228 FPRTemporary scratch(this);
3229 FPRReg valueFPR = valueOp.fpr();
3230 FPRReg scratchFPR = scratch.fpr();
3231
3232 ASSERT_UNUSED(baseUse, node->arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(baseUse)));
3233
3234 MacroAssembler::Jump outOfBounds = jumpForTypedArrayOutOfBounds(node, base, property);
3235
3236 switch (elementSize(type)) {
3237 case 4: {
3238 m_jit.moveDouble(valueFPR, scratchFPR);
3239 m_jit.convertDoubleToFloat(valueFPR, scratchFPR);
3240 m_jit.storeFloat(scratchFPR, MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesFour));
3241 break;
3242 }
3243 case 8:
3244 m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesEight));
3245 break;
3246 default:
3247 RELEASE_ASSERT_NOT_REACHED();
3248 }
3249
3250 JITCompiler::Jump done = jumpForTypedArrayIsNeuteredIfOutOfBounds(node, base, outOfBounds);
3251 if (done.isSet())
3252 done.link(&m_jit);
3253 noResult(node);
3254}
3255
3256void SpeculativeJIT::compileGetByValForObjectWithString(Node* node)
3257{
3258 SpeculateCellOperand arg1(this, m_graph.varArgChild(node, 0));
3259 SpeculateCellOperand arg2(this, m_graph.varArgChild(node, 1));
3260
3261 GPRReg arg1GPR = arg1.gpr();
3262 GPRReg arg2GPR = arg2.gpr();
3263
3264 speculateObject(m_graph.varArgChild(node, 0), arg1GPR);
3265 speculateString(m_graph.varArgChild(node, 1), arg2GPR);
3266
3267 flushRegisters();
3268 JSValueRegsFlushedCallResult result(this);
3269 JSValueRegs resultRegs = result.regs();
3270 callOperation(operationGetByValObjectString, resultRegs, arg1GPR, arg2GPR);
3271 m_jit.exceptionCheck();
3272
3273 jsValueResult(resultRegs, node);
3274}
3275
3276void SpeculativeJIT::compileGetByValForObjectWithSymbol(Node* node)
3277{
3278 SpeculateCellOperand arg1(this, m_graph.varArgChild(node, 0));
3279 SpeculateCellOperand arg2(this, m_graph.varArgChild(node, 1));
3280
3281 GPRReg arg1GPR = arg1.gpr();
3282 GPRReg arg2GPR = arg2.gpr();
3283
3284 speculateObject(m_graph.varArgChild(node, 0), arg1GPR);
3285 speculateSymbol(m_graph.varArgChild(node, 1), arg2GPR);
3286
3287 flushRegisters();
3288 JSValueRegsFlushedCallResult result(this);
3289 JSValueRegs resultRegs = result.regs();
3290 callOperation(operationGetByValObjectSymbol, resultRegs, arg1GPR, arg2GPR);
3291 m_jit.exceptionCheck();
3292
3293 jsValueResult(resultRegs, node);
3294}
3295
3296void SpeculativeJIT::compilePutByValForCellWithString(Node* node, Edge& child1, Edge& child2, Edge& child3)
3297{
3298 SpeculateCellOperand arg1(this, child1);
3299 SpeculateCellOperand arg2(this, child2);
3300 JSValueOperand arg3(this, child3);
3301
3302 GPRReg arg1GPR = arg1.gpr();
3303 GPRReg arg2GPR = arg2.gpr();
3304 JSValueRegs arg3Regs = arg3.jsValueRegs();
3305
3306 speculateString(child2, arg2GPR);
3307
3308 flushRegisters();
3309 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValCellStringStrict : operationPutByValCellStringNonStrict, arg1GPR, arg2GPR, arg3Regs);
3310 m_jit.exceptionCheck();
3311
3312 noResult(node);
3313}
3314
3315void SpeculativeJIT::compilePutByValForCellWithSymbol(Node* node, Edge& child1, Edge& child2, Edge& child3)
3316{
3317 SpeculateCellOperand arg1(this, child1);
3318 SpeculateCellOperand arg2(this, child2);
3319 JSValueOperand arg3(this, child3);
3320
3321 GPRReg arg1GPR = arg1.gpr();
3322 GPRReg arg2GPR = arg2.gpr();
3323 JSValueRegs arg3Regs = arg3.jsValueRegs();
3324
3325 speculateSymbol(child2, arg2GPR);
3326
3327 flushRegisters();
3328 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValCellSymbolStrict : operationPutByValCellSymbolNonStrict, arg1GPR, arg2GPR, arg3Regs);
3329 m_jit.exceptionCheck();
3330
3331 noResult(node);
3332}
3333
3334void SpeculativeJIT::compileGetByValWithThis(Node* node)
3335{
3336 JSValueOperand base(this, node->child1());
3337 JSValueRegs baseRegs = base.jsValueRegs();
3338 JSValueOperand thisValue(this, node->child2());
3339 JSValueRegs thisValueRegs = thisValue.jsValueRegs();
3340 JSValueOperand subscript(this, node->child3());
3341 JSValueRegs subscriptRegs = subscript.jsValueRegs();
3342
3343 flushRegisters();
3344 JSValueRegsFlushedCallResult result(this);
3345 JSValueRegs resultRegs = result.regs();
3346 callOperation(operationGetByValWithThis, resultRegs, baseRegs, thisValueRegs, subscriptRegs);
3347 m_jit.exceptionCheck();
3348
3349 jsValueResult(resultRegs, node);
3350}
3351
3352void SpeculativeJIT::compileCheckTypeInfoFlags(Node* node)
3353{
3354 SpeculateCellOperand base(this, node->child1());
3355
3356 GPRReg baseGPR = base.gpr();
3357
3358 // FIXME: This only works for checking if a single bit is set. If we want to check more
3359 // than one bit at once, we'll need to fix this:
3360 // https://bugs.webkit.org/show_bug.cgi?id=185705
3361 speculationCheck(BadTypeInfoFlags, JSValueRegs(), 0, m_jit.branchTest8(MacroAssembler::Zero, MacroAssembler::Address(baseGPR, JSCell::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(node->typeInfoOperand())));
3362
3363 noResult(node);
3364}
3365
3366void SpeculativeJIT::compileParseInt(Node* node)
3367{
3368 RELEASE_ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == StringUse);
3369 if (node->child2()) {
3370 SpeculateInt32Operand radix(this, node->child2());
3371 GPRReg radixGPR = radix.gpr();
3372 if (node->child1().useKind() == UntypedUse) {
3373 JSValueOperand value(this, node->child1());
3374 JSValueRegs valueRegs = value.jsValueRegs();
3375
3376 flushRegisters();
3377 JSValueRegsFlushedCallResult result(this);
3378 JSValueRegs resultRegs = result.regs();
3379 callOperation(operationParseIntGeneric, resultRegs, valueRegs, radixGPR);
3380 m_jit.exceptionCheck();
3381 jsValueResult(resultRegs, node);
3382 return;
3383 }
3384
3385 SpeculateCellOperand value(this, node->child1());
3386 GPRReg valueGPR = value.gpr();
3387 speculateString(node->child1(), valueGPR);
3388
3389 flushRegisters();
3390 JSValueRegsFlushedCallResult result(this);
3391 JSValueRegs resultRegs = result.regs();
3392 callOperation(operationParseIntString, resultRegs, valueGPR, radixGPR);
3393 m_jit.exceptionCheck();
3394 jsValueResult(resultRegs, node);
3395 return;
3396 }
3397
3398 if (node->child1().useKind() == UntypedUse) {
3399 JSValueOperand value(this, node->child1());
3400 JSValueRegs valueRegs = value.jsValueRegs();
3401
3402 flushRegisters();
3403 JSValueRegsFlushedCallResult result(this);
3404 JSValueRegs resultRegs = result.regs();
3405 callOperation(operationParseIntNoRadixGeneric, resultRegs, valueRegs);
3406 m_jit.exceptionCheck();
3407 jsValueResult(resultRegs, node);
3408 return;
3409 }
3410
3411 SpeculateCellOperand value(this, node->child1());
3412 GPRReg valueGPR = value.gpr();
3413 speculateString(node->child1(), valueGPR);
3414
3415 flushRegisters();
3416 JSValueRegsFlushedCallResult result(this);
3417 JSValueRegs resultRegs = result.regs();
3418 callOperation(operationParseIntStringNoRadix, resultRegs, valueGPR);
3419 m_jit.exceptionCheck();
3420 jsValueResult(resultRegs, node);
3421}
3422
3423void SpeculativeJIT::compileOverridesHasInstance(Node* node)
3424{
3425 Node* hasInstanceValueNode = node->child2().node();
3426 JSFunction* defaultHasInstanceFunction = jsCast<JSFunction*>(node->cellOperand()->value());
3427
3428 MacroAssembler::JumpList notDefault;
3429 SpeculateCellOperand base(this, node->child1());
3430 JSValueOperand hasInstanceValue(this, node->child2());
3431 GPRTemporary result(this);
3432
3433 GPRReg baseGPR = base.gpr();
3434 GPRReg resultGPR = result.gpr();
3435
3436 // It would be great if constant folding handled automatically the case where we knew the hasInstance function
3437 // was a constant. Unfortunately, the folding rule for OverridesHasInstance is in the strength reduction phase
3438 // since it relies on OSR information. https://bugs.webkit.org/show_bug.cgi?id=154832
3439 if (!hasInstanceValueNode->isCellConstant() || defaultHasInstanceFunction != hasInstanceValueNode->asCell()) {
3440 JSValueRegs hasInstanceValueRegs = hasInstanceValue.jsValueRegs();
3441#if USE(JSVALUE64)
3442 notDefault.append(m_jit.branchPtr(MacroAssembler::NotEqual, hasInstanceValueRegs.gpr(), TrustedImmPtr(node->cellOperand())));
3443#else
3444 notDefault.append(m_jit.branchIfNotCell(hasInstanceValueRegs));
3445 notDefault.append(m_jit.branchPtr(MacroAssembler::NotEqual, hasInstanceValueRegs.payloadGPR(), TrustedImmPtr(node->cellOperand())));
3446#endif
3447 }
3448
3449 // Check that base 'ImplementsDefaultHasInstance'.
3450 m_jit.test8(MacroAssembler::Zero, MacroAssembler::Address(baseGPR, JSCell::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(ImplementsDefaultHasInstance), resultGPR);
3451 MacroAssembler::Jump done = m_jit.jump();
3452
3453 if (!notDefault.empty()) {
3454 notDefault.link(&m_jit);
3455 m_jit.move(TrustedImm32(1), resultGPR);
3456 }
3457
3458 done.link(&m_jit);
3459 unblessedBooleanResult(resultGPR, node);
3460}
3461
3462void SpeculativeJIT::compileInstanceOfForCells(Node* node, JSValueRegs valueRegs, JSValueRegs prototypeRegs, GPRReg resultGPR, GPRReg scratchGPR, GPRReg scratch2GPR, JITCompiler::Jump slowCase)
3463{
3464 CallSiteIndex callSiteIndex = m_jit.addCallSite(node->origin.semantic);
3465
3466 JITInstanceOfGenerator gen(
3467 m_jit.codeBlock(), node->origin.semantic, callSiteIndex, usedRegisters(), resultGPR,
3468 valueRegs.payloadGPR(), prototypeRegs.payloadGPR(), scratchGPR, scratch2GPR,
3469 m_state.forNode(node->child2()).isType(SpecObject | ~SpecCell));
3470 gen.generateFastPath(m_jit);
3471
3472 JITCompiler::JumpList slowCases;
3473 slowCases.append(slowCase);
3474
3475 std::unique_ptr<SlowPathGenerator> slowPath = slowPathCall(
3476 slowCases, this, operationInstanceOfOptimize, resultGPR, gen.stubInfo(), valueRegs,
3477 prototypeRegs);
3478
3479 m_jit.addInstanceOf(gen, slowPath.get());
3480 addSlowPathGenerator(WTFMove(slowPath));
3481}
3482
3483void SpeculativeJIT::compileInstanceOf(Node* node)
3484{
3485#if USE(JSVALUE64)
3486 if (node->child1().useKind() == CellUse
3487 && node->child2().useKind() == CellUse) {
3488 SpeculateCellOperand value(this, node->child1());
3489 SpeculateCellOperand prototype(this, node->child2());
3490
3491 GPRTemporary result(this);
3492 GPRTemporary scratch(this);
3493 GPRTemporary scratch2(this);
3494
3495 GPRReg valueGPR = value.gpr();
3496 GPRReg prototypeGPR = prototype.gpr();
3497 GPRReg resultGPR = result.gpr();
3498 GPRReg scratchGPR = scratch.gpr();
3499 GPRReg scratch2GPR = scratch2.gpr();
3500
3501 compileInstanceOfForCells(node, JSValueRegs(valueGPR), JSValueRegs(prototypeGPR), resultGPR, scratchGPR, scratch2GPR);
3502
3503 blessedBooleanResult(resultGPR, node);
3504 return;
3505 }
3506#endif
3507
3508 DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse);
3509 DFG_ASSERT(m_jit.graph(), node, node->child2().useKind() == UntypedUse);
3510
3511 JSValueOperand value(this, node->child1());
3512 JSValueOperand prototype(this, node->child2());
3513
3514 GPRTemporary result(this);
3515 GPRTemporary scratch(this);
3516
3517 JSValueRegs valueRegs = value.jsValueRegs();
3518 JSValueRegs prototypeRegs = prototype.jsValueRegs();
3519
3520 GPRReg resultGPR = result.gpr();
3521 GPRReg scratchGPR = scratch.gpr();
3522
3523 JITCompiler::Jump isCell = m_jit.branchIfCell(valueRegs);
3524 moveFalseTo(resultGPR);
3525
3526 JITCompiler::Jump done = m_jit.jump();
3527
3528 isCell.link(&m_jit);
3529
3530 JITCompiler::Jump slowCase = m_jit.branchIfNotCell(prototypeRegs);
3531
3532 compileInstanceOfForCells(node, valueRegs, prototypeRegs, resultGPR, scratchGPR, InvalidGPRReg, slowCase);
3533
3534 done.link(&m_jit);
3535 blessedBooleanResult(resultGPR, node);
3536 return;
3537}
3538
3539void SpeculativeJIT::compileValueBitNot(Node* node)
3540{
3541 Edge& child1 = node->child1();
3542
3543 if (child1.useKind() == BigIntUse) {
3544 SpeculateCellOperand operand(this, child1);
3545 GPRReg operandGPR = operand.gpr();
3546
3547 speculateBigInt(child1, operandGPR);
3548
3549 flushRegisters();
3550 GPRFlushedCallResult result(this);
3551 GPRReg resultGPR = result.gpr();
3552
3553 callOperation(operationBitNotBigInt, resultGPR, operandGPR);
3554 m_jit.exceptionCheck();
3555 cellResult(resultGPR, node);
3556
3557 return;
3558 }
3559
3560 JSValueOperand operand(this, child1);
3561 JSValueRegs operandRegs = operand.jsValueRegs();
3562
3563 flushRegisters();
3564 JSValueRegsFlushedCallResult result(this);
3565 JSValueRegs resultRegs = result.regs();
3566 callOperation(operationValueBitNot, resultRegs, operandRegs);
3567 m_jit.exceptionCheck();
3568
3569 jsValueResult(resultRegs, node);
3570}
3571
3572void SpeculativeJIT::compileBitwiseNot(Node* node)
3573{
3574 Edge& child1 = node->child1();
3575
3576 SpeculateInt32Operand operand(this, child1);
3577 GPRTemporary result(this);
3578 GPRReg resultGPR = result.gpr();
3579
3580 m_jit.move(operand.gpr(), resultGPR);
3581
3582 m_jit.not32(resultGPR);
3583
3584 int32Result(resultGPR, node);
3585}
3586
3587template<typename SnippetGenerator, J_JITOperation_EJJ snippetSlowPathFunction>
3588void SpeculativeJIT::emitUntypedBitOp(Node* node)
3589{
3590 Edge& leftChild = node->child1();
3591 Edge& rightChild = node->child2();
3592
3593 if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
3594 JSValueOperand left(this, leftChild);
3595 JSValueOperand right(this, rightChild);
3596 JSValueRegs leftRegs = left.jsValueRegs();
3597 JSValueRegs rightRegs = right.jsValueRegs();
3598
3599 flushRegisters();
3600 JSValueRegsFlushedCallResult result(this);
3601 JSValueRegs resultRegs = result.regs();
3602 callOperation(snippetSlowPathFunction, resultRegs, leftRegs, rightRegs);
3603 m_jit.exceptionCheck();
3604
3605 jsValueResult(resultRegs, node);
3606 return;
3607 }
3608
3609 Optional<JSValueOperand> left;
3610 Optional<JSValueOperand> right;
3611
3612 JSValueRegs leftRegs;
3613 JSValueRegs rightRegs;
3614
3615#if USE(JSVALUE64)
3616 GPRTemporary result(this);
3617 JSValueRegs resultRegs = JSValueRegs(result.gpr());
3618 GPRTemporary scratch(this);
3619 GPRReg scratchGPR = scratch.gpr();
3620#else
3621 GPRTemporary resultTag(this);
3622 GPRTemporary resultPayload(this);
3623 JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
3624 GPRReg scratchGPR = resultTag.gpr();
3625#endif
3626
3627 SnippetOperand leftOperand;
3628 SnippetOperand rightOperand;
3629
3630 // The snippet generator does not support both operands being constant. If the left
3631 // operand is already const, we'll ignore the right operand's constness.
3632 if (leftChild->isInt32Constant())
3633 leftOperand.setConstInt32(leftChild->asInt32());
3634 else if (rightChild->isInt32Constant())
3635 rightOperand.setConstInt32(rightChild->asInt32());
3636
3637 RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
3638
3639 if (!leftOperand.isConst()) {
3640 left.emplace(this, leftChild);
3641 leftRegs = left->jsValueRegs();
3642 }
3643 if (!rightOperand.isConst()) {
3644 right.emplace(this, rightChild);
3645 rightRegs = right->jsValueRegs();
3646 }
3647
3648 SnippetGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs, scratchGPR);
3649 gen.generateFastPath(m_jit);
3650
3651 ASSERT(gen.didEmitFastPath());
3652 gen.endJumpList().append(m_jit.jump());
3653
3654 gen.slowPathJumpList().link(&m_jit);
3655 silentSpillAllRegisters(resultRegs);
3656
3657 if (leftOperand.isConst()) {
3658 leftRegs = resultRegs;
3659 m_jit.moveValue(leftChild->asJSValue(), leftRegs);
3660 } else if (rightOperand.isConst()) {
3661 rightRegs = resultRegs;
3662 m_jit.moveValue(rightChild->asJSValue(), rightRegs);
3663 }
3664
3665 callOperation(snippetSlowPathFunction, resultRegs, leftRegs, rightRegs);
3666
3667 silentFillAllRegisters();
3668 m_jit.exceptionCheck();
3669
3670 gen.endJumpList().link(&m_jit);
3671 jsValueResult(resultRegs, node);
3672}
3673
3674void SpeculativeJIT::compileValueBitwiseOp(Node* node)
3675{
3676 NodeType op = node->op();
3677 Edge& leftChild = node->child1();
3678 Edge& rightChild = node->child2();
3679
3680 if (leftChild.useKind() == UntypedUse || rightChild.useKind() == UntypedUse) {
3681 switch (op) {
3682 case ValueBitAnd:
3683 emitUntypedBitOp<JITBitAndGenerator, operationValueBitAnd>(node);
3684 return;
3685 case ValueBitXor:
3686 emitUntypedBitOp<JITBitXorGenerator, operationValueBitXor>(node);
3687 return;
3688 case ValueBitOr:
3689 emitUntypedBitOp<JITBitOrGenerator, operationValueBitOr>(node);
3690 return;
3691 default:
3692 RELEASE_ASSERT_NOT_REACHED();
3693 }
3694 }
3695
3696 ASSERT(leftChild.useKind() == BigIntUse && rightChild.useKind() == BigIntUse);
3697
3698 SpeculateCellOperand left(this, node->child1());
3699 SpeculateCellOperand right(this, node->child2());
3700 GPRReg leftGPR = left.gpr();
3701 GPRReg rightGPR = right.gpr();
3702
3703 speculateBigInt(leftChild, leftGPR);
3704 speculateBigInt(rightChild, rightGPR);
3705
3706 flushRegisters();
3707 GPRFlushedCallResult result(this);
3708 GPRReg resultGPR = result.gpr();
3709
3710 switch (op) {
3711 case ValueBitAnd:
3712 callOperation(operationBitAndBigInt, resultGPR, leftGPR, rightGPR);
3713 break;
3714 case ValueBitXor:
3715 callOperation(operationBitXorBigInt, resultGPR, leftGPR, rightGPR);
3716 break;
3717 case ValueBitOr:
3718 callOperation(operationBitOrBigInt, resultGPR, leftGPR, rightGPR);
3719 break;
3720 default:
3721 RELEASE_ASSERT_NOT_REACHED();
3722 }
3723
3724 m_jit.exceptionCheck();
3725 cellResult(resultGPR, node);
3726}
3727
3728void SpeculativeJIT::compileBitwiseOp(Node* node)
3729{
3730 NodeType op = node->op();
3731 Edge& leftChild = node->child1();
3732 Edge& rightChild = node->child2();
3733
3734 if (leftChild->isInt32Constant()) {
3735 SpeculateInt32Operand op2(this, rightChild);
3736 GPRTemporary result(this, Reuse, op2);
3737
3738 bitOp(op, leftChild->asInt32(), op2.gpr(), result.gpr());
3739
3740 int32Result(result.gpr(), node);
3741 return;
3742 }
3743
3744 if (rightChild->isInt32Constant()) {
3745 SpeculateInt32Operand op1(this, leftChild);
3746 GPRTemporary result(this, Reuse, op1);
3747
3748 bitOp(op, rightChild->asInt32(), op1.gpr(), result.gpr());
3749
3750 int32Result(result.gpr(), node);
3751 return;
3752 }
3753
3754 SpeculateInt32Operand op1(this, leftChild);
3755 SpeculateInt32Operand op2(this, rightChild);
3756 GPRTemporary result(this, Reuse, op1, op2);
3757
3758 GPRReg reg1 = op1.gpr();
3759 GPRReg reg2 = op2.gpr();
3760 bitOp(op, reg1, reg2, result.gpr());
3761
3762 int32Result(result.gpr(), node);
3763}
3764
3765void SpeculativeJIT::emitUntypedRightShiftBitOp(Node* node)
3766{
3767 J_JITOperation_EJJ snippetSlowPathFunction = node->op() == BitRShift
3768 ? operationValueBitRShift : operationValueBitURShift;
3769 JITRightShiftGenerator::ShiftType shiftType = node->op() == BitRShift
3770 ? JITRightShiftGenerator::SignedShift : JITRightShiftGenerator::UnsignedShift;
3771
3772 Edge& leftChild = node->child1();
3773 Edge& rightChild = node->child2();
3774
3775 if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
3776 JSValueOperand left(this, leftChild);
3777 JSValueOperand right(this, rightChild);
3778 JSValueRegs leftRegs = left.jsValueRegs();
3779 JSValueRegs rightRegs = right.jsValueRegs();
3780
3781 flushRegisters();
3782 JSValueRegsFlushedCallResult result(this);
3783 JSValueRegs resultRegs = result.regs();
3784 callOperation(snippetSlowPathFunction, resultRegs, leftRegs, rightRegs);
3785 m_jit.exceptionCheck();
3786
3787 jsValueResult(resultRegs, node);
3788 return;
3789 }
3790
3791 Optional<JSValueOperand> left;
3792 Optional<JSValueOperand> right;
3793
3794 JSValueRegs leftRegs;
3795 JSValueRegs rightRegs;
3796
3797 FPRTemporary leftNumber(this);
3798 FPRReg leftFPR = leftNumber.fpr();
3799
3800#if USE(JSVALUE64)
3801 GPRTemporary result(this);
3802 JSValueRegs resultRegs = JSValueRegs(result.gpr());
3803 GPRTemporary scratch(this);
3804 GPRReg scratchGPR = scratch.gpr();
3805 FPRReg scratchFPR = InvalidFPRReg;
3806#else
3807 GPRTemporary resultTag(this);
3808 GPRTemporary resultPayload(this);
3809 JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
3810 GPRReg scratchGPR = resultTag.gpr();
3811 FPRTemporary fprScratch(this);
3812 FPRReg scratchFPR = fprScratch.fpr();
3813#endif
3814
3815 SnippetOperand leftOperand;
3816 SnippetOperand rightOperand;
3817
3818 // The snippet generator does not support both operands being constant. If the left
3819 // operand is already const, we'll ignore the right operand's constness.
3820 if (leftChild->isInt32Constant())
3821 leftOperand.setConstInt32(leftChild->asInt32());
3822 else if (rightChild->isInt32Constant())
3823 rightOperand.setConstInt32(rightChild->asInt32());
3824
3825 RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
3826
3827 if (!leftOperand.isConst()) {
3828 left.emplace(this, leftChild);
3829 leftRegs = left->jsValueRegs();
3830 }
3831 if (!rightOperand.isConst()) {
3832 right.emplace(this, rightChild);
3833 rightRegs = right->jsValueRegs();
3834 }
3835
3836 JITRightShiftGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs,
3837 leftFPR, scratchGPR, scratchFPR, shiftType);
3838 gen.generateFastPath(m_jit);
3839
3840 ASSERT(gen.didEmitFastPath());
3841 gen.endJumpList().append(m_jit.jump());
3842
3843 gen.slowPathJumpList().link(&m_jit);
3844 silentSpillAllRegisters(resultRegs);
3845
3846 if (leftOperand.isConst()) {
3847 leftRegs = resultRegs;
3848 m_jit.moveValue(leftChild->asJSValue(), leftRegs);
3849 } else if (rightOperand.isConst()) {
3850 rightRegs = resultRegs;
3851 m_jit.moveValue(rightChild->asJSValue(), rightRegs);
3852 }
3853
3854 callOperation(snippetSlowPathFunction, resultRegs, leftRegs, rightRegs);
3855
3856 silentFillAllRegisters();
3857 m_jit.exceptionCheck();
3858
3859 gen.endJumpList().link(&m_jit);
3860 jsValueResult(resultRegs, node);
3861 return;
3862}
3863
3864void SpeculativeJIT::compileShiftOp(Node* node)
3865{
3866 NodeType op = node->op();
3867 Edge& leftChild = node->child1();
3868 Edge& rightChild = node->child2();
3869
3870 if (leftChild.useKind() == UntypedUse || rightChild.useKind() == UntypedUse) {
3871 switch (op) {
3872 case BitLShift:
3873 emitUntypedBitOp<JITLeftShiftGenerator, operationValueBitLShift>(node);
3874 return;
3875 case BitRShift:
3876 case BitURShift:
3877 emitUntypedRightShiftBitOp(node);
3878 return;
3879 default:
3880 RELEASE_ASSERT_NOT_REACHED();
3881 }
3882 }
3883
3884 if (rightChild->isInt32Constant()) {
3885 SpeculateInt32Operand op1(this, leftChild);
3886 GPRTemporary result(this, Reuse, op1);
3887
3888 shiftOp(op, op1.gpr(), rightChild->asInt32() & 0x1f, result.gpr());
3889
3890 int32Result(result.gpr(), node);
3891 } else {
3892 // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.
3893 SpeculateInt32Operand op1(this, leftChild);
3894 SpeculateInt32Operand op2(this, rightChild);
3895 GPRTemporary result(this, Reuse, op1);
3896
3897 GPRReg reg1 = op1.gpr();
3898 GPRReg reg2 = op2.gpr();
3899 shiftOp(op, reg1, reg2, result.gpr());
3900
3901 int32Result(result.gpr(), node);
3902 }
3903}
3904
3905void SpeculativeJIT::compileValueAdd(Node* node)
3906{
3907 Edge& leftChild = node->child1();
3908 Edge& rightChild = node->child2();
3909
3910 if (node->isBinaryUseKind(BigIntUse)) {
3911 SpeculateCellOperand left(this, node->child1());
3912 SpeculateCellOperand right(this, node->child2());
3913 GPRReg leftGPR = left.gpr();
3914 GPRReg rightGPR = right.gpr();
3915
3916 speculateBigInt(leftChild, leftGPR);
3917 speculateBigInt(rightChild, rightGPR);
3918
3919 flushRegisters();
3920 GPRFlushedCallResult result(this);
3921 GPRReg resultGPR = result.gpr();
3922 callOperation(operationAddBigInt, resultGPR, leftGPR, rightGPR);
3923 m_jit.exceptionCheck();
3924
3925 cellResult(resultGPR, node);
3926 return;
3927 }
3928
3929 if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
3930 JSValueOperand left(this, leftChild);
3931 JSValueOperand right(this, rightChild);
3932 JSValueRegs leftRegs = left.jsValueRegs();
3933 JSValueRegs rightRegs = right.jsValueRegs();
3934
3935 flushRegisters();
3936 JSValueRegsFlushedCallResult result(this);
3937 JSValueRegs resultRegs = result.regs();
3938 callOperation(operationValueAddNotNumber, resultRegs, leftRegs, rightRegs);
3939 m_jit.exceptionCheck();
3940
3941 jsValueResult(resultRegs, node);
3942 return;
3943 }
3944
3945#if USE(JSVALUE64)
3946 bool needsScratchGPRReg = true;
3947 bool needsScratchFPRReg = false;
3948#else
3949 bool needsScratchGPRReg = true;
3950 bool needsScratchFPRReg = true;
3951#endif
3952
3953 CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
3954 unsigned bytecodeIndex = node->origin.semantic.bytecodeIndex();
3955 ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(bytecodeIndex);
3956 JITAddIC* addIC = m_jit.codeBlock()->addJITAddIC(arithProfile);
3957 auto repatchingFunction = operationValueAddOptimize;
3958 auto nonRepatchingFunction = operationValueAdd;
3959
3960 compileMathIC(node, addIC, needsScratchGPRReg, needsScratchFPRReg, repatchingFunction, nonRepatchingFunction);
3961}
3962
3963void SpeculativeJIT::compileValueSub(Node* node)
3964{
3965 Edge& leftChild = node->child1();
3966 Edge& rightChild = node->child2();
3967
3968 if (node->binaryUseKind() == UntypedUse) {
3969#if USE(JSVALUE64)
3970 bool needsScratchGPRReg = true;
3971 bool needsScratchFPRReg = false;
3972#else
3973 bool needsScratchGPRReg = true;
3974 bool needsScratchFPRReg = true;
3975#endif
3976
3977 CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
3978 unsigned bytecodeIndex = node->origin.semantic.bytecodeIndex();
3979 ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(bytecodeIndex);
3980 JITSubIC* subIC = m_jit.codeBlock()->addJITSubIC(arithProfile);
3981 auto repatchingFunction = operationValueSubOptimize;
3982 auto nonRepatchingFunction = operationValueSub;
3983
3984 compileMathIC(node, subIC, needsScratchGPRReg, needsScratchFPRReg, repatchingFunction, nonRepatchingFunction);
3985 return;
3986 }
3987
3988 ASSERT(leftChild.useKind() == BigIntUse && rightChild.useKind() == BigIntUse);
3989
3990 SpeculateCellOperand left(this, node->child1());
3991 SpeculateCellOperand right(this, node->child2());
3992 GPRReg leftGPR = left.gpr();
3993 GPRReg rightGPR = right.gpr();
3994
3995 speculateBigInt(leftChild, leftGPR);
3996 speculateBigInt(rightChild, rightGPR);
3997
3998 flushRegisters();
3999 GPRFlushedCallResult result(this);
4000 GPRReg resultGPR = result.gpr();
4001
4002 callOperation(operationSubBigInt, resultGPR, leftGPR, rightGPR);
4003
4004 m_jit.exceptionCheck();
4005 cellResult(resultGPR, node);
4006}
4007
4008template <typename Generator, typename RepatchingFunction, typename NonRepatchingFunction>
4009void SpeculativeJIT::compileMathIC(Node* node, JITBinaryMathIC<Generator>* mathIC, bool needsScratchGPRReg, bool needsScratchFPRReg, RepatchingFunction repatchingFunction, NonRepatchingFunction nonRepatchingFunction)
4010{
4011 Edge& leftChild = node->child1();
4012 Edge& rightChild = node->child2();
4013
4014 Optional<JSValueOperand> left;
4015 Optional<JSValueOperand> right;
4016
4017 JSValueRegs leftRegs;
4018 JSValueRegs rightRegs;
4019
4020 FPRTemporary leftNumber(this);
4021 FPRTemporary rightNumber(this);
4022 FPRReg leftFPR = leftNumber.fpr();
4023 FPRReg rightFPR = rightNumber.fpr();
4024
4025 GPRReg scratchGPR = InvalidGPRReg;
4026 FPRReg scratchFPR = InvalidFPRReg;
4027
4028 Optional<FPRTemporary> fprScratch;
4029 if (needsScratchFPRReg) {
4030 fprScratch.emplace(this);
4031 scratchFPR = fprScratch->fpr();
4032 }
4033
4034#if USE(JSVALUE64)
4035 Optional<GPRTemporary> gprScratch;
4036 if (needsScratchGPRReg) {
4037 gprScratch.emplace(this);
4038 scratchGPR = gprScratch->gpr();
4039 }
4040 GPRTemporary result(this);
4041 JSValueRegs resultRegs = JSValueRegs(result.gpr());
4042#else
4043 GPRTemporary resultTag(this);
4044 GPRTemporary resultPayload(this);
4045 JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
4046 if (needsScratchGPRReg)
4047 scratchGPR = resultRegs.tagGPR();
4048#endif
4049
4050 SnippetOperand leftOperand(m_state.forNode(leftChild).resultType());
4051 SnippetOperand rightOperand(m_state.forNode(rightChild).resultType());
4052
4053 // The snippet generator does not support both operands being constant. If the left
4054 // operand is already const, we'll ignore the right operand's constness.
4055 if (leftChild->isInt32Constant())
4056 leftOperand.setConstInt32(leftChild->asInt32());
4057 else if (rightChild->isInt32Constant())
4058 rightOperand.setConstInt32(rightChild->asInt32());
4059
4060 ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
4061 ASSERT(!(Generator::isLeftOperandValidConstant(leftOperand) && Generator::isRightOperandValidConstant(rightOperand)));
4062
4063 if (!Generator::isLeftOperandValidConstant(leftOperand)) {
4064 left.emplace(this, leftChild);
4065 leftRegs = left->jsValueRegs();
4066 }
4067 if (!Generator::isRightOperandValidConstant(rightOperand)) {
4068 right.emplace(this, rightChild);
4069 rightRegs = right->jsValueRegs();
4070 }
4071
4072#if ENABLE(MATH_IC_STATS)
4073 auto inlineStart = m_jit.label();
4074#endif
4075
4076 Box<MathICGenerationState> addICGenerationState = Box<MathICGenerationState>::create();
4077 mathIC->m_generator = Generator(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs, leftFPR, rightFPR, scratchGPR, scratchFPR);
4078
4079 bool shouldEmitProfiling = false;
4080 bool generatedInline = mathIC->generateInline(m_jit, *addICGenerationState, shouldEmitProfiling);
4081 if (generatedInline) {
4082 ASSERT(!addICGenerationState->slowPathJumps.empty());
4083
4084 Vector<SilentRegisterSavePlan> savePlans;
4085 silentSpillAllRegistersImpl(false, savePlans, resultRegs);
4086
4087 auto done = m_jit.label();
4088
4089 addSlowPathGeneratorLambda([=, savePlans = WTFMove(savePlans)] () {
4090 addICGenerationState->slowPathJumps.link(&m_jit);
4091 addICGenerationState->slowPathStart = m_jit.label();
4092#if ENABLE(MATH_IC_STATS)
4093 auto slowPathStart = m_jit.label();
4094#endif
4095
4096 silentSpill(savePlans);
4097
4098 auto innerLeftRegs = leftRegs;
4099 auto innerRightRegs = rightRegs;
4100 if (Generator::isLeftOperandValidConstant(leftOperand)) {
4101 innerLeftRegs = resultRegs;
4102 m_jit.moveValue(leftChild->asJSValue(), innerLeftRegs);
4103 } else if (Generator::isRightOperandValidConstant(rightOperand)) {
4104 innerRightRegs = resultRegs;
4105 m_jit.moveValue(rightChild->asJSValue(), innerRightRegs);
4106 }
4107
4108 if (addICGenerationState->shouldSlowPathRepatch)
4109 addICGenerationState->slowPathCall = callOperation(bitwise_cast<J_JITOperation_EJJMic>(repatchingFunction), resultRegs, innerLeftRegs, innerRightRegs, TrustedImmPtr(mathIC));
4110 else
4111 addICGenerationState->slowPathCall = callOperation(nonRepatchingFunction, resultRegs, innerLeftRegs, innerRightRegs);
4112
4113 silentFill(savePlans);
4114 m_jit.exceptionCheck();
4115 m_jit.jump().linkTo(done, &m_jit);
4116
4117 m_jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
4118 mathIC->finalizeInlineCode(*addICGenerationState, linkBuffer);
4119 });
4120
4121#if ENABLE(MATH_IC_STATS)
4122 auto slowPathEnd = m_jit.label();
4123 m_jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
4124 size_t size = static_cast<char*>(linkBuffer.locationOf(slowPathEnd).executableAddress()) - static_cast<char*>(linkBuffer.locationOf(slowPathStart).executableAddress());
4125 mathIC->m_generatedCodeSize += size;
4126 });
4127#endif
4128
4129 });
4130 } else {
4131 if (Generator::isLeftOperandValidConstant(leftOperand)) {
4132 left.emplace(this, leftChild);
4133 leftRegs = left->jsValueRegs();
4134 } else if (Generator::isRightOperandValidConstant(rightOperand)) {
4135 right.emplace(this, rightChild);
4136 rightRegs = right->jsValueRegs();
4137 }
4138
4139 flushRegisters();
4140 callOperation(nonRepatchingFunction, resultRegs, leftRegs, rightRegs);
4141 m_jit.exceptionCheck();
4142 }
4143
4144#if ENABLE(MATH_IC_STATS)
4145 auto inlineEnd = m_jit.label();
4146 m_jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
4147 size_t size = static_cast<char*>(linkBuffer.locationOf(inlineEnd).executableAddress()) - static_cast<char*>(linkBuffer.locationOf(inlineStart).executableAddress());
4148 mathIC->m_generatedCodeSize += size;
4149 });
4150#endif
4151
4152 jsValueResult(resultRegs, node);
4153 return;
4154}
4155
4156void SpeculativeJIT::compileInstanceOfCustom(Node* node)
4157{
4158 // We could do something smarter here but this case is currently super rare and unless
4159 // Symbol.hasInstance becomes popular will likely remain that way.
4160
4161 JSValueOperand value(this, node->child1());
4162 SpeculateCellOperand constructor(this, node->child2());
4163 JSValueOperand hasInstanceValue(this, node->child3());
4164 GPRTemporary result(this);
4165
4166 JSValueRegs valueRegs = value.jsValueRegs();
4167 GPRReg constructorGPR = constructor.gpr();
4168 JSValueRegs hasInstanceRegs = hasInstanceValue.jsValueRegs();
4169 GPRReg resultGPR = result.gpr();
4170
4171 MacroAssembler::Jump slowCase = m_jit.jump();
4172
4173 addSlowPathGenerator(slowPathCall(slowCase, this, operationInstanceOfCustom, resultGPR, valueRegs, constructorGPR, hasInstanceRegs));
4174
4175 unblessedBooleanResult(resultGPR, node);
4176}
4177
4178void SpeculativeJIT::compileIsCellWithType(Node* node)
4179{
4180 switch (node->child1().useKind()) {
4181 case UntypedUse: {
4182 JSValueOperand value(this, node->child1());
4183 GPRTemporary result(this, Reuse, value, PayloadWord);
4184
4185 JSValueRegs valueRegs = value.jsValueRegs();
4186 GPRReg resultGPR = result.gpr();
4187
4188 JITCompiler::Jump isNotCell = m_jit.branchIfNotCell(valueRegs);
4189
4190 m_jit.compare8(JITCompiler::Equal,
4191 JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoTypeOffset()),
4192 TrustedImm32(node->queriedType()),
4193 resultGPR);
4194 blessBoolean(resultGPR);
4195 JITCompiler::Jump done = m_jit.jump();
4196
4197 isNotCell.link(&m_jit);
4198 moveFalseTo(resultGPR);
4199
4200 done.link(&m_jit);
4201 blessedBooleanResult(resultGPR, node);
4202 return;
4203 }
4204
4205 case CellUse: {
4206 SpeculateCellOperand cell(this, node->child1());
4207 GPRTemporary result(this, Reuse, cell);
4208
4209 GPRReg cellGPR = cell.gpr();
4210 GPRReg resultGPR = result.gpr();
4211
4212 m_jit.compare8(JITCompiler::Equal,
4213 JITCompiler::Address(cellGPR, JSCell::typeInfoTypeOffset()),
4214 TrustedImm32(node->queriedType()),
4215 resultGPR);
4216 blessBoolean(resultGPR);
4217 blessedBooleanResult(resultGPR, node);
4218 return;
4219 }
4220
4221 default:
4222 RELEASE_ASSERT_NOT_REACHED();
4223 break;
4224 }
4225}
4226
4227void SpeculativeJIT::compileIsTypedArrayView(Node* node)
4228{
4229 JSValueOperand value(this, node->child1());
4230 GPRTemporary result(this, Reuse, value, PayloadWord);
4231
4232 JSValueRegs valueRegs = value.jsValueRegs();
4233 GPRReg resultGPR = result.gpr();
4234
4235 JITCompiler::Jump isNotCell = m_jit.branchIfNotCell(valueRegs);
4236
4237 m_jit.load8(JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoTypeOffset()), resultGPR);
4238 m_jit.sub32(TrustedImm32(FirstTypedArrayType), resultGPR);
4239 m_jit.compare32(JITCompiler::Below,
4240 resultGPR,
4241 TrustedImm32(NumberOfTypedArrayTypesExcludingDataView),
4242 resultGPR);
4243 blessBoolean(resultGPR);
4244 JITCompiler::Jump done = m_jit.jump();
4245
4246 isNotCell.link(&m_jit);
4247 moveFalseTo(resultGPR);
4248
4249 done.link(&m_jit);
4250 blessedBooleanResult(resultGPR, node);
4251}
4252
4253void SpeculativeJIT::compileToObjectOrCallObjectConstructor(Node* node)
4254{
4255 RELEASE_ASSERT(node->child1().useKind() == UntypedUse);
4256
4257 JSValueOperand value(this, node->child1());
4258 GPRTemporary result(this, Reuse, value, PayloadWord);
4259
4260 JSValueRegs valueRegs = value.jsValueRegs();
4261 GPRReg resultGPR = result.gpr();
4262
4263 MacroAssembler::JumpList slowCases;
4264 slowCases.append(m_jit.branchIfNotCell(valueRegs));
4265 slowCases.append(m_jit.branchIfNotObject(valueRegs.payloadGPR()));
4266 m_jit.move(valueRegs.payloadGPR(), resultGPR);
4267
4268 if (node->op() == ToObject)
4269 addSlowPathGenerator(slowPathCall(slowCases, this, operationToObject, resultGPR, m_jit.graph().globalObjectFor(node->origin.semantic), valueRegs, identifierUID(node->identifierNumber())));
4270 else
4271 addSlowPathGenerator(slowPathCall(slowCases, this, operationCallObjectConstructor, resultGPR, TrustedImmPtr(node->cellOperand()), valueRegs));
4272
4273 cellResult(resultGPR, node);
4274}
4275
4276void SpeculativeJIT::compileArithAdd(Node* node)
4277{
4278 switch (node->binaryUseKind()) {
4279 case Int32Use: {
4280 ASSERT(!shouldCheckNegativeZero(node->arithMode()));
4281
4282 if (node->child2()->isInt32Constant()) {
4283 SpeculateInt32Operand op1(this, node->child1());
4284 GPRTemporary result(this, Reuse, op1);
4285
4286 GPRReg gpr1 = op1.gpr();
4287 int32_t imm2 = node->child2()->asInt32();
4288 GPRReg gprResult = result.gpr();
4289
4290 if (!shouldCheckOverflow(node->arithMode())) {
4291 m_jit.add32(Imm32(imm2), gpr1, gprResult);
4292 int32Result(gprResult, node);
4293 return;
4294 }
4295
4296 MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, Imm32(imm2), gprResult);
4297 if (gpr1 == gprResult) {
4298 speculationCheck(Overflow, JSValueRegs(), 0, check,
4299 SpeculationRecovery(SpeculativeAddImmediate, gpr1, imm2));
4300 } else
4301 speculationCheck(Overflow, JSValueRegs(), 0, check);
4302
4303 int32Result(gprResult, node);
4304 return;
4305 }
4306
4307 SpeculateInt32Operand op1(this, node->child1());
4308 SpeculateInt32Operand op2(this, node->child2());
4309 GPRTemporary result(this, Reuse, op1, op2);
4310
4311 GPRReg gpr1 = op1.gpr();
4312 GPRReg gpr2 = op2.gpr();
4313 GPRReg gprResult = result.gpr();
4314
4315 if (!shouldCheckOverflow(node->arithMode()))
4316 m_jit.add32(gpr1, gpr2, gprResult);
4317 else {
4318 MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult);
4319
4320 if (gpr1 == gprResult && gpr2 == gprResult)
4321 speculationCheck(Overflow, JSValueRegs(), 0, check, SpeculationRecovery(SpeculativeAddSelf, gprResult, gpr2));
4322 else if (gpr1 == gprResult)
4323 speculationCheck(Overflow, JSValueRegs(), 0, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2));
4324 else if (gpr2 == gprResult)
4325 speculationCheck(Overflow, JSValueRegs(), 0, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1));
4326 else
4327 speculationCheck(Overflow, JSValueRegs(), 0, check);
4328 }
4329
4330 int32Result(gprResult, node);
4331 return;
4332 }
4333
4334#if USE(JSVALUE64)
4335 case Int52RepUse: {
4336 ASSERT(shouldCheckOverflow(node->arithMode()));
4337 ASSERT(!shouldCheckNegativeZero(node->arithMode()));
4338
4339 // Will we need an overflow check? If we can prove that neither input can be
4340 // Int52 then the overflow check will not be necessary.
4341 if (!m_state.forNode(node->child1()).couldBeType(SpecNonInt32AsInt52)
4342 && !m_state.forNode(node->child2()).couldBeType(SpecNonInt32AsInt52)) {
4343 SpeculateWhicheverInt52Operand op1(this, node->child1());
4344 SpeculateWhicheverInt52Operand op2(this, node->child2(), op1);
4345 GPRTemporary result(this, Reuse, op1);
4346 m_jit.add64(op1.gpr(), op2.gpr(), result.gpr());
4347 int52Result(result.gpr(), node, op1.format());
4348 return;
4349 }
4350
4351 SpeculateInt52Operand op1(this, node->child1());
4352 SpeculateInt52Operand op2(this, node->child2());
4353 GPRTemporary result(this);
4354 m_jit.move(op1.gpr(), result.gpr());
4355 speculationCheck(
4356 Int52Overflow, JSValueRegs(), 0,
4357 m_jit.branchAdd64(MacroAssembler::Overflow, op2.gpr(), result.gpr()));
4358 int52Result(result.gpr(), node);
4359 return;
4360 }
4361#endif // USE(JSVALUE64)
4362
4363 case DoubleRepUse: {
4364 SpeculateDoubleOperand op1(this, node->child1());
4365 SpeculateDoubleOperand op2(this, node->child2());
4366 FPRTemporary result(this, op1, op2);
4367
4368 FPRReg reg1 = op1.fpr();
4369 FPRReg reg2 = op2.fpr();
4370 m_jit.addDouble(reg1, reg2, result.fpr());
4371
4372 doubleResult(result.fpr(), node);
4373 return;
4374 }
4375
4376 default:
4377 RELEASE_ASSERT_NOT_REACHED();
4378 break;
4379 }
4380}
4381
4382void SpeculativeJIT::compileArithAbs(Node* node)
4383{
4384 switch (node->child1().useKind()) {
4385 case Int32Use: {
4386 SpeculateStrictInt32Operand op1(this, node->child1());
4387 GPRTemporary result(this, Reuse, op1);
4388 GPRTemporary scratch(this);
4389
4390 m_jit.move(op1.gpr(), result.gpr());
4391 m_jit.rshift32(result.gpr(), MacroAssembler::TrustedImm32(31), scratch.gpr());
4392 m_jit.add32(scratch.gpr(), result.gpr());
4393 m_jit.xor32(scratch.gpr(), result.gpr());
4394 if (shouldCheckOverflow(node->arithMode()))
4395 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Signed, result.gpr()));
4396 int32Result(result.gpr(), node);
4397 break;
4398 }
4399
4400 case DoubleRepUse: {
4401 SpeculateDoubleOperand op1(this, node->child1());
4402 FPRTemporary result(this);
4403
4404 m_jit.absDouble(op1.fpr(), result.fpr());
4405 doubleResult(result.fpr(), node);
4406 break;
4407 }
4408
4409 default: {
4410 DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse, node->child1().useKind());
4411 JSValueOperand op1(this, node->child1());
4412 JSValueRegs op1Regs = op1.jsValueRegs();
4413 flushRegisters();
4414 FPRResult result(this);
4415 callOperation(operationArithAbs, result.fpr(), op1Regs);
4416 m_jit.exceptionCheck();
4417 doubleResult(result.fpr(), node);
4418 break;
4419 }
4420 }
4421}
4422
4423void SpeculativeJIT::compileArithClz32(Node* node)
4424{
4425 if (node->child1().useKind() == Int32Use || node->child1().useKind() == KnownInt32Use) {
4426 SpeculateInt32Operand value(this, node->child1());
4427 GPRTemporary result(this, Reuse, value);
4428 GPRReg valueReg = value.gpr();
4429 GPRReg resultReg = result.gpr();
4430 m_jit.countLeadingZeros32(valueReg, resultReg);
4431 int32Result(resultReg, node);
4432 return;
4433 }
4434 JSValueOperand op1(this, node->child1());
4435 JSValueRegs op1Regs = op1.jsValueRegs();
4436 GPRTemporary result(this);
4437 GPRReg resultReg = result.gpr();
4438 flushRegisters();
4439 callOperation(operationArithClz32, resultReg, op1Regs);
4440 m_jit.exceptionCheck();
4441 int32Result(resultReg, node);
4442}
4443
4444void SpeculativeJIT::compileArithDoubleUnaryOp(Node* node, double (*doubleFunction)(double), double (*operation)(ExecState*, EncodedJSValue))
4445{
4446 if (node->child1().useKind() == DoubleRepUse) {
4447 SpeculateDoubleOperand op1(this, node->child1());
4448 FPRReg op1FPR = op1.fpr();
4449
4450 flushRegisters();
4451
4452 FPRResult result(this);
4453 callOperation(doubleFunction, result.fpr(), op1FPR);
4454
4455 doubleResult(result.fpr(), node);
4456 return;
4457 }
4458
4459 JSValueOperand op1(this, node->child1());
4460 JSValueRegs op1Regs = op1.jsValueRegs();
4461 flushRegisters();
4462 FPRResult result(this);
4463 callOperation(operation, result.fpr(), op1Regs);
4464 m_jit.exceptionCheck();
4465 doubleResult(result.fpr(), node);
4466}
4467
4468void SpeculativeJIT::compileArithSub(Node* node)
4469{
4470 switch (node->binaryUseKind()) {
4471 case Int32Use: {
4472 ASSERT(!shouldCheckNegativeZero(node->arithMode()));
4473
4474 if (node->child2()->isInt32Constant()) {
4475 SpeculateInt32Operand op1(this, node->child1());
4476 int32_t imm2 = node->child2()->asInt32();
4477 GPRTemporary result(this);
4478
4479 if (!shouldCheckOverflow(node->arithMode())) {
4480 m_jit.move(op1.gpr(), result.gpr());
4481 m_jit.sub32(Imm32(imm2), result.gpr());
4482 } else {
4483 GPRTemporary scratch(this);
4484 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr(), scratch.gpr()));
4485 }
4486
4487 int32Result(result.gpr(), node);
4488 return;
4489 }
4490
4491 if (node->child1()->isInt32Constant()) {
4492 int32_t imm1 = node->child1()->asInt32();
4493 SpeculateInt32Operand op2(this, node->child2());
4494 GPRTemporary result(this);
4495
4496 m_jit.move(Imm32(imm1), result.gpr());
4497 if (!shouldCheckOverflow(node->arithMode()))
4498 m_jit.sub32(op2.gpr(), result.gpr());
4499 else
4500 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchSub32(MacroAssembler::Overflow, op2.gpr(), result.gpr()));
4501
4502 int32Result(result.gpr(), node);
4503 return;
4504 }
4505
4506 SpeculateInt32Operand op1(this, node->child1());
4507 SpeculateInt32Operand op2(this, node->child2());
4508 GPRTemporary result(this);
4509
4510 if (!shouldCheckOverflow(node->arithMode())) {
4511 m_jit.move(op1.gpr(), result.gpr());
4512 m_jit.sub32(op2.gpr(), result.gpr());
4513 } else
4514 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr()));
4515
4516 int32Result(result.gpr(), node);
4517 return;
4518 }
4519
4520#if USE(JSVALUE64)
4521 case Int52RepUse: {
4522 ASSERT(shouldCheckOverflow(node->arithMode()));
4523 ASSERT(!shouldCheckNegativeZero(node->arithMode()));
4524
4525 // Will we need an overflow check? If we can prove that neither input can be
4526 // Int52 then the overflow check will not be necessary.
4527 if (!m_state.forNode(node->child1()).couldBeType(SpecNonInt32AsInt52)
4528 && !m_state.forNode(node->child2()).couldBeType(SpecNonInt32AsInt52)) {
4529 SpeculateWhicheverInt52Operand op1(this, node->child1());
4530 SpeculateWhicheverInt52Operand op2(this, node->child2(), op1);
4531 GPRTemporary result(this, Reuse, op1);
4532 m_jit.move(op1.gpr(), result.gpr());
4533 m_jit.sub64(op2.gpr(), result.gpr());
4534 int52Result(result.gpr(), node, op1.format());
4535 return;
4536 }
4537
4538 SpeculateInt52Operand op1(this, node->child1());
4539 SpeculateInt52Operand op2(this, node->child2());
4540 GPRTemporary result(this);
4541 m_jit.move(op1.gpr(), result.gpr());
4542 speculationCheck(
4543 Int52Overflow, JSValueRegs(), 0,
4544 m_jit.branchSub64(MacroAssembler::Overflow, op2.gpr(), result.gpr()));
4545 int52Result(result.gpr(), node);
4546 return;
4547 }
4548#endif // USE(JSVALUE64)
4549
4550 case DoubleRepUse: {
4551 SpeculateDoubleOperand op1(this, node->child1());
4552 SpeculateDoubleOperand op2(this, node->child2());
4553 FPRTemporary result(this, op1);
4554
4555 FPRReg reg1 = op1.fpr();
4556 FPRReg reg2 = op2.fpr();
4557 m_jit.subDouble(reg1, reg2, result.fpr());
4558
4559 doubleResult(result.fpr(), node);
4560 return;
4561 }
4562
4563 default:
4564 RELEASE_ASSERT_NOT_REACHED();
4565 return;
4566 }
4567}
4568
4569void SpeculativeJIT::compileValueNegate(Node* node)
4570{
4571 CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
4572 unsigned bytecodeIndex = node->origin.semantic.bytecodeIndex();
4573 ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(bytecodeIndex);
4574 JITNegIC* negIC = m_jit.codeBlock()->addJITNegIC(arithProfile);
4575 auto repatchingFunction = operationArithNegateOptimize;
4576 auto nonRepatchingFunction = operationArithNegate;
4577 bool needsScratchGPRReg = true;
4578 compileMathIC(node, negIC, needsScratchGPRReg, repatchingFunction, nonRepatchingFunction);
4579}
4580
4581void SpeculativeJIT::compileArithNegate(Node* node)
4582{
4583 switch (node->child1().useKind()) {
4584 case Int32Use: {
4585 SpeculateInt32Operand op1(this, node->child1());
4586 GPRTemporary result(this);
4587
4588 m_jit.move(op1.gpr(), result.gpr());
4589
4590 // Note: there is no notion of being not used as a number, but someone
4591 // caring about negative zero.
4592
4593 if (!shouldCheckOverflow(node->arithMode()))
4594 m_jit.neg32(result.gpr());
4595 else if (!shouldCheckNegativeZero(node->arithMode()))
4596 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchNeg32(MacroAssembler::Overflow, result.gpr()));
4597 else {
4598 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Zero, result.gpr(), TrustedImm32(0x7fffffff)));
4599 m_jit.neg32(result.gpr());
4600 }
4601
4602 int32Result(result.gpr(), node);
4603 return;
4604 }
4605
4606#if USE(JSVALUE64)
4607 case Int52RepUse: {
4608 ASSERT(shouldCheckOverflow(node->arithMode()));
4609
4610 if (!m_state.forNode(node->child1()).couldBeType(SpecNonInt32AsInt52)) {
4611 SpeculateWhicheverInt52Operand op1(this, node->child1());
4612 GPRTemporary result(this);
4613 GPRReg op1GPR = op1.gpr();
4614 GPRReg resultGPR = result.gpr();
4615 m_jit.move(op1GPR, resultGPR);
4616 m_jit.neg64(resultGPR);
4617 if (shouldCheckNegativeZero(node->arithMode())) {
4618 speculationCheck(
4619 NegativeZero, JSValueRegs(), 0,
4620 m_jit.branchTest64(MacroAssembler::Zero, resultGPR));
4621 }
4622 int52Result(resultGPR, node, op1.format());
4623 return;
4624 }
4625
4626 SpeculateInt52Operand op1(this, node->child1());
4627 GPRTemporary result(this);
4628 GPRReg op1GPR = op1.gpr();
4629 GPRReg resultGPR = result.gpr();
4630 m_jit.move(op1GPR, resultGPR);
4631 speculationCheck(
4632 Int52Overflow, JSValueRegs(), 0,
4633 m_jit.branchNeg64(MacroAssembler::Overflow, resultGPR));
4634 if (shouldCheckNegativeZero(node->arithMode())) {
4635 speculationCheck(
4636 NegativeZero, JSValueRegs(), 0,
4637 m_jit.branchTest64(MacroAssembler::Zero, resultGPR));
4638 }
4639 int52Result(resultGPR, node);
4640 return;
4641 }
4642#endif // USE(JSVALUE64)
4643
4644 case DoubleRepUse: {
4645 SpeculateDoubleOperand op1(this, node->child1());
4646 FPRTemporary result(this);
4647
4648 m_jit.negateDouble(op1.fpr(), result.fpr());
4649
4650 doubleResult(result.fpr(), node);
4651 return;
4652 }
4653
4654 default: {
4655 RELEASE_ASSERT_NOT_REACHED();
4656 }
4657 }
4658}
4659
4660template <typename Generator, typename RepatchingFunction, typename NonRepatchingFunction>
4661void SpeculativeJIT::compileMathIC(Node* node, JITUnaryMathIC<Generator>* mathIC, bool needsScratchGPRReg, RepatchingFunction repatchingFunction, NonRepatchingFunction nonRepatchingFunction)
4662{
4663 GPRReg scratchGPR = InvalidGPRReg;
4664 Optional<GPRTemporary> gprScratch;
4665 if (needsScratchGPRReg) {
4666 gprScratch.emplace(this);
4667 scratchGPR = gprScratch->gpr();
4668 }
4669 JSValueOperand childOperand(this, node->child1());
4670 JSValueRegs childRegs = childOperand.jsValueRegs();
4671#if USE(JSVALUE64)
4672 GPRTemporary result(this, Reuse, childOperand);
4673 JSValueRegs resultRegs(result.gpr());
4674#else
4675 GPRTemporary resultTag(this);
4676 GPRTemporary resultPayload(this);
4677 JSValueRegs resultRegs(resultPayload.gpr(), resultTag.gpr());
4678#endif
4679
4680#if ENABLE(MATH_IC_STATS)
4681 auto inlineStart = m_jit.label();
4682#endif
4683
4684 Box<MathICGenerationState> icGenerationState = Box<MathICGenerationState>::create();
4685 mathIC->m_generator = Generator(resultRegs, childRegs, scratchGPR);
4686
4687 bool shouldEmitProfiling = false;
4688 bool generatedInline = mathIC->generateInline(m_jit, *icGenerationState, shouldEmitProfiling);
4689 if (generatedInline) {
4690 ASSERT(!icGenerationState->slowPathJumps.empty());
4691
4692 Vector<SilentRegisterSavePlan> savePlans;
4693 silentSpillAllRegistersImpl(false, savePlans, resultRegs);
4694
4695 auto done = m_jit.label();
4696
4697 addSlowPathGeneratorLambda([=, savePlans = WTFMove(savePlans)] () {
4698 icGenerationState->slowPathJumps.link(&m_jit);
4699 icGenerationState->slowPathStart = m_jit.label();
4700#if ENABLE(MATH_IC_STATS)
4701 auto slowPathStart = m_jit.label();
4702#endif
4703
4704 silentSpill(savePlans);
4705
4706 if (icGenerationState->shouldSlowPathRepatch)
4707 icGenerationState->slowPathCall = callOperation(bitwise_cast<J_JITOperation_EJMic>(repatchingFunction), resultRegs, childRegs, TrustedImmPtr(mathIC));
4708 else
4709 icGenerationState->slowPathCall = callOperation(nonRepatchingFunction, resultRegs, childRegs);
4710
4711 silentFill(savePlans);
4712 m_jit.exceptionCheck();
4713 m_jit.jump().linkTo(done, &m_jit);
4714
4715 m_jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
4716 mathIC->finalizeInlineCode(*icGenerationState, linkBuffer);
4717 });
4718
4719#if ENABLE(MATH_IC_STATS)
4720 auto slowPathEnd = m_jit.label();
4721 m_jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
4722 size_t size = static_cast<char*>(linkBuffer.locationOf(slowPathEnd).executableAddress()) - static_cast<char*>(linkBuffer.locationOf(slowPathStart).executableAddress());
4723 mathIC->m_generatedCodeSize += size;
4724 });
4725#endif
4726
4727 });
4728 } else {
4729 flushRegisters();
4730 callOperation(nonRepatchingFunction, resultRegs, childRegs);
4731 m_jit.exceptionCheck();
4732 }
4733
4734#if ENABLE(MATH_IC_STATS)
4735 auto inlineEnd = m_jit.label();
4736 m_jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
4737 size_t size = static_cast<char*>(linkBuffer.locationOf(inlineEnd).executableAddress()) - static_cast<char*>(linkBuffer.locationOf(inlineStart).executableAddress());
4738 mathIC->m_generatedCodeSize += size;
4739 });
4740#endif
4741
4742 jsValueResult(resultRegs, node);
4743 return;
4744}
4745
4746void SpeculativeJIT::compileValueMul(Node* node)
4747{
4748 Edge& leftChild = node->child1();
4749 Edge& rightChild = node->child2();
4750
4751 if (leftChild.useKind() == BigIntUse && rightChild.useKind() == BigIntUse) {
4752 SpeculateCellOperand left(this, leftChild);
4753 SpeculateCellOperand right(this, rightChild);
4754 GPRReg leftGPR = left.gpr();
4755 GPRReg rightGPR = right.gpr();
4756
4757 speculateBigInt(leftChild, leftGPR);
4758 speculateBigInt(rightChild, rightGPR);
4759
4760 flushRegisters();
4761 GPRFlushedCallResult result(this);
4762 GPRReg resultGPR = result.gpr();
4763
4764 callOperation(operationMulBigInt, resultGPR, leftGPR, rightGPR);
4765
4766 m_jit.exceptionCheck();
4767 cellResult(resultGPR, node);
4768 return;
4769 }
4770
4771 if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
4772 JSValueOperand left(this, leftChild);
4773 JSValueOperand right(this, rightChild);
4774 JSValueRegs leftRegs = left.jsValueRegs();
4775 JSValueRegs rightRegs = right.jsValueRegs();
4776
4777 flushRegisters();
4778 JSValueRegsFlushedCallResult result(this);
4779 JSValueRegs resultRegs = result.regs();
4780 callOperation(operationValueMul, resultRegs, leftRegs, rightRegs);
4781 m_jit.exceptionCheck();
4782
4783 jsValueResult(resultRegs, node);
4784 return;
4785 }
4786
4787 bool needsScratchGPRReg = true;
4788#if USE(JSVALUE64)
4789 bool needsScratchFPRReg = false;
4790#else
4791 bool needsScratchFPRReg = true;
4792#endif
4793
4794 CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
4795 unsigned bytecodeIndex = node->origin.semantic.bytecodeIndex();
4796 ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(bytecodeIndex);
4797 JITMulIC* mulIC = m_jit.codeBlock()->addJITMulIC(arithProfile);
4798 auto repatchingFunction = operationValueMulOptimize;
4799 auto nonRepatchingFunction = operationValueMul;
4800
4801 compileMathIC(node, mulIC, needsScratchGPRReg, needsScratchFPRReg, repatchingFunction, nonRepatchingFunction);
4802}
4803
4804void SpeculativeJIT::compileArithMul(Node* node)
4805{
4806 switch (node->binaryUseKind()) {
4807 case Int32Use: {
4808 if (node->child2()->isInt32Constant()) {
4809 SpeculateInt32Operand op1(this, node->child1());
4810 GPRTemporary result(this);
4811
4812 int32_t imm = node->child2()->asInt32();
4813 GPRReg op1GPR = op1.gpr();
4814 GPRReg resultGPR = result.gpr();
4815
4816 if (!shouldCheckOverflow(node->arithMode()))
4817 m_jit.mul32(Imm32(imm), op1GPR, resultGPR);
4818 else {
4819 speculationCheck(Overflow, JSValueRegs(), 0,
4820 m_jit.branchMul32(MacroAssembler::Overflow, op1GPR, Imm32(imm), resultGPR));
4821 }
4822
4823 // The only way to create negative zero with a constant is:
4824 // -negative-op1 * 0.
4825 // -zero-op1 * negative constant.
4826 if (shouldCheckNegativeZero(node->arithMode())) {
4827 if (!imm)
4828 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Signed, op1GPR));
4829 else if (imm < 0) {
4830 if (shouldCheckOverflow(node->arithMode()))
4831 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Zero, resultGPR));
4832 else
4833 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Zero, op1GPR));
4834 }
4835 }
4836
4837 int32Result(resultGPR, node);
4838 return;
4839 }
4840 SpeculateInt32Operand op1(this, node->child1());
4841 SpeculateInt32Operand op2(this, node->child2());
4842 GPRTemporary result(this);
4843
4844 GPRReg reg1 = op1.gpr();
4845 GPRReg reg2 = op2.gpr();
4846
4847 // We can perform truncated multiplications if we get to this point, because if the
4848 // fixup phase could not prove that it would be safe, it would have turned us into
4849 // a double multiplication.
4850 if (!shouldCheckOverflow(node->arithMode()))
4851 m_jit.mul32(reg1, reg2, result.gpr());
4852 else {
4853 speculationCheck(
4854 Overflow, JSValueRegs(), 0,
4855 m_jit.branchMul32(MacroAssembler::Overflow, reg1, reg2, result.gpr()));
4856 }
4857
4858 // Check for negative zero, if the users of this node care about such things.
4859 if (shouldCheckNegativeZero(node->arithMode())) {
4860 MacroAssembler::Jump resultNonZero = m_jit.branchTest32(MacroAssembler::NonZero, result.gpr());
4861 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Signed, reg1));
4862 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Signed, reg2));
4863 resultNonZero.link(&m_jit);
4864 }
4865
4866 int32Result(result.gpr(), node);
4867 return;
4868 }
4869
4870#if USE(JSVALUE64)
4871 case Int52RepUse: {
4872 ASSERT(shouldCheckOverflow(node->arithMode()));
4873
4874 // This is super clever. We want to do an int52 multiplication and check the
4875 // int52 overflow bit. There is no direct hardware support for this, but we do
4876 // have the ability to do an int64 multiplication and check the int64 overflow
4877 // bit. We leverage that. Consider that a, b are int52 numbers inside int64
4878 // registers, with the high 12 bits being sign-extended. We can do:
4879 //
4880 // (a * (b << 12))
4881 //
4882 // This will give us a left-shifted int52 (value is in high 52 bits, low 16
4883 // bits are zero) plus the int52 overflow bit. I.e. whether this 64-bit
4884 // multiplication overflows is identical to whether the 'a * b' 52-bit
4885 // multiplication overflows.
4886 //
4887 // In our nomenclature, this is:
4888 //
4889 // strictInt52(a) * int52(b) => int52
4890 //
4891 // That is "strictInt52" means unshifted and "int52" means left-shifted by 16
4892 // bits.
4893 //
4894 // We don't care which of op1 or op2 serves as the left-shifted operand, so
4895 // we just do whatever is more convenient for op1 and have op2 do the
4896 // opposite. This ensures that we do at most one shift.
4897
4898 SpeculateWhicheverInt52Operand op1(this, node->child1());
4899 SpeculateWhicheverInt52Operand op2(this, node->child2(), OppositeShift, op1);
4900 GPRTemporary result(this);
4901
4902 GPRReg op1GPR = op1.gpr();
4903 GPRReg op2GPR = op2.gpr();
4904 GPRReg resultGPR = result.gpr();
4905
4906 m_jit.move(op1GPR, resultGPR);
4907 speculationCheck(
4908 Int52Overflow, JSValueRegs(), 0,
4909 m_jit.branchMul64(MacroAssembler::Overflow, op2GPR, resultGPR));
4910
4911 if (shouldCheckNegativeZero(node->arithMode())) {
4912 MacroAssembler::Jump resultNonZero = m_jit.branchTest64(
4913 MacroAssembler::NonZero, resultGPR);
4914 speculationCheck(
4915 NegativeZero, JSValueRegs(), 0,
4916 m_jit.branch64(MacroAssembler::LessThan, op1GPR, TrustedImm32(0)));
4917 speculationCheck(
4918 NegativeZero, JSValueRegs(), 0,
4919 m_jit.branch64(MacroAssembler::LessThan, op2GPR, TrustedImm32(0)));
4920 resultNonZero.link(&m_jit);
4921 }
4922
4923 int52Result(resultGPR, node);
4924 return;
4925 }
4926#endif // USE(JSVALUE64)
4927
4928 case DoubleRepUse: {
4929 SpeculateDoubleOperand op1(this, node->child1());
4930 SpeculateDoubleOperand op2(this, node->child2());
4931 FPRTemporary result(this, op1, op2);
4932
4933 FPRReg reg1 = op1.fpr();
4934 FPRReg reg2 = op2.fpr();
4935
4936 m_jit.mulDouble(reg1, reg2, result.fpr());
4937
4938 doubleResult(result.fpr(), node);
4939 return;
4940 }
4941
4942 default:
4943 RELEASE_ASSERT_NOT_REACHED();
4944 return;
4945 }
4946}
4947
4948void SpeculativeJIT::compileValueDiv(Node* node)
4949{
4950 Edge& leftChild = node->child1();
4951 Edge& rightChild = node->child2();
4952
4953 if (leftChild.useKind() == BigIntUse && rightChild.useKind() == BigIntUse) {
4954 SpeculateCellOperand left(this, leftChild);
4955 SpeculateCellOperand right(this, rightChild);
4956 GPRReg leftGPR = left.gpr();
4957 GPRReg rightGPR = right.gpr();
4958
4959 speculateBigInt(leftChild, leftGPR);
4960 speculateBigInt(rightChild, rightGPR);
4961
4962 flushRegisters();
4963 GPRFlushedCallResult result(this);
4964 GPRReg resultGPR = result.gpr();
4965
4966 callOperation(operationDivBigInt, resultGPR, leftGPR, rightGPR);
4967
4968 m_jit.exceptionCheck();
4969 cellResult(resultGPR, node);
4970 return;
4971 }
4972
4973 if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
4974 JSValueOperand left(this, leftChild);
4975 JSValueOperand right(this, rightChild);
4976 JSValueRegs leftRegs = left.jsValueRegs();
4977 JSValueRegs rightRegs = right.jsValueRegs();
4978
4979 flushRegisters();
4980 JSValueRegsFlushedCallResult result(this);
4981 JSValueRegs resultRegs = result.regs();
4982 callOperation(operationValueDiv, resultRegs, leftRegs, rightRegs);
4983 m_jit.exceptionCheck();
4984
4985 jsValueResult(resultRegs, node);
4986 return;
4987 }
4988
4989 Optional<JSValueOperand> left;
4990 Optional<JSValueOperand> right;
4991
4992 JSValueRegs leftRegs;
4993 JSValueRegs rightRegs;
4994
4995 FPRTemporary leftNumber(this);
4996 FPRTemporary rightNumber(this);
4997 FPRReg leftFPR = leftNumber.fpr();
4998 FPRReg rightFPR = rightNumber.fpr();
4999 FPRTemporary fprScratch(this);
5000 FPRReg scratchFPR = fprScratch.fpr();
5001
5002#if USE(JSVALUE64)
5003 GPRTemporary result(this);
5004 JSValueRegs resultRegs = JSValueRegs(result.gpr());
5005 GPRTemporary scratch(this);
5006 GPRReg scratchGPR = scratch.gpr();
5007#else
5008 GPRTemporary resultTag(this);
5009 GPRTemporary resultPayload(this);
5010 JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
5011 GPRReg scratchGPR = resultTag.gpr();
5012#endif
5013
5014 SnippetOperand leftOperand(m_state.forNode(leftChild).resultType());
5015 SnippetOperand rightOperand(m_state.forNode(rightChild).resultType());
5016
5017 if (leftChild->isInt32Constant())
5018 leftOperand.setConstInt32(leftChild->asInt32());
5019#if USE(JSVALUE64)
5020 else if (leftChild->isDoubleConstant())
5021 leftOperand.setConstDouble(leftChild->asNumber());
5022#endif
5023
5024 if (leftOperand.isConst()) {
5025 // The snippet generator only supports 1 argument as a constant.
5026 // Ignore the rightChild's const-ness.
5027 } else if (rightChild->isInt32Constant())
5028 rightOperand.setConstInt32(rightChild->asInt32());
5029#if USE(JSVALUE64)
5030 else if (rightChild->isDoubleConstant())
5031 rightOperand.setConstDouble(rightChild->asNumber());
5032#endif
5033
5034 RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
5035
5036 if (!leftOperand.isConst()) {
5037 left.emplace(this, leftChild);
5038 leftRegs = left->jsValueRegs();
5039 }
5040 if (!rightOperand.isConst()) {
5041 right.emplace(this, rightChild);
5042 rightRegs = right->jsValueRegs();
5043 }
5044
5045 JITDivGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs,
5046 leftFPR, rightFPR, scratchGPR, scratchFPR);
5047 gen.generateFastPath(m_jit);
5048
5049 ASSERT(gen.didEmitFastPath());
5050 gen.endJumpList().append(m_jit.jump());
5051
5052 gen.slowPathJumpList().link(&m_jit);
5053 silentSpillAllRegisters(resultRegs);
5054
5055 if (leftOperand.isConst()) {
5056 leftRegs = resultRegs;
5057 m_jit.moveValue(leftChild->asJSValue(), leftRegs);
5058 }
5059 if (rightOperand.isConst()) {
5060 rightRegs = resultRegs;
5061 m_jit.moveValue(rightChild->asJSValue(), rightRegs);
5062 }
5063
5064 callOperation(operationValueDiv, resultRegs, leftRegs, rightRegs);
5065
5066 silentFillAllRegisters();
5067 m_jit.exceptionCheck();
5068
5069 gen.endJumpList().link(&m_jit);
5070 jsValueResult(resultRegs, node);
5071}
5072
5073void SpeculativeJIT::compileArithDiv(Node* node)
5074{
5075 switch (node->binaryUseKind()) {
5076 case Int32Use: {
5077#if CPU(X86) || CPU(X86_64)
5078 SpeculateInt32Operand op1(this, node->child1());
5079 SpeculateInt32Operand op2(this, node->child2());
5080 GPRTemporary eax(this, X86Registers::eax);
5081 GPRTemporary edx(this, X86Registers::edx);
5082 GPRReg op1GPR = op1.gpr();
5083 GPRReg op2GPR = op2.gpr();
5084
5085 GPRReg op2TempGPR;
5086 GPRReg temp;
5087 if (op2GPR == X86Registers::eax || op2GPR == X86Registers::edx) {
5088 op2TempGPR = allocate();
5089 temp = op2TempGPR;
5090 } else {
5091 op2TempGPR = InvalidGPRReg;
5092 if (op1GPR == X86Registers::eax)
5093 temp = X86Registers::edx;
5094 else
5095 temp = X86Registers::eax;
5096 }
5097
5098 ASSERT(temp != op1GPR);
5099 ASSERT(temp != op2GPR);
5100
5101 m_jit.add32(JITCompiler::TrustedImm32(1), op2GPR, temp);
5102
5103 JITCompiler::Jump safeDenominator = m_jit.branch32(JITCompiler::Above, temp, JITCompiler::TrustedImm32(1));
5104
5105 JITCompiler::JumpList done;
5106 if (shouldCheckOverflow(node->arithMode())) {
5107 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, op2GPR));
5108 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(JITCompiler::Equal, op1GPR, TrustedImm32(-2147483647-1)));
5109 } else {
5110 // This is the case where we convert the result to an int after we're done, and we
5111 // already know that the denominator is either -1 or 0. So, if the denominator is
5112 // zero, then the result should be zero. If the denominator is not zero (i.e. it's
5113 // -1) and the numerator is -2^31 then the result should be -2^31. Otherwise we
5114 // are happy to fall through to a normal division, since we're just dividing
5115 // something by negative 1.
5116
5117 JITCompiler::Jump notZero = m_jit.branchTest32(JITCompiler::NonZero, op2GPR);
5118 m_jit.move(TrustedImm32(0), eax.gpr());
5119 done.append(m_jit.jump());
5120
5121 notZero.link(&m_jit);
5122 JITCompiler::Jump notNeg2ToThe31 =
5123 m_jit.branch32(JITCompiler::NotEqual, op1GPR, TrustedImm32(-2147483647-1));
5124 m_jit.zeroExtend32ToPtr(op1GPR, eax.gpr());
5125 done.append(m_jit.jump());
5126
5127 notNeg2ToThe31.link(&m_jit);
5128 }
5129
5130 safeDenominator.link(&m_jit);
5131
5132 // If the user cares about negative zero, then speculate that we're not about
5133 // to produce negative zero.
5134 if (shouldCheckNegativeZero(node->arithMode())) {
5135 MacroAssembler::Jump numeratorNonZero = m_jit.branchTest32(MacroAssembler::NonZero, op1GPR);
5136 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, op2GPR, TrustedImm32(0)));
5137 numeratorNonZero.link(&m_jit);
5138 }
5139
5140 if (op2TempGPR != InvalidGPRReg) {
5141 m_jit.move(op2GPR, op2TempGPR);
5142 op2GPR = op2TempGPR;
5143 }
5144
5145 m_jit.move(op1GPR, eax.gpr());
5146 m_jit.x86ConvertToDoubleWord32();
5147 m_jit.x86Div32(op2GPR);
5148
5149 if (op2TempGPR != InvalidGPRReg)
5150 unlock(op2TempGPR);
5151
5152 // Check that there was no remainder. If there had been, then we'd be obligated to
5153 // produce a double result instead.
5154 if (shouldCheckOverflow(node->arithMode()))
5155 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::NonZero, edx.gpr()));
5156
5157 done.link(&m_jit);
5158 int32Result(eax.gpr(), node);
5159#elif HAVE(ARM_IDIV_INSTRUCTIONS) || CPU(ARM64)
5160 SpeculateInt32Operand op1(this, node->child1());
5161 SpeculateInt32Operand op2(this, node->child2());
5162 GPRReg op1GPR = op1.gpr();
5163 GPRReg op2GPR = op2.gpr();
5164 GPRTemporary quotient(this);
5165 GPRTemporary multiplyAnswer(this);
5166
5167 // If the user cares about negative zero, then speculate that we're not about
5168 // to produce negative zero.
5169 if (shouldCheckNegativeZero(node->arithMode())) {
5170 MacroAssembler::Jump numeratorNonZero = m_jit.branchTest32(MacroAssembler::NonZero, op1GPR);
5171 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, op2GPR, TrustedImm32(0)));
5172 numeratorNonZero.link(&m_jit);
5173 }
5174
5175 if (shouldCheckOverflow(node->arithMode()))
5176 speculationCheck(Overflow, JSValueRegs(), nullptr, m_jit.branchTest32(MacroAssembler::Zero, op2GPR));
5177
5178 m_jit.assembler().sdiv<32>(quotient.gpr(), op1GPR, op2GPR);
5179
5180 // Check that there was no remainder. If there had been, then we'd be obligated to
5181 // produce a double result instead.
5182 if (shouldCheckOverflow(node->arithMode())) {
5183 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchMul32(JITCompiler::Overflow, quotient.gpr(), op2GPR, multiplyAnswer.gpr()));
5184 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(JITCompiler::NotEqual, multiplyAnswer.gpr(), op1GPR));
5185 }
5186
5187 int32Result(quotient.gpr(), node);
5188#else
5189 RELEASE_ASSERT_NOT_REACHED();
5190#endif
5191 break;
5192 }
5193
5194 case DoubleRepUse: {
5195 SpeculateDoubleOperand op1(this, node->child1());
5196 SpeculateDoubleOperand op2(this, node->child2());
5197 FPRTemporary result(this, op1);
5198
5199 FPRReg reg1 = op1.fpr();
5200 FPRReg reg2 = op2.fpr();
5201 m_jit.divDouble(reg1, reg2, result.fpr());
5202
5203 doubleResult(result.fpr(), node);
5204 break;
5205 }
5206
5207 default:
5208 RELEASE_ASSERT_NOT_REACHED();
5209 break;
5210 }
5211}
5212
5213void SpeculativeJIT::compileArithFRound(Node* node)
5214{
5215 if (node->child1().useKind() == DoubleRepUse) {
5216 SpeculateDoubleOperand op1(this, node->child1());
5217 FPRTemporary result(this, op1);
5218 m_jit.convertDoubleToFloat(op1.fpr(), result.fpr());
5219 m_jit.convertFloatToDouble(result.fpr(), result.fpr());
5220 doubleResult(result.fpr(), node);
5221 return;
5222 }
5223
5224 JSValueOperand op1(this, node->child1());
5225 JSValueRegs op1Regs = op1.jsValueRegs();
5226 flushRegisters();
5227 FPRResult result(this);
5228 callOperation(operationArithFRound, result.fpr(), op1Regs);
5229 m_jit.exceptionCheck();
5230 doubleResult(result.fpr(), node);
5231}
5232
5233void SpeculativeJIT::compileValueMod(Node* node)
5234{
5235 Edge& leftChild = node->child1();
5236 Edge& rightChild = node->child2();
5237
5238 if (node->binaryUseKind() == BigIntUse) {
5239 SpeculateCellOperand left(this, leftChild);
5240 SpeculateCellOperand right(this, rightChild);
5241 GPRReg leftGPR = left.gpr();
5242 GPRReg rightGPR = right.gpr();
5243
5244 speculateBigInt(leftChild, leftGPR);
5245 speculateBigInt(rightChild, rightGPR);
5246
5247 flushRegisters();
5248 GPRFlushedCallResult result(this);
5249 GPRReg resultGPR = result.gpr();
5250
5251 callOperation(operationModBigInt, resultGPR, leftGPR, rightGPR);
5252
5253 m_jit.exceptionCheck();
5254 cellResult(resultGPR, node);
5255 return;
5256 }
5257
5258 DFG_ASSERT(m_jit.graph(), node, node->binaryUseKind() == UntypedUse, node->binaryUseKind());
5259 JSValueOperand op1(this, leftChild);
5260 JSValueOperand op2(this, rightChild);
5261 JSValueRegs op1Regs = op1.jsValueRegs();
5262 JSValueRegs op2Regs = op2.jsValueRegs();
5263 flushRegisters();
5264 JSValueRegsFlushedCallResult result(this);
5265 JSValueRegs resultRegs = result.regs();
5266 callOperation(operationValueMod, resultRegs, op1Regs, op2Regs);
5267 m_jit.exceptionCheck();
5268 jsValueResult(resultRegs, node);
5269}
5270
5271void SpeculativeJIT::compileArithMod(Node* node)
5272{
5273 switch (node->binaryUseKind()) {
5274 case Int32Use: {
5275 // In the fast path, the dividend value could be the final result
5276 // (in case of |dividend| < |divisor|), so we speculate it as strict int32.
5277 SpeculateStrictInt32Operand op1(this, node->child1());
5278
5279 if (node->child2()->isInt32Constant()) {
5280 int32_t divisor = node->child2()->asInt32();
5281 if (divisor > 1 && hasOneBitSet(divisor)) {
5282 unsigned logarithm = WTF::fastLog2(static_cast<uint32_t>(divisor));
5283 GPRReg dividendGPR = op1.gpr();
5284 GPRTemporary result(this);
5285 GPRReg resultGPR = result.gpr();
5286
5287 // This is what LLVM generates. It's pretty crazy. Here's my
5288 // attempt at understanding it.
5289
5290 // First, compute either divisor - 1, or 0, depending on whether
5291 // the dividend is negative:
5292 //
5293 // If dividend < 0: resultGPR = divisor - 1
5294 // If dividend >= 0: resultGPR = 0
5295 m_jit.move(dividendGPR, resultGPR);
5296 m_jit.rshift32(TrustedImm32(31), resultGPR);
5297 m_jit.urshift32(TrustedImm32(32 - logarithm), resultGPR);
5298
5299 // Add in the dividend, so that:
5300 //
5301 // If dividend < 0: resultGPR = dividend + divisor - 1
5302 // If dividend >= 0: resultGPR = dividend
5303 m_jit.add32(dividendGPR, resultGPR);
5304
5305 // Mask so as to only get the *high* bits. This rounds down
5306 // (towards negative infinity) resultGPR to the nearest multiple
5307 // of divisor, so that:
5308 //
5309 // If dividend < 0: resultGPR = floor((dividend + divisor - 1) / divisor)
5310 // If dividend >= 0: resultGPR = floor(dividend / divisor)
5311 //
5312 // Note that this can be simplified to:
5313 //
5314 // If dividend < 0: resultGPR = ceil(dividend / divisor)
5315 // If dividend >= 0: resultGPR = floor(dividend / divisor)
5316 //
5317 // Note that if the dividend is negative, resultGPR will also be negative.
5318 // Regardless of the sign of dividend, resultGPR will be rounded towards
5319 // zero, because of how things are conditionalized.
5320 m_jit.and32(TrustedImm32(-divisor), resultGPR);
5321
5322 // Subtract resultGPR from dividendGPR, which yields the remainder:
5323 //
5324 // resultGPR = dividendGPR - resultGPR
5325 m_jit.neg32(resultGPR);
5326 m_jit.add32(dividendGPR, resultGPR);
5327
5328 if (shouldCheckNegativeZero(node->arithMode())) {
5329 // Check that we're not about to create negative zero.
5330 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, dividendGPR, TrustedImm32(0));
5331 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, resultGPR));
5332 numeratorPositive.link(&m_jit);
5333 }
5334
5335 int32Result(resultGPR, node);
5336 return;
5337 }
5338 }
5339
5340#if CPU(X86) || CPU(X86_64)
5341 if (node->child2()->isInt32Constant()) {
5342 int32_t divisor = node->child2()->asInt32();
5343 if (divisor && divisor != -1) {
5344 GPRReg op1Gpr = op1.gpr();
5345
5346 GPRTemporary eax(this, X86Registers::eax);
5347 GPRTemporary edx(this, X86Registers::edx);
5348 GPRTemporary scratch(this);
5349 GPRReg scratchGPR = scratch.gpr();
5350
5351 GPRReg op1SaveGPR;
5352 if (op1Gpr == X86Registers::eax || op1Gpr == X86Registers::edx) {
5353 op1SaveGPR = allocate();
5354 ASSERT(op1Gpr != op1SaveGPR);
5355 m_jit.move(op1Gpr, op1SaveGPR);
5356 } else
5357 op1SaveGPR = op1Gpr;
5358 ASSERT(op1SaveGPR != X86Registers::eax);
5359 ASSERT(op1SaveGPR != X86Registers::edx);
5360
5361 m_jit.move(op1Gpr, eax.gpr());
5362 m_jit.move(TrustedImm32(divisor), scratchGPR);
5363 m_jit.x86ConvertToDoubleWord32();
5364 m_jit.x86Div32(scratchGPR);
5365 if (shouldCheckNegativeZero(node->arithMode())) {
5366 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, op1SaveGPR, TrustedImm32(0));
5367 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, edx.gpr()));
5368 numeratorPositive.link(&m_jit);
5369 }
5370
5371 if (op1SaveGPR != op1Gpr)
5372 unlock(op1SaveGPR);
5373
5374 int32Result(edx.gpr(), node);
5375 return;
5376 }
5377 }
5378#endif
5379
5380 SpeculateInt32Operand op2(this, node->child2());
5381#if CPU(X86) || CPU(X86_64)
5382 GPRTemporary eax(this, X86Registers::eax);
5383 GPRTemporary edx(this, X86Registers::edx);
5384 GPRReg op1GPR = op1.gpr();
5385 GPRReg op2GPR = op2.gpr();
5386
5387 GPRReg op2TempGPR;
5388 GPRReg temp;
5389 GPRReg op1SaveGPR;
5390
5391 if (op2GPR == X86Registers::eax || op2GPR == X86Registers::edx) {
5392 op2TempGPR = allocate();
5393 temp = op2TempGPR;
5394 } else {
5395 op2TempGPR = InvalidGPRReg;
5396 if (op1GPR == X86Registers::eax)
5397 temp = X86Registers::edx;
5398 else
5399 temp = X86Registers::eax;
5400 }
5401
5402 if (op1GPR == X86Registers::eax || op1GPR == X86Registers::edx) {
5403 op1SaveGPR = allocate();
5404 ASSERT(op1GPR != op1SaveGPR);
5405 m_jit.move(op1GPR, op1SaveGPR);
5406 } else
5407 op1SaveGPR = op1GPR;
5408
5409 ASSERT(temp != op1GPR);
5410 ASSERT(temp != op2GPR);
5411 ASSERT(op1SaveGPR != X86Registers::eax);
5412 ASSERT(op1SaveGPR != X86Registers::edx);
5413
5414 m_jit.add32(JITCompiler::TrustedImm32(1), op2GPR, temp);
5415
5416 JITCompiler::Jump safeDenominator = m_jit.branch32(JITCompiler::Above, temp, JITCompiler::TrustedImm32(1));
5417
5418 JITCompiler::JumpList done;
5419
5420 // FIXME: -2^31 / -1 will actually yield negative zero, so we could have a
5421 // separate case for that. But it probably doesn't matter so much.
5422 if (shouldCheckOverflow(node->arithMode())) {
5423 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, op2GPR));
5424 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(JITCompiler::Equal, op1GPR, TrustedImm32(-2147483647-1)));
5425 } else {
5426 // This is the case where we convert the result to an int after we're done, and we
5427 // already know that the denominator is either -1 or 0. So, if the denominator is
5428 // zero, then the result should be zero. If the denominator is not zero (i.e. it's
5429 // -1) and the numerator is -2^31 then the result should be 0. Otherwise we are
5430 // happy to fall through to a normal division, since we're just dividing something
5431 // by negative 1.
5432
5433 JITCompiler::Jump notZero = m_jit.branchTest32(JITCompiler::NonZero, op2GPR);
5434 m_jit.move(TrustedImm32(0), edx.gpr());
5435 done.append(m_jit.jump());
5436
5437 notZero.link(&m_jit);
5438 JITCompiler::Jump notNeg2ToThe31 =
5439 m_jit.branch32(JITCompiler::NotEqual, op1GPR, TrustedImm32(-2147483647-1));
5440 m_jit.move(TrustedImm32(0), edx.gpr());
5441 done.append(m_jit.jump());
5442
5443 notNeg2ToThe31.link(&m_jit);
5444 }
5445
5446 safeDenominator.link(&m_jit);
5447
5448 if (op2TempGPR != InvalidGPRReg) {
5449 m_jit.move(op2GPR, op2TempGPR);
5450 op2GPR = op2TempGPR;
5451 }
5452
5453 m_jit.move(op1GPR, eax.gpr());
5454 m_jit.x86ConvertToDoubleWord32();
5455 m_jit.x86Div32(op2GPR);
5456
5457 if (op2TempGPR != InvalidGPRReg)
5458 unlock(op2TempGPR);
5459
5460 // Check that we're not about to create negative zero.
5461 if (shouldCheckNegativeZero(node->arithMode())) {
5462 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, op1SaveGPR, TrustedImm32(0));
5463 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, edx.gpr()));
5464 numeratorPositive.link(&m_jit);
5465 }
5466
5467 if (op1SaveGPR != op1GPR)
5468 unlock(op1SaveGPR);
5469
5470 done.link(&m_jit);
5471 int32Result(edx.gpr(), node);
5472
5473#elif HAVE(ARM_IDIV_INSTRUCTIONS) || CPU(ARM64)
5474 GPRTemporary temp(this);
5475 GPRTemporary quotientThenRemainder(this);
5476 GPRTemporary multiplyAnswer(this);
5477 GPRReg dividendGPR = op1.gpr();
5478 GPRReg divisorGPR = op2.gpr();
5479 GPRReg quotientThenRemainderGPR = quotientThenRemainder.gpr();
5480 GPRReg multiplyAnswerGPR = multiplyAnswer.gpr();
5481
5482 JITCompiler::JumpList done;
5483
5484 if (shouldCheckOverflow(node->arithMode()))
5485 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, divisorGPR));
5486 else {
5487 JITCompiler::Jump denominatorNotZero = m_jit.branchTest32(JITCompiler::NonZero, divisorGPR);
5488 // We know that the low 32-bit of divisorGPR is 0, but we don't know if the high bits are.
5489 // So, use TrustedImm32(0) on ARM instead because done expects the result to be in DataFormatInt32.
5490 // Using an immediate 0 doesn't cost anything extra on ARM.
5491 m_jit.move(TrustedImm32(0), quotientThenRemainderGPR);
5492 done.append(m_jit.jump());
5493 denominatorNotZero.link(&m_jit);
5494 }
5495
5496 m_jit.assembler().sdiv<32>(quotientThenRemainderGPR, dividendGPR, divisorGPR);
5497 // FIXME: It seems like there are cases where we don't need this? What if we have
5498 // arithMode() == Arith::Unchecked?
5499 // https://bugs.webkit.org/show_bug.cgi?id=126444
5500 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchMul32(JITCompiler::Overflow, quotientThenRemainderGPR, divisorGPR, multiplyAnswerGPR));
5501#if HAVE(ARM_IDIV_INSTRUCTIONS)
5502 m_jit.assembler().sub(quotientThenRemainderGPR, dividendGPR, multiplyAnswerGPR);
5503#else
5504 m_jit.assembler().sub<32>(quotientThenRemainderGPR, dividendGPR, multiplyAnswerGPR);
5505#endif
5506
5507 // If the user cares about negative zero, then speculate that we're not about
5508 // to produce negative zero.
5509 if (shouldCheckNegativeZero(node->arithMode())) {
5510 // Check that we're not about to create negative zero.
5511 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, dividendGPR, TrustedImm32(0));
5512 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, quotientThenRemainderGPR));
5513 numeratorPositive.link(&m_jit);
5514 }
5515
5516 done.link(&m_jit);
5517
5518 int32Result(quotientThenRemainderGPR, node);
5519#else // not architecture that can do integer division
5520 RELEASE_ASSERT_NOT_REACHED();
5521#endif
5522 return;
5523 }
5524
5525 case DoubleRepUse: {
5526 SpeculateDoubleOperand op1(this, node->child1());
5527 SpeculateDoubleOperand op2(this, node->child2());
5528
5529 FPRReg op1FPR = op1.fpr();
5530 FPRReg op2FPR = op2.fpr();
5531
5532 flushRegisters();
5533
5534 FPRResult result(this);
5535
5536 using OperationType = D_JITOperation_DD;
5537 callOperation<OperationType>(jsMod, result.fpr(), op1FPR, op2FPR);
5538
5539 doubleResult(result.fpr(), node);
5540 return;
5541 }
5542
5543 default:
5544 RELEASE_ASSERT_NOT_REACHED();
5545 return;
5546 }
5547}
5548
5549void SpeculativeJIT::compileArithRounding(Node* node)
5550{
5551 if (node->child1().useKind() == DoubleRepUse) {
5552 SpeculateDoubleOperand value(this, node->child1());
5553 FPRReg valueFPR = value.fpr();
5554
5555 auto setResult = [&] (FPRReg resultFPR) {
5556 if (producesInteger(node->arithRoundingMode())) {
5557 GPRTemporary roundedResultAsInt32(this);
5558 FPRTemporary scratch(this);
5559 FPRReg scratchFPR = scratch.fpr();
5560 GPRReg resultGPR = roundedResultAsInt32.gpr();
5561 JITCompiler::JumpList failureCases;
5562 m_jit.branchConvertDoubleToInt32(resultFPR, resultGPR, failureCases, scratchFPR, shouldCheckNegativeZero(node->arithRoundingMode()));
5563 speculationCheck(Overflow, JSValueRegs(), node, failureCases);
5564
5565 int32Result(resultGPR, node);
5566 } else
5567 doubleResult(resultFPR, node);
5568 };
5569
5570 if (m_jit.supportsFloatingPointRounding()) {
5571 switch (node->op()) {
5572 case ArithRound: {
5573 FPRTemporary result(this);
5574 FPRReg resultFPR = result.fpr();
5575 if (producesInteger(node->arithRoundingMode()) && !shouldCheckNegativeZero(node->arithRoundingMode())) {
5576 static const double halfConstant = 0.5;
5577 m_jit.loadDouble(TrustedImmPtr(&halfConstant), resultFPR);
5578 m_jit.addDouble(valueFPR, resultFPR);
5579 m_jit.floorDouble(resultFPR, resultFPR);
5580 } else {
5581 m_jit.ceilDouble(valueFPR, resultFPR);
5582 FPRTemporary realPart(this);
5583 FPRReg realPartFPR = realPart.fpr();
5584 m_jit.subDouble(resultFPR, valueFPR, realPartFPR);
5585
5586 FPRTemporary scratch(this);
5587 FPRReg scratchFPR = scratch.fpr();
5588 static const double halfConstant = 0.5;
5589 m_jit.loadDouble(TrustedImmPtr(&halfConstant), scratchFPR);
5590
5591 JITCompiler::Jump shouldUseCeiled = m_jit.branchDouble(JITCompiler::DoubleLessThanOrEqual, realPartFPR, scratchFPR);
5592 static const double oneConstant = -1.0;
5593 m_jit.loadDouble(TrustedImmPtr(&oneConstant), scratchFPR);
5594 m_jit.addDouble(scratchFPR, resultFPR);
5595 shouldUseCeiled.link(&m_jit);
5596 }
5597 setResult(resultFPR);
5598 return;
5599 }
5600
5601 case ArithFloor: {
5602 FPRTemporary rounded(this);
5603 FPRReg resultFPR = rounded.fpr();
5604 m_jit.floorDouble(valueFPR, resultFPR);
5605 setResult(resultFPR);
5606 return;
5607 }
5608
5609 case ArithCeil: {
5610 FPRTemporary rounded(this);
5611 FPRReg resultFPR = rounded.fpr();
5612 m_jit.ceilDouble(valueFPR, resultFPR);
5613 setResult(resultFPR);
5614 return;
5615 }
5616
5617 case ArithTrunc: {
5618 FPRTemporary rounded(this);
5619 FPRReg resultFPR = rounded.fpr();
5620 m_jit.roundTowardZeroDouble(valueFPR, resultFPR);
5621 setResult(resultFPR);
5622 return;
5623 }
5624
5625 default:
5626 RELEASE_ASSERT_NOT_REACHED();
5627 }
5628 } else {
5629 flushRegisters();
5630 FPRResult roundedResultAsDouble(this);
5631 FPRReg resultFPR = roundedResultAsDouble.fpr();
5632 using OperationType = D_JITOperation_D;
5633 if (node->op() == ArithRound)
5634 callOperation<OperationType>(jsRound, resultFPR, valueFPR);
5635 else if (node->op() == ArithFloor)
5636 callOperation<OperationType>(floor, resultFPR, valueFPR);
5637 else if (node->op() == ArithCeil)
5638 callOperation<OperationType>(ceil, resultFPR, valueFPR);
5639 else {
5640 ASSERT(node->op() == ArithTrunc);
5641 callOperation<OperationType>(trunc, resultFPR, valueFPR);
5642 }
5643 setResult(resultFPR);
5644 }
5645 return;
5646 }
5647
5648 DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse, node->child1().useKind());
5649
5650 JSValueOperand argument(this, node->child1());
5651 JSValueRegs argumentRegs = argument.jsValueRegs();
5652
5653 flushRegisters();
5654 JSValueRegsFlushedCallResult result(this);
5655 JSValueRegs resultRegs = result.regs();
5656 J_JITOperation_EJ operation = nullptr;
5657 if (node->op() == ArithRound)
5658 operation = operationArithRound;
5659 else if (node->op() == ArithFloor)
5660 operation = operationArithFloor;
5661 else if (node->op() == ArithCeil)
5662 operation = operationArithCeil;
5663 else {
5664 ASSERT(node->op() == ArithTrunc);
5665 operation = operationArithTrunc;
5666 }
5667 callOperation(operation, resultRegs, argumentRegs);
5668 m_jit.exceptionCheck();
5669 jsValueResult(resultRegs, node);
5670}
5671
5672void SpeculativeJIT::compileArithUnary(Node* node)
5673{
5674 compileArithDoubleUnaryOp(node, arithUnaryFunction(node->arithUnaryType()), arithUnaryOperation(node->arithUnaryType()));
5675}
5676
5677void SpeculativeJIT::compileArithSqrt(Node* node)
5678{
5679 if (node->child1().useKind() == DoubleRepUse) {
5680 SpeculateDoubleOperand op1(this, node->child1());
5681 FPRReg op1FPR = op1.fpr();
5682
5683 if (!MacroAssembler::supportsFloatingPointSqrt() || !Options::useArchitectureSpecificOptimizations()) {
5684 flushRegisters();
5685 FPRResult result(this);
5686 callOperation<D_JITOperation_D>(sqrt, result.fpr(), op1FPR);
5687 doubleResult(result.fpr(), node);
5688 } else {
5689 FPRTemporary result(this, op1);
5690 m_jit.sqrtDouble(op1.fpr(), result.fpr());
5691 doubleResult(result.fpr(), node);
5692 }
5693 return;
5694 }
5695
5696 JSValueOperand op1(this, node->child1());
5697 JSValueRegs op1Regs = op1.jsValueRegs();
5698 flushRegisters();
5699 FPRResult result(this);
5700 callOperation(operationArithSqrt, result.fpr(), op1Regs);
5701 m_jit.exceptionCheck();
5702 doubleResult(result.fpr(), node);
5703}
5704
5705void SpeculativeJIT::compileArithMinMax(Node* node)
5706{
5707 switch (node->binaryUseKind()) {
5708 case Int32Use: {
5709 SpeculateStrictInt32Operand op1(this, node->child1());
5710 SpeculateStrictInt32Operand op2(this, node->child2());
5711 GPRTemporary result(this, Reuse, op1);
5712
5713 GPRReg op1GPR = op1.gpr();
5714 GPRReg op2GPR = op2.gpr();
5715 GPRReg resultGPR = result.gpr();
5716
5717 MacroAssembler::Jump op1Less = m_jit.branch32(node->op() == ArithMin ? MacroAssembler::LessThan : MacroAssembler::GreaterThan, op1GPR, op2GPR);
5718 m_jit.move(op2GPR, resultGPR);
5719 if (op1GPR != resultGPR) {
5720 MacroAssembler::Jump done = m_jit.jump();
5721 op1Less.link(&m_jit);
5722 m_jit.move(op1GPR, resultGPR);
5723 done.link(&m_jit);
5724 } else
5725 op1Less.link(&m_jit);
5726
5727 int32Result(resultGPR, node);
5728 break;
5729 }
5730
5731 case DoubleRepUse: {
5732 SpeculateDoubleOperand op1(this, node->child1());
5733 SpeculateDoubleOperand op2(this, node->child2());
5734 FPRTemporary result(this, op1);
5735
5736 FPRReg op1FPR = op1.fpr();
5737 FPRReg op2FPR = op2.fpr();
5738 FPRReg resultFPR = result.fpr();
5739
5740 MacroAssembler::JumpList done;
5741
5742 MacroAssembler::Jump op1Less = m_jit.branchDouble(node->op() == ArithMin ? MacroAssembler::DoubleLessThan : MacroAssembler::DoubleGreaterThan, op1FPR, op2FPR);
5743
5744 // op2 is eather the lesser one or one of then is NaN
5745 MacroAssembler::Jump op2Less = m_jit.branchDouble(node->op() == ArithMin ? MacroAssembler::DoubleGreaterThanOrEqual : MacroAssembler::DoubleLessThanOrEqual, op1FPR, op2FPR);
5746
5747 // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding
5748 // op1 + op2 and putting it into result.
5749 m_jit.addDouble(op1FPR, op2FPR, resultFPR);
5750 done.append(m_jit.jump());
5751
5752 op2Less.link(&m_jit);
5753 m_jit.moveDouble(op2FPR, resultFPR);
5754
5755 if (op1FPR != resultFPR) {
5756 done.append(m_jit.jump());
5757
5758 op1Less.link(&m_jit);
5759 m_jit.moveDouble(op1FPR, resultFPR);
5760 } else
5761 op1Less.link(&m_jit);
5762
5763 done.link(&m_jit);
5764
5765 doubleResult(resultFPR, node);
5766 break;
5767 }
5768
5769 default:
5770 DFG_CRASH(m_jit.graph(), node, "Bad use kind");
5771 break;
5772 }
5773}
5774
5775// For small positive integers , it is worth doing a tiny inline loop to exponentiate the base.
5776// Every register is clobbered by this helper.
5777static MacroAssembler::Jump compileArithPowIntegerFastPath(JITCompiler& assembler, FPRReg xOperand, GPRReg yOperand, FPRReg result)
5778{
5779 MacroAssembler::JumpList skipFastPath;
5780 skipFastPath.append(assembler.branch32(MacroAssembler::Above, yOperand, MacroAssembler::TrustedImm32(maxExponentForIntegerMathPow)));
5781
5782 static const double oneConstant = 1.0;
5783 assembler.loadDouble(MacroAssembler::TrustedImmPtr(&oneConstant), result);
5784
5785 MacroAssembler::Label startLoop(assembler.label());
5786 MacroAssembler::Jump exponentIsEven = assembler.branchTest32(MacroAssembler::Zero, yOperand, MacroAssembler::TrustedImm32(1));
5787 assembler.mulDouble(xOperand, result);
5788 exponentIsEven.link(&assembler);
5789 assembler.mulDouble(xOperand, xOperand);
5790 assembler.rshift32(MacroAssembler::TrustedImm32(1), yOperand);
5791 assembler.branchTest32(MacroAssembler::NonZero, yOperand).linkTo(startLoop, &assembler);
5792
5793 MacroAssembler::Jump skipSlowPath = assembler.jump();
5794 skipFastPath.link(&assembler);
5795
5796 return skipSlowPath;
5797}
5798
5799void SpeculativeJIT::compileArithPow(Node* node)
5800{
5801 if (node->child2().useKind() == Int32Use) {
5802 SpeculateDoubleOperand xOperand(this, node->child1());
5803 SpeculateInt32Operand yOperand(this, node->child2());
5804 FPRReg xOperandfpr = xOperand.fpr();
5805 GPRReg yOperandGpr = yOperand.gpr();
5806 FPRTemporary yOperandfpr(this);
5807
5808 flushRegisters();
5809
5810 FPRResult result(this);
5811 FPRReg resultFpr = result.fpr();
5812
5813 FPRTemporary xOperandCopy(this);
5814 FPRReg xOperandCopyFpr = xOperandCopy.fpr();
5815 m_jit.moveDouble(xOperandfpr, xOperandCopyFpr);
5816
5817 GPRTemporary counter(this);
5818 GPRReg counterGpr = counter.gpr();
5819 m_jit.move(yOperandGpr, counterGpr);
5820
5821 MacroAssembler::Jump skipFallback = compileArithPowIntegerFastPath(m_jit, xOperandCopyFpr, counterGpr, resultFpr);
5822 m_jit.convertInt32ToDouble(yOperandGpr, yOperandfpr.fpr());
5823 callOperation(operationMathPow, resultFpr, xOperandfpr, yOperandfpr.fpr());
5824
5825 skipFallback.link(&m_jit);
5826 doubleResult(resultFpr, node);
5827 return;
5828 }
5829
5830 if (node->child2()->isDoubleConstant()) {
5831 double exponent = node->child2()->asNumber();
5832 static const double infinityConstant = std::numeric_limits<double>::infinity();
5833 static const double minusInfinityConstant = -std::numeric_limits<double>::infinity();
5834 if (exponent == 0.5) {
5835 SpeculateDoubleOperand xOperand(this, node->child1());
5836 FPRTemporary result(this);
5837 FPRReg xOperandFpr = xOperand.fpr();
5838 FPRReg resultFpr = result.fpr();
5839
5840 m_jit.moveZeroToDouble(resultFpr);
5841 MacroAssembler::Jump xIsZeroOrNegativeZero = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr);
5842
5843 m_jit.loadDouble(TrustedImmPtr(&minusInfinityConstant), resultFpr);
5844 MacroAssembler::Jump xIsMinusInfinity = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr);
5845 m_jit.sqrtDouble(xOperandFpr, resultFpr);
5846 MacroAssembler::Jump doneWithSqrt = m_jit.jump();
5847
5848 xIsMinusInfinity.link(&m_jit);
5849 if (isX86())
5850 m_jit.loadDouble(TrustedImmPtr(&infinityConstant), resultFpr);
5851 else
5852 m_jit.absDouble(resultFpr, resultFpr);
5853
5854 xIsZeroOrNegativeZero.link(&m_jit);
5855 doneWithSqrt.link(&m_jit);
5856 doubleResult(resultFpr, node);
5857 return;
5858 }
5859 if (exponent == -0.5) {
5860 SpeculateDoubleOperand xOperand(this, node->child1());
5861 FPRTemporary scratch(this);
5862 FPRTemporary result(this);
5863 FPRReg xOperandFpr = xOperand.fpr();
5864 FPRReg scratchFPR = scratch.fpr();
5865 FPRReg resultFpr = result.fpr();
5866
5867 m_jit.moveZeroToDouble(resultFpr);
5868 MacroAssembler::Jump xIsZeroOrNegativeZero = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr);
5869
5870 m_jit.loadDouble(TrustedImmPtr(&minusInfinityConstant), resultFpr);
5871 MacroAssembler::Jump xIsMinusInfinity = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr);
5872
5873 static const double oneConstant = 1.;
5874 m_jit.loadDouble(TrustedImmPtr(&oneConstant), resultFpr);
5875 m_jit.sqrtDouble(xOperandFpr, scratchFPR);
5876 m_jit.divDouble(resultFpr, scratchFPR, resultFpr);
5877 MacroAssembler::Jump doneWithSqrt = m_jit.jump();
5878
5879 xIsZeroOrNegativeZero.link(&m_jit);
5880 m_jit.loadDouble(TrustedImmPtr(&infinityConstant), resultFpr);
5881 MacroAssembler::Jump doneWithBaseZero = m_jit.jump();
5882
5883 xIsMinusInfinity.link(&m_jit);
5884 m_jit.moveZeroToDouble(resultFpr);
5885
5886 doneWithBaseZero.link(&m_jit);
5887 doneWithSqrt.link(&m_jit);
5888 doubleResult(resultFpr, node);
5889 return;
5890 }
5891 }
5892
5893 SpeculateDoubleOperand xOperand(this, node->child1());
5894 SpeculateDoubleOperand yOperand(this, node->child2());
5895 FPRReg xOperandfpr = xOperand.fpr();
5896 FPRReg yOperandfpr = yOperand.fpr();
5897
5898 flushRegisters();
5899
5900 FPRResult result(this);
5901 FPRReg resultFpr = result.fpr();
5902
5903 FPRTemporary xOperandCopy(this);
5904 FPRReg xOperandCopyFpr = xOperandCopy.fpr();
5905
5906 FPRTemporary scratch(this);
5907 FPRReg scratchFpr = scratch.fpr();
5908
5909 GPRTemporary yOperandInteger(this);
5910 GPRReg yOperandIntegerGpr = yOperandInteger.gpr();
5911 MacroAssembler::JumpList failedExponentConversionToInteger;
5912 m_jit.branchConvertDoubleToInt32(yOperandfpr, yOperandIntegerGpr, failedExponentConversionToInteger, scratchFpr, false);
5913
5914 m_jit.moveDouble(xOperandfpr, xOperandCopyFpr);
5915 MacroAssembler::Jump skipFallback = compileArithPowIntegerFastPath(m_jit, xOperandCopyFpr, yOperandInteger.gpr(), resultFpr);
5916 failedExponentConversionToInteger.link(&m_jit);
5917
5918 callOperation(operationMathPow, resultFpr, xOperandfpr, yOperandfpr);
5919 skipFallback.link(&m_jit);
5920 doubleResult(resultFpr, node);
5921}
5922
5923// Returns true if the compare is fused with a subsequent branch.
5924bool SpeculativeJIT::compare(Node* node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_JITOperation_EJJ operation)
5925{
5926 if (compilePeepHoleBranch(node, condition, doubleCondition, operation))
5927 return true;
5928
5929 if (node->isBinaryUseKind(Int32Use)) {
5930 compileInt32Compare(node, condition);
5931 return false;
5932 }
5933
5934#if USE(JSVALUE64)
5935 if (node->isBinaryUseKind(Int52RepUse)) {
5936 compileInt52Compare(node, condition);
5937 return false;
5938 }
5939#endif // USE(JSVALUE64)
5940
5941 if (node->isBinaryUseKind(DoubleRepUse)) {
5942 compileDoubleCompare(node, doubleCondition);
5943 return false;
5944 }
5945
5946 if (node->isBinaryUseKind(StringUse)) {
5947 if (node->op() == CompareEq)
5948 compileStringEquality(node);
5949 else
5950 compileStringCompare(node, condition);
5951 return false;
5952 }
5953
5954 if (node->isBinaryUseKind(StringIdentUse)) {
5955 if (node->op() == CompareEq)
5956 compileStringIdentEquality(node);
5957 else
5958 compileStringIdentCompare(node, condition);
5959 return false;
5960 }
5961
5962 if (node->op() == CompareEq) {
5963 if (node->isBinaryUseKind(BooleanUse)) {
5964 compileBooleanCompare(node, condition);
5965 return false;
5966 }
5967
5968 if (node->isBinaryUseKind(SymbolUse)) {
5969 compileSymbolEquality(node);
5970 return false;
5971 }
5972
5973 if (node->isBinaryUseKind(ObjectUse)) {
5974 compileObjectEquality(node);
5975 return false;
5976 }
5977
5978 if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse)) {
5979 compileObjectToObjectOrOtherEquality(node->child1(), node->child2());
5980 return false;
5981 }
5982
5983 if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) {
5984 compileObjectToObjectOrOtherEquality(node->child2(), node->child1());
5985 return false;
5986 }
5987
5988 if (!needsTypeCheck(node->child1(), SpecOther)) {
5989 nonSpeculativeNonPeepholeCompareNullOrUndefined(node->child2());
5990 return false;
5991 }
5992
5993 if (!needsTypeCheck(node->child2(), SpecOther)) {
5994 nonSpeculativeNonPeepholeCompareNullOrUndefined(node->child1());
5995 return false;
5996 }
5997 }
5998
5999 nonSpeculativeNonPeepholeCompare(node, condition, operation);
6000 return false;
6001}
6002
6003void SpeculativeJIT::compileCompareUnsigned(Node* node, MacroAssembler::RelationalCondition condition)
6004{
6005 compileInt32Compare(node, condition);
6006}
6007
6008bool SpeculativeJIT::compileStrictEq(Node* node)
6009{
6010 if (node->isBinaryUseKind(BooleanUse)) {
6011 unsigned branchIndexInBlock = detectPeepHoleBranch();
6012 if (branchIndexInBlock != UINT_MAX) {
6013 Node* branchNode = m_block->at(branchIndexInBlock);
6014 compilePeepHoleBooleanBranch(node, branchNode, MacroAssembler::Equal);
6015 use(node->child1());
6016 use(node->child2());
6017 m_indexInBlock = branchIndexInBlock;
6018 m_currentNode = branchNode;
6019 return true;
6020 }
6021 compileBooleanCompare(node, MacroAssembler::Equal);
6022 return false;
6023 }
6024
6025 if (node->isBinaryUseKind(Int32Use)) {
6026 unsigned branchIndexInBlock = detectPeepHoleBranch();
6027 if (branchIndexInBlock != UINT_MAX) {
6028 Node* branchNode = m_block->at(branchIndexInBlock);
6029 compilePeepHoleInt32Branch(node, branchNode, MacroAssembler::Equal);
6030 use(node->child1());
6031 use(node->child2());
6032 m_indexInBlock = branchIndexInBlock;
6033 m_currentNode = branchNode;
6034 return true;
6035 }
6036 compileInt32Compare(node, MacroAssembler::Equal);
6037 return false;
6038 }
6039
6040#if USE(JSVALUE64)
6041 if (node->isBinaryUseKind(Int52RepUse)) {
6042 unsigned branchIndexInBlock = detectPeepHoleBranch();
6043 if (branchIndexInBlock != UINT_MAX) {
6044 Node* branchNode = m_block->at(branchIndexInBlock);
6045 compilePeepHoleInt52Branch(node, branchNode, MacroAssembler::Equal);
6046 use(node->child1());
6047 use(node->child2());
6048 m_indexInBlock = branchIndexInBlock;
6049 m_currentNode = branchNode;
6050 return true;
6051 }
6052 compileInt52Compare(node, MacroAssembler::Equal);
6053 return false;
6054 }
6055#endif // USE(JSVALUE64)
6056
6057 if (node->isBinaryUseKind(DoubleRepUse)) {
6058 unsigned branchIndexInBlock = detectPeepHoleBranch();
6059 if (branchIndexInBlock != UINT_MAX) {
6060 Node* branchNode = m_block->at(branchIndexInBlock);
6061 compilePeepHoleDoubleBranch(node, branchNode, MacroAssembler::DoubleEqual);
6062 use(node->child1());
6063 use(node->child2());
6064 m_indexInBlock = branchIndexInBlock;
6065 m_currentNode = branchNode;
6066 return true;
6067 }
6068 compileDoubleCompare(node, MacroAssembler::DoubleEqual);
6069 return false;
6070 }
6071
6072 if (node->isBinaryUseKind(SymbolUse)) {
6073 unsigned branchIndexInBlock = detectPeepHoleBranch();
6074 if (branchIndexInBlock != UINT_MAX) {
6075 Node* branchNode = m_block->at(branchIndexInBlock);
6076 compilePeepHoleSymbolEquality(node, branchNode);
6077 use(node->child1());
6078 use(node->child2());
6079 m_indexInBlock = branchIndexInBlock;
6080 m_currentNode = branchNode;
6081 return true;
6082 }
6083 compileSymbolEquality(node);
6084 return false;
6085 }
6086
6087 if (node->isBinaryUseKind(BigIntUse)) {
6088 compileBigIntEquality(node);
6089 return false;
6090 }
6091
6092 if (node->isBinaryUseKind(SymbolUse, UntypedUse)) {
6093 compileSymbolUntypedEquality(node, node->child1(), node->child2());
6094 return false;
6095 }
6096
6097 if (node->isBinaryUseKind(UntypedUse, SymbolUse)) {
6098 compileSymbolUntypedEquality(node, node->child2(), node->child1());
6099 return false;
6100 }
6101
6102 if (node->isBinaryUseKind(StringUse)) {
6103 compileStringEquality(node);
6104 return false;
6105 }
6106
6107 if (node->isBinaryUseKind(StringIdentUse)) {
6108 compileStringIdentEquality(node);
6109 return false;
6110 }
6111
6112 if (node->isBinaryUseKind(ObjectUse, UntypedUse)) {
6113 unsigned branchIndexInBlock = detectPeepHoleBranch();
6114 if (branchIndexInBlock != UINT_MAX) {
6115 Node* branchNode = m_block->at(branchIndexInBlock);
6116 compilePeepHoleObjectStrictEquality(node->child1(), node->child2(), branchNode);
6117 use(node->child1());
6118 use(node->child2());
6119 m_indexInBlock = branchIndexInBlock;
6120 m_currentNode = branchNode;
6121 return true;
6122 }
6123 compileObjectStrictEquality(node->child1(), node->child2());
6124 return false;
6125 }
6126
6127 if (node->isBinaryUseKind(UntypedUse, ObjectUse)) {
6128 unsigned branchIndexInBlock = detectPeepHoleBranch();
6129 if (branchIndexInBlock != UINT_MAX) {
6130 Node* branchNode = m_block->at(branchIndexInBlock);
6131 compilePeepHoleObjectStrictEquality(node->child2(), node->child1(), branchNode);
6132 use(node->child1());
6133 use(node->child2());
6134 m_indexInBlock = branchIndexInBlock;
6135 m_currentNode = branchNode;
6136 return true;
6137 }
6138 compileObjectStrictEquality(node->child2(), node->child1());
6139 return false;
6140 }
6141
6142 if (node->isBinaryUseKind(ObjectUse)) {
6143 unsigned branchIndexInBlock = detectPeepHoleBranch();
6144 if (branchIndexInBlock != UINT_MAX) {
6145 Node* branchNode = m_block->at(branchIndexInBlock);
6146 compilePeepHoleObjectEquality(node, branchNode);
6147 use(node->child1());
6148 use(node->child2());
6149 m_indexInBlock = branchIndexInBlock;
6150 m_currentNode = branchNode;
6151 return true;
6152 }
6153 compileObjectEquality(node);
6154 return false;
6155 }
6156
6157 if (node->isBinaryUseKind(MiscUse, UntypedUse)
6158 || node->isBinaryUseKind(UntypedUse, MiscUse)) {
6159 compileMiscStrictEq(node);
6160 return false;
6161 }
6162
6163 if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse)) {
6164 compileStringIdentToNotStringVarEquality(node, node->child1(), node->child2());
6165 return false;
6166 }
6167
6168 if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse)) {
6169 compileStringIdentToNotStringVarEquality(node, node->child2(), node->child1());
6170 return false;
6171 }
6172
6173 if (node->isBinaryUseKind(StringUse, UntypedUse)) {
6174 compileStringToUntypedEquality(node, node->child1(), node->child2());
6175 return false;
6176 }
6177
6178 if (node->isBinaryUseKind(UntypedUse, StringUse)) {
6179 compileStringToUntypedEquality(node, node->child2(), node->child1());
6180 return false;
6181 }
6182
6183 RELEASE_ASSERT(node->isBinaryUseKind(UntypedUse));
6184 return nonSpeculativeStrictEq(node);
6185}
6186
6187void SpeculativeJIT::compileBooleanCompare(Node* node, MacroAssembler::RelationalCondition condition)
6188{
6189 SpeculateBooleanOperand op1(this, node->child1());
6190 SpeculateBooleanOperand op2(this, node->child2());
6191 GPRTemporary result(this);
6192
6193 m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());
6194
6195 unblessedBooleanResult(result.gpr(), node);
6196}
6197
6198void SpeculativeJIT::compileInt32Compare(Node* node, MacroAssembler::RelationalCondition condition)
6199{
6200 if (node->child1()->isInt32Constant()) {
6201 SpeculateInt32Operand op2(this, node->child2());
6202 GPRTemporary result(this, Reuse, op2);
6203 int32_t imm = node->child1()->asInt32();
6204 m_jit.compare32(condition, JITCompiler::Imm32(imm), op2.gpr(), result.gpr());
6205
6206 unblessedBooleanResult(result.gpr(), node);
6207 } else if (node->child2()->isInt32Constant()) {
6208 SpeculateInt32Operand op1(this, node->child1());
6209 GPRTemporary result(this, Reuse, op1);
6210 int32_t imm = node->child2()->asInt32();
6211 m_jit.compare32(condition, op1.gpr(), JITCompiler::Imm32(imm), result.gpr());
6212
6213 unblessedBooleanResult(result.gpr(), node);
6214 } else {
6215 SpeculateInt32Operand op1(this, node->child1());
6216 SpeculateInt32Operand op2(this, node->child2());
6217 GPRTemporary result(this, Reuse, op1, op2);
6218 m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());
6219
6220 unblessedBooleanResult(result.gpr(), node);
6221 }
6222}
6223
6224void SpeculativeJIT::compileDoubleCompare(Node* node, MacroAssembler::DoubleCondition condition)
6225{
6226 SpeculateDoubleOperand op1(this, node->child1());
6227 SpeculateDoubleOperand op2(this, node->child2());
6228 GPRTemporary result(this);
6229
6230 FPRReg op1FPR = op1.fpr();
6231 FPRReg op2FPR = op2.fpr();
6232 GPRReg resultGPR = result.gpr();
6233
6234 m_jit.compareDouble(condition, op1FPR, op2FPR, resultGPR);
6235
6236 unblessedBooleanResult(resultGPR, node);
6237}
6238
6239void SpeculativeJIT::compileObjectEquality(Node* node)
6240{
6241 SpeculateCellOperand op1(this, node->child1());
6242 SpeculateCellOperand op2(this, node->child2());
6243 GPRTemporary result(this, Reuse, op1);
6244
6245 GPRReg op1GPR = op1.gpr();
6246 GPRReg op2GPR = op2.gpr();
6247 GPRReg resultGPR = result.gpr();
6248
6249 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
6250 DFG_TYPE_CHECK(
6251 JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchIfNotObject(op1GPR));
6252 DFG_TYPE_CHECK(
6253 JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchIfNotObject(op2GPR));
6254 } else {
6255 DFG_TYPE_CHECK(
6256 JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchIfNotObject(op1GPR));
6257 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
6258 m_jit.branchTest8(
6259 MacroAssembler::NonZero,
6260 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
6261 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
6262
6263 DFG_TYPE_CHECK(
6264 JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchIfNotObject(op2GPR));
6265 speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
6266 m_jit.branchTest8(
6267 MacroAssembler::NonZero,
6268 MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()),
6269 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
6270 }
6271
6272 m_jit.comparePtr(MacroAssembler::Equal, op1GPR, op2GPR, resultGPR);
6273 unblessedBooleanResult(resultGPR, node);
6274}
6275
6276void SpeculativeJIT::compileSymbolEquality(Node* node)
6277{
6278 SpeculateCellOperand left(this, node->child1());
6279 SpeculateCellOperand right(this, node->child2());
6280 GPRTemporary result(this, Reuse, left, right);
6281
6282 GPRReg leftGPR = left.gpr();
6283 GPRReg rightGPR = right.gpr();
6284 GPRReg resultGPR = result.gpr();
6285
6286 speculateSymbol(node->child1(), leftGPR);
6287 speculateSymbol(node->child2(), rightGPR);
6288
6289 m_jit.comparePtr(JITCompiler::Equal, leftGPR, rightGPR, resultGPR);
6290 unblessedBooleanResult(resultGPR, node);
6291}
6292
6293void SpeculativeJIT::compilePeepHoleSymbolEquality(Node* node, Node* branchNode)
6294{
6295 SpeculateCellOperand left(this, node->child1());
6296 SpeculateCellOperand right(this, node->child2());
6297
6298 GPRReg leftGPR = left.gpr();
6299 GPRReg rightGPR = right.gpr();
6300
6301 speculateSymbol(node->child1(), leftGPR);
6302 speculateSymbol(node->child2(), rightGPR);
6303
6304 BasicBlock* taken = branchNode->branchData()->taken.block;
6305 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
6306
6307 if (taken == nextBlock()) {
6308 branchPtr(JITCompiler::NotEqual, leftGPR, rightGPR, notTaken);
6309 jump(taken);
6310 } else {
6311 branchPtr(JITCompiler::Equal, leftGPR, rightGPR, taken);
6312 jump(notTaken);
6313 }
6314}
6315
6316void SpeculativeJIT::compileStringEquality(
6317 Node* node, GPRReg leftGPR, GPRReg rightGPR, GPRReg lengthGPR, GPRReg leftTempGPR,
6318 GPRReg rightTempGPR, GPRReg leftTemp2GPR, GPRReg rightTemp2GPR,
6319 const JITCompiler::JumpList& fastTrue, const JITCompiler::JumpList& fastFalse)
6320{
6321 JITCompiler::JumpList trueCase;
6322 JITCompiler::JumpList falseCase;
6323 JITCompiler::JumpList slowCase;
6324
6325 trueCase.append(fastTrue);
6326 falseCase.append(fastFalse);
6327
6328 m_jit.loadPtr(MacroAssembler::Address(leftGPR, JSString::offsetOfValue()), leftTempGPR);
6329 m_jit.loadPtr(MacroAssembler::Address(rightGPR, JSString::offsetOfValue()), rightTempGPR);
6330
6331 slowCase.append(m_jit.branchIfRopeStringImpl(leftTempGPR));
6332 slowCase.append(m_jit.branchIfRopeStringImpl(rightTempGPR));
6333
6334 m_jit.load32(MacroAssembler::Address(leftTempGPR, StringImpl::lengthMemoryOffset()), lengthGPR);
6335
6336 falseCase.append(m_jit.branch32(
6337 MacroAssembler::NotEqual,
6338 MacroAssembler::Address(rightTempGPR, StringImpl::lengthMemoryOffset()),
6339 lengthGPR));
6340
6341 trueCase.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR));
6342
6343 slowCase.append(m_jit.branchTest32(
6344 MacroAssembler::Zero,
6345 MacroAssembler::Address(leftTempGPR, StringImpl::flagsOffset()),
6346 TrustedImm32(StringImpl::flagIs8Bit())));
6347 slowCase.append(m_jit.branchTest32(
6348 MacroAssembler::Zero,
6349 MacroAssembler::Address(rightTempGPR, StringImpl::flagsOffset()),
6350 TrustedImm32(StringImpl::flagIs8Bit())));
6351
6352 m_jit.loadPtr(MacroAssembler::Address(leftTempGPR, StringImpl::dataOffset()), leftTempGPR);
6353 m_jit.loadPtr(MacroAssembler::Address(rightTempGPR, StringImpl::dataOffset()), rightTempGPR);
6354
6355 MacroAssembler::Label loop = m_jit.label();
6356
6357 m_jit.sub32(TrustedImm32(1), lengthGPR);
6358
6359 // This isn't going to generate the best code on x86. But that's OK, it's still better
6360 // than not inlining.
6361 m_jit.load8(MacroAssembler::BaseIndex(leftTempGPR, lengthGPR, MacroAssembler::TimesOne), leftTemp2GPR);
6362 m_jit.load8(MacroAssembler::BaseIndex(rightTempGPR, lengthGPR, MacroAssembler::TimesOne), rightTemp2GPR);
6363 falseCase.append(m_jit.branch32(MacroAssembler::NotEqual, leftTemp2GPR, rightTemp2GPR));
6364
6365 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loop, &m_jit);
6366
6367 trueCase.link(&m_jit);
6368 moveTrueTo(leftTempGPR);
6369
6370 JITCompiler::Jump done = m_jit.jump();
6371
6372 falseCase.link(&m_jit);
6373 moveFalseTo(leftTempGPR);
6374
6375 done.link(&m_jit);
6376 addSlowPathGenerator(
6377 slowPathCall(
6378 slowCase, this, operationCompareStringEq, leftTempGPR, leftGPR, rightGPR));
6379
6380 blessedBooleanResult(leftTempGPR, node);
6381}
6382
6383void SpeculativeJIT::compileStringEquality(Node* node)
6384{
6385 SpeculateCellOperand left(this, node->child1());
6386 SpeculateCellOperand right(this, node->child2());
6387 GPRTemporary length(this);
6388 GPRTemporary leftTemp(this);
6389 GPRTemporary rightTemp(this);
6390 GPRTemporary leftTemp2(this, Reuse, left);
6391 GPRTemporary rightTemp2(this, Reuse, right);
6392
6393 GPRReg leftGPR = left.gpr();
6394 GPRReg rightGPR = right.gpr();
6395 GPRReg lengthGPR = length.gpr();
6396 GPRReg leftTempGPR = leftTemp.gpr();
6397 GPRReg rightTempGPR = rightTemp.gpr();
6398 GPRReg leftTemp2GPR = leftTemp2.gpr();
6399 GPRReg rightTemp2GPR = rightTemp2.gpr();
6400
6401 speculateString(node->child1(), leftGPR);
6402
6403 // It's safe to branch around the type check below, since proving that the values are
6404 // equal does indeed prove that the right value is a string.
6405 JITCompiler::Jump fastTrue = m_jit.branchPtr(MacroAssembler::Equal, leftGPR, rightGPR);
6406
6407 speculateString(node->child2(), rightGPR);
6408
6409 compileStringEquality(
6410 node, leftGPR, rightGPR, lengthGPR, leftTempGPR, rightTempGPR, leftTemp2GPR,
6411 rightTemp2GPR, fastTrue, JITCompiler::Jump());
6412}
6413
6414void SpeculativeJIT::compileStringToUntypedEquality(Node* node, Edge stringEdge, Edge untypedEdge)
6415{
6416 SpeculateCellOperand left(this, stringEdge);
6417 JSValueOperand right(this, untypedEdge, ManualOperandSpeculation);
6418 GPRTemporary length(this);
6419 GPRTemporary leftTemp(this);
6420 GPRTemporary rightTemp(this);
6421 GPRTemporary leftTemp2(this, Reuse, left);
6422 GPRTemporary rightTemp2(this);
6423
6424 GPRReg leftGPR = left.gpr();
6425 JSValueRegs rightRegs = right.jsValueRegs();
6426 GPRReg lengthGPR = length.gpr();
6427 GPRReg leftTempGPR = leftTemp.gpr();
6428 GPRReg rightTempGPR = rightTemp.gpr();
6429 GPRReg leftTemp2GPR = leftTemp2.gpr();
6430 GPRReg rightTemp2GPR = rightTemp2.gpr();
6431
6432 speculateString(stringEdge, leftGPR);
6433
6434 JITCompiler::JumpList fastTrue;
6435 JITCompiler::JumpList fastFalse;
6436
6437 fastFalse.append(m_jit.branchIfNotCell(rightRegs));
6438
6439 // It's safe to branch around the type check below, since proving that the values are
6440 // equal does indeed prove that the right value is a string.
6441 fastTrue.append(m_jit.branchPtr(
6442 MacroAssembler::Equal, leftGPR, rightRegs.payloadGPR()));
6443
6444 fastFalse.append(m_jit.branchIfNotString(rightRegs.payloadGPR()));
6445
6446 compileStringEquality(
6447 node, leftGPR, rightRegs.payloadGPR(), lengthGPR, leftTempGPR, rightTempGPR, leftTemp2GPR,
6448 rightTemp2GPR, fastTrue, fastFalse);
6449}
6450
6451void SpeculativeJIT::compileStringIdentEquality(Node* node)
6452{
6453 SpeculateCellOperand left(this, node->child1());
6454 SpeculateCellOperand right(this, node->child2());
6455 GPRTemporary leftTemp(this);
6456 GPRTemporary rightTemp(this);
6457
6458 GPRReg leftGPR = left.gpr();
6459 GPRReg rightGPR = right.gpr();
6460 GPRReg leftTempGPR = leftTemp.gpr();
6461 GPRReg rightTempGPR = rightTemp.gpr();
6462
6463 speculateString(node->child1(), leftGPR);
6464 speculateString(node->child2(), rightGPR);
6465
6466 speculateStringIdentAndLoadStorage(node->child1(), leftGPR, leftTempGPR);
6467 speculateStringIdentAndLoadStorage(node->child2(), rightGPR, rightTempGPR);
6468
6469 m_jit.comparePtr(MacroAssembler::Equal, leftTempGPR, rightTempGPR, leftTempGPR);
6470
6471 unblessedBooleanResult(leftTempGPR, node);
6472}
6473
6474void SpeculativeJIT::compileStringIdentToNotStringVarEquality(
6475 Node* node, Edge stringEdge, Edge notStringVarEdge)
6476{
6477 SpeculateCellOperand left(this, stringEdge);
6478 JSValueOperand right(this, notStringVarEdge, ManualOperandSpeculation);
6479 GPRTemporary leftTemp(this);
6480 GPRTemporary rightTemp(this);
6481 GPRReg leftTempGPR = leftTemp.gpr();
6482 GPRReg rightTempGPR = rightTemp.gpr();
6483 GPRReg leftGPR = left.gpr();
6484 JSValueRegs rightRegs = right.jsValueRegs();
6485
6486 speculateString(stringEdge, leftGPR);
6487 speculateStringIdentAndLoadStorage(stringEdge, leftGPR, leftTempGPR);
6488
6489 moveFalseTo(rightTempGPR);
6490 JITCompiler::JumpList notString;
6491 notString.append(m_jit.branchIfNotCell(rightRegs));
6492 notString.append(m_jit.branchIfNotString(rightRegs.payloadGPR()));
6493
6494 speculateStringIdentAndLoadStorage(notStringVarEdge, rightRegs.payloadGPR(), rightTempGPR);
6495
6496 m_jit.comparePtr(MacroAssembler::Equal, leftTempGPR, rightTempGPR, rightTempGPR);
6497 notString.link(&m_jit);
6498
6499 unblessedBooleanResult(rightTempGPR, node);
6500}
6501
6502void SpeculativeJIT::compileStringCompare(Node* node, MacroAssembler::RelationalCondition condition)
6503{
6504 SpeculateCellOperand left(this, node->child1());
6505 SpeculateCellOperand right(this, node->child2());
6506 GPRReg leftGPR = left.gpr();
6507 GPRReg rightGPR = right.gpr();
6508
6509 speculateString(node->child1(), leftGPR);
6510 speculateString(node->child2(), rightGPR);
6511
6512 C_JITOperation_B_EJssJss compareFunction = nullptr;
6513 if (condition == MacroAssembler::LessThan)
6514 compareFunction = operationCompareStringLess;
6515 else if (condition == MacroAssembler::LessThanOrEqual)
6516 compareFunction = operationCompareStringLessEq;
6517 else if (condition == MacroAssembler::GreaterThan)
6518 compareFunction = operationCompareStringGreater;
6519 else if (condition == MacroAssembler::GreaterThanOrEqual)
6520 compareFunction = operationCompareStringGreaterEq;
6521 else
6522 RELEASE_ASSERT_NOT_REACHED();
6523
6524 GPRFlushedCallResult result(this);
6525 GPRReg resultGPR = result.gpr();
6526
6527 flushRegisters();
6528 callOperation(compareFunction, resultGPR, leftGPR, rightGPR);
6529 m_jit.exceptionCheck();
6530
6531 unblessedBooleanResult(resultGPR, node);
6532}
6533
6534void SpeculativeJIT::compileStringIdentCompare(Node* node, MacroAssembler::RelationalCondition condition)
6535{
6536 SpeculateCellOperand left(this, node->child1());
6537 SpeculateCellOperand right(this, node->child2());
6538 GPRFlushedCallResult result(this);
6539 GPRTemporary leftTemp(this);
6540 GPRTemporary rightTemp(this);
6541
6542 GPRReg leftGPR = left.gpr();
6543 GPRReg rightGPR = right.gpr();
6544 GPRReg resultGPR = result.gpr();
6545 GPRReg leftTempGPR = leftTemp.gpr();
6546 GPRReg rightTempGPR = rightTemp.gpr();
6547
6548 speculateString(node->child1(), leftGPR);
6549 speculateString(node->child2(), rightGPR);
6550
6551 C_JITOperation_TT compareFunction = nullptr;
6552 if (condition == MacroAssembler::LessThan)
6553 compareFunction = operationCompareStringImplLess;
6554 else if (condition == MacroAssembler::LessThanOrEqual)
6555 compareFunction = operationCompareStringImplLessEq;
6556 else if (condition == MacroAssembler::GreaterThan)
6557 compareFunction = operationCompareStringImplGreater;
6558 else if (condition == MacroAssembler::GreaterThanOrEqual)
6559 compareFunction = operationCompareStringImplGreaterEq;
6560 else
6561 RELEASE_ASSERT_NOT_REACHED();
6562
6563 speculateStringIdentAndLoadStorage(node->child1(), leftGPR, leftTempGPR);
6564 speculateStringIdentAndLoadStorage(node->child2(), rightGPR, rightTempGPR);
6565
6566 flushRegisters();
6567 callOperation(compareFunction, resultGPR, leftTempGPR, rightTempGPR);
6568
6569 unblessedBooleanResult(resultGPR, node);
6570}
6571
6572void SpeculativeJIT::compileSameValue(Node* node)
6573{
6574 if (node->isBinaryUseKind(DoubleRepUse)) {
6575 SpeculateDoubleOperand arg1(this, node->child1());
6576 SpeculateDoubleOperand arg2(this, node->child2());
6577 GPRTemporary result(this);
6578 GPRTemporary temp(this);
6579 GPRTemporary temp2(this);
6580
6581 FPRReg arg1FPR = arg1.fpr();
6582 FPRReg arg2FPR = arg2.fpr();
6583 GPRReg resultGPR = result.gpr();
6584 GPRReg tempGPR = temp.gpr();
6585 GPRReg temp2GPR = temp2.gpr();
6586
6587#if USE(JSVALUE64)
6588 m_jit.moveDoubleTo64(arg1FPR, tempGPR);
6589 m_jit.moveDoubleTo64(arg2FPR, temp2GPR);
6590 auto trueCase = m_jit.branch64(CCallHelpers::Equal, tempGPR, temp2GPR);
6591#else
6592 GPRTemporary temp3(this);
6593 GPRReg temp3GPR = temp3.gpr();
6594
6595 m_jit.moveDoubleToInts(arg1FPR, tempGPR, temp2GPR);
6596 m_jit.moveDoubleToInts(arg2FPR, temp3GPR, resultGPR);
6597 auto notEqual = m_jit.branch32(CCallHelpers::NotEqual, tempGPR, temp3GPR);
6598 auto trueCase = m_jit.branch32(CCallHelpers::Equal, temp2GPR, resultGPR);
6599 notEqual.link(&m_jit);
6600#endif
6601
6602 m_jit.compareDouble(CCallHelpers::DoubleNotEqualOrUnordered, arg1FPR, arg1FPR, tempGPR);
6603 m_jit.compareDouble(CCallHelpers::DoubleNotEqualOrUnordered, arg2FPR, arg2FPR, temp2GPR);
6604 m_jit.and32(tempGPR, temp2GPR, resultGPR);
6605 auto done = m_jit.jump();
6606
6607 trueCase.link(&m_jit);
6608 m_jit.move(CCallHelpers::TrustedImm32(1), resultGPR);
6609 done.link(&m_jit);
6610
6611 unblessedBooleanResult(resultGPR, node);
6612 return;
6613 }
6614
6615 ASSERT(node->isBinaryUseKind(UntypedUse));
6616
6617 JSValueOperand arg1(this, node->child1());
6618 JSValueOperand arg2(this, node->child2());
6619 JSValueRegs arg1Regs = arg1.jsValueRegs();
6620 JSValueRegs arg2Regs = arg2.jsValueRegs();
6621
6622 arg1.use();
6623 arg2.use();
6624
6625 flushRegisters();
6626
6627 GPRFlushedCallResult result(this);
6628 GPRReg resultGPR = result.gpr();
6629 callOperation(operationSameValue, resultGPR, arg1Regs, arg2Regs);
6630 m_jit.exceptionCheck();
6631
6632 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
6633}
6634
6635void SpeculativeJIT::compileStringZeroLength(Node* node)
6636{
6637 SpeculateCellOperand str(this, node->child1());
6638 GPRReg strGPR = str.gpr();
6639
6640 // Make sure that this is a string.
6641 speculateString(node->child1(), strGPR);
6642
6643 GPRTemporary eq(this);
6644 GPRReg eqGPR = eq.gpr();
6645
6646 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), eqGPR);
6647 m_jit.comparePtr(CCallHelpers::Equal, strGPR, eqGPR, eqGPR);
6648 unblessedBooleanResult(eqGPR, node);
6649}
6650
6651void SpeculativeJIT::compileLogicalNotStringOrOther(Node* node)
6652{
6653 JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
6654 GPRTemporary temp(this);
6655 JSValueRegs valueRegs = value.jsValueRegs();
6656 GPRReg tempGPR = temp.gpr();
6657
6658 JITCompiler::Jump notCell = m_jit.branchIfNotCell(valueRegs);
6659 GPRReg cellGPR = valueRegs.payloadGPR();
6660 DFG_TYPE_CHECK(
6661 valueRegs, node->child1(), (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cellGPR));
6662
6663 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), tempGPR);
6664 m_jit.comparePtr(CCallHelpers::Equal, cellGPR, tempGPR, tempGPR);
6665 auto done = m_jit.jump();
6666
6667 notCell.link(&m_jit);
6668 DFG_TYPE_CHECK(
6669 valueRegs, node->child1(), SpecCellCheck | SpecOther, m_jit.branchIfNotOther(valueRegs, tempGPR));
6670 m_jit.move(TrustedImm32(1), tempGPR);
6671
6672 done.link(&m_jit);
6673 unblessedBooleanResult(tempGPR, node);
6674
6675}
6676
6677void SpeculativeJIT::emitStringBranch(Edge nodeUse, BasicBlock* taken, BasicBlock* notTaken)
6678{
6679 SpeculateCellOperand str(this, nodeUse);
6680
6681 GPRReg strGPR = str.gpr();
6682
6683 speculateString(nodeUse, strGPR);
6684
6685 branchPtr(CCallHelpers::Equal, strGPR, TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), notTaken);
6686 jump(taken);
6687
6688 noResult(m_currentNode);
6689}
6690
6691void SpeculativeJIT::emitStringOrOtherBranch(Edge nodeUse, BasicBlock* taken, BasicBlock* notTaken)
6692{
6693 JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
6694 GPRTemporary temp(this);
6695 JSValueRegs valueRegs = value.jsValueRegs();
6696 GPRReg tempGPR = temp.gpr();
6697
6698 JITCompiler::Jump notCell = m_jit.branchIfNotCell(valueRegs);
6699 GPRReg cellGPR = valueRegs.payloadGPR();
6700 DFG_TYPE_CHECK(valueRegs, nodeUse, (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cellGPR));
6701
6702 branchPtr(CCallHelpers::Equal, cellGPR, TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), notTaken);
6703 jump(taken, ForceJump);
6704
6705 notCell.link(&m_jit);
6706 DFG_TYPE_CHECK(
6707 valueRegs, nodeUse, SpecCellCheck | SpecOther, m_jit.branchIfNotOther(valueRegs, tempGPR));
6708 jump(notTaken);
6709 noResult(m_currentNode);
6710}
6711
6712void SpeculativeJIT::compileConstantStoragePointer(Node* node)
6713{
6714 GPRTemporary storage(this);
6715 GPRReg storageGPR = storage.gpr();
6716 m_jit.move(TrustedImmPtr(node->storagePointer()), storageGPR);
6717 storageResult(storageGPR, node);
6718}
6719
6720void SpeculativeJIT::cageTypedArrayStorage(GPRReg baseReg, GPRReg storageReg)
6721{
6722#if GIGACAGE_ENABLED
6723 UNUSED_PARAM(baseReg);
6724 if (!Gigacage::shouldBeEnabled())
6725 return;
6726
6727 if (Gigacage::canPrimitiveGigacageBeDisabled()) {
6728 if (m_jit.vm()->primitiveGigacageEnabled().isStillValid())
6729 m_jit.graph().watchpoints().addLazily(m_jit.vm()->primitiveGigacageEnabled());
6730 else
6731 return;
6732 }
6733
6734 m_jit.cage(Gigacage::Primitive, storageReg);
6735#elif CPU(ARM64E)
6736 m_jit.untagArrayPtr(MacroAssembler::Address(baseReg, JSArrayBufferView::offsetOfLength()), storageReg);
6737#else
6738 UNUSED_PARAM(baseReg);
6739 UNUSED_PARAM(storageReg);
6740#endif
6741}
6742
6743void SpeculativeJIT::compileGetIndexedPropertyStorage(Node* node)
6744{
6745 SpeculateCellOperand base(this, node->child1());
6746 GPRReg baseReg = base.gpr();
6747
6748 GPRTemporary storage(this);
6749 GPRReg storageReg = storage.gpr();
6750
6751 switch (node->arrayMode().type()) {
6752 case Array::String:
6753 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), storageReg);
6754
6755 addSlowPathGenerator(
6756 slowPathCall(
6757 m_jit.branchIfRopeStringImpl(storageReg),
6758 this, operationResolveRope, storageReg, baseReg));
6759
6760 m_jit.loadPtr(MacroAssembler::Address(storageReg, StringImpl::dataOffset()), storageReg);
6761 break;
6762
6763 default: {
6764 auto typedArrayType = node->arrayMode().typedArrayType();
6765 ASSERT_UNUSED(typedArrayType, isTypedView(typedArrayType));
6766
6767 m_jit.loadPtr(JITCompiler::Address(baseReg, JSArrayBufferView::offsetOfVector()), storageReg);
6768 cageTypedArrayStorage(baseReg, storageReg);
6769 break;
6770 }
6771 }
6772
6773 storageResult(storageReg, node);
6774}
6775
6776void SpeculativeJIT::compileGetTypedArrayByteOffset(Node* node)
6777{
6778 SpeculateCellOperand base(this, node->child1());
6779 GPRTemporary vector(this);
6780 GPRTemporary data(this);
6781
6782 GPRReg baseGPR = base.gpr();
6783 GPRReg vectorGPR = vector.gpr();
6784 GPRReg dataGPR = data.gpr();
6785 ASSERT(baseGPR != vectorGPR);
6786 ASSERT(baseGPR != dataGPR);
6787 ASSERT(vectorGPR != dataGPR);
6788
6789 GPRReg arrayBufferGPR = dataGPR;
6790
6791 JITCompiler::Jump emptyByteOffset = m_jit.branch32(
6792 MacroAssembler::NotEqual,
6793 MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfMode()),
6794 TrustedImm32(WastefulTypedArray));
6795
6796 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfVector()), vectorGPR);
6797
6798 // FIXME: This should mask the PAC bits
6799 // https://bugs.webkit.org/show_bug.cgi?id=197701
6800 JITCompiler::Jump nullVector = m_jit.branchTestPtr(JITCompiler::Zero, vectorGPR);
6801
6802 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), dataGPR);
6803 m_jit.cage(Gigacage::JSValue, dataGPR);
6804
6805 cageTypedArrayStorage(baseGPR, vectorGPR);
6806
6807 m_jit.loadPtr(MacroAssembler::Address(dataGPR, Butterfly::offsetOfArrayBuffer()), arrayBufferGPR);
6808 // FIXME: This needs caging.
6809 // https://bugs.webkit.org/show_bug.cgi?id=175515
6810 m_jit.loadPtr(MacroAssembler::Address(arrayBufferGPR, ArrayBuffer::offsetOfData()), dataGPR);
6811#if CPU(ARM64E)
6812 m_jit.removeArrayPtrTag(dataGPR);
6813#endif
6814
6815 m_jit.subPtr(dataGPR, vectorGPR);
6816
6817 JITCompiler::Jump done = m_jit.jump();
6818
6819 emptyByteOffset.link(&m_jit);
6820 m_jit.move(TrustedImmPtr(nullptr), vectorGPR);
6821
6822 done.link(&m_jit);
6823 nullVector.link(&m_jit);
6824
6825 int32Result(vectorGPR, node);
6826}
6827
6828void SpeculativeJIT::compileGetByValOnDirectArguments(Node* node)
6829{
6830 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
6831 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
6832 JSValueRegsTemporary result(this);
6833 GPRTemporary scratch(this);
6834
6835 GPRReg baseReg = base.gpr();
6836 GPRReg propertyReg = property.gpr();
6837 JSValueRegs resultRegs = result.regs();
6838 GPRReg scratchReg = scratch.gpr();
6839
6840 if (!m_compileOkay)
6841 return;
6842
6843 ASSERT(ArrayMode(Array::DirectArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.varArgChild(node, 0))));
6844
6845 speculationCheck(
6846 ExoticObjectMode, JSValueSource(), 0,
6847 m_jit.branchTestPtr(
6848 MacroAssembler::NonZero,
6849 MacroAssembler::Address(baseReg, DirectArguments::offsetOfMappedArguments())));
6850
6851 m_jit.load32(CCallHelpers::Address(baseReg, DirectArguments::offsetOfLength()), scratchReg);
6852 auto isOutOfBounds = m_jit.branch32(CCallHelpers::AboveOrEqual, propertyReg, scratchReg);
6853 if (node->arrayMode().isInBounds())
6854 speculationCheck(OutOfBounds, JSValueSource(), 0, isOutOfBounds);
6855
6856 m_jit.loadValue(
6857 MacroAssembler::BaseIndex(
6858 baseReg, propertyReg, MacroAssembler::TimesEight, DirectArguments::storageOffset()),
6859 resultRegs);
6860
6861 if (!node->arrayMode().isInBounds()) {
6862 addSlowPathGenerator(
6863 slowPathCall(
6864 isOutOfBounds, this, operationGetByValObjectInt,
6865 extractResult(resultRegs), baseReg, propertyReg));
6866 }
6867
6868 jsValueResult(resultRegs, node);
6869}
6870
6871void SpeculativeJIT::compileGetByValOnScopedArguments(Node* node)
6872{
6873 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
6874 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
6875 JSValueRegsTemporary result(this);
6876 GPRTemporary scratch(this);
6877 GPRTemporary scratch2(this);
6878 GPRTemporary indexMask(this);
6879
6880 GPRReg baseReg = base.gpr();
6881 GPRReg propertyReg = property.gpr();
6882 JSValueRegs resultRegs = result.regs();
6883 GPRReg scratchReg = scratch.gpr();
6884 GPRReg scratch2Reg = scratch2.gpr();
6885 GPRReg indexMaskReg = indexMask.gpr();
6886
6887 if (!m_compileOkay)
6888 return;
6889
6890 ASSERT(ArrayMode(Array::ScopedArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.varArgChild(node, 0))));
6891
6892 m_jit.loadPtr(
6893 MacroAssembler::Address(baseReg, ScopedArguments::offsetOfStorage()), resultRegs.payloadGPR());
6894 m_jit.load32(
6895 MacroAssembler::Address(resultRegs.payloadGPR(), ScopedArguments::offsetOfTotalLengthInStorage()),
6896 scratchReg);
6897
6898 speculationCheck(
6899 ExoticObjectMode, JSValueSource(), nullptr,
6900 m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, scratchReg));
6901
6902 m_jit.emitPreparePreciseIndexMask32(propertyReg, scratchReg, indexMaskReg);
6903
6904 m_jit.loadPtr(MacroAssembler::Address(baseReg, ScopedArguments::offsetOfTable()), scratchReg);
6905 m_jit.load32(
6906 MacroAssembler::Address(scratchReg, ScopedArgumentsTable::offsetOfLength()), scratch2Reg);
6907
6908 MacroAssembler::Jump overflowArgument = m_jit.branch32(
6909 MacroAssembler::AboveOrEqual, propertyReg, scratch2Reg);
6910
6911 m_jit.loadPtr(MacroAssembler::Address(baseReg, ScopedArguments::offsetOfScope()), scratch2Reg);
6912
6913 m_jit.loadPtr(
6914 MacroAssembler::Address(scratchReg, ScopedArgumentsTable::offsetOfArguments()),
6915 scratchReg);
6916 m_jit.load32(
6917 MacroAssembler::BaseIndex(scratchReg, propertyReg, MacroAssembler::TimesFour),
6918 scratchReg);
6919
6920 speculationCheck(
6921 ExoticObjectMode, JSValueSource(), nullptr,
6922 m_jit.branch32(
6923 MacroAssembler::Equal, scratchReg, TrustedImm32(ScopeOffset::invalidOffset)));
6924
6925 m_jit.loadValue(
6926 MacroAssembler::BaseIndex(
6927 scratch2Reg, propertyReg, MacroAssembler::TimesEight,
6928 JSLexicalEnvironment::offsetOfVariables()),
6929 resultRegs);
6930
6931 MacroAssembler::Jump done = m_jit.jump();
6932 overflowArgument.link(&m_jit);
6933
6934 m_jit.sub32(propertyReg, scratch2Reg);
6935 m_jit.neg32(scratch2Reg);
6936
6937 m_jit.loadValue(
6938 MacroAssembler::BaseIndex(
6939 resultRegs.payloadGPR(), scratch2Reg, MacroAssembler::TimesEight),
6940 resultRegs);
6941 speculationCheck(ExoticObjectMode, JSValueSource(), nullptr, m_jit.branchIfEmpty(resultRegs));
6942
6943 done.link(&m_jit);
6944
6945 m_jit.andPtr(indexMaskReg, resultRegs.payloadGPR());
6946
6947 jsValueResult(resultRegs, node);
6948}
6949
6950void SpeculativeJIT::compileGetScope(Node* node)
6951{
6952 SpeculateCellOperand function(this, node->child1());
6953 GPRTemporary result(this, Reuse, function);
6954 m_jit.loadPtr(JITCompiler::Address(function.gpr(), JSFunction::offsetOfScopeChain()), result.gpr());
6955 cellResult(result.gpr(), node);
6956}
6957
6958void SpeculativeJIT::compileSkipScope(Node* node)
6959{
6960 SpeculateCellOperand scope(this, node->child1());
6961 GPRTemporary result(this, Reuse, scope);
6962 m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSScope::offsetOfNext()), result.gpr());
6963 cellResult(result.gpr(), node);
6964}
6965
6966void SpeculativeJIT::compileGetGlobalObject(Node* node)
6967{
6968 SpeculateCellOperand object(this, node->child1());
6969 GPRTemporary result(this);
6970 GPRTemporary scratch(this);
6971 m_jit.emitLoadStructure(*m_jit.vm(), object.gpr(), result.gpr(), scratch.gpr());
6972 m_jit.loadPtr(JITCompiler::Address(result.gpr(), Structure::globalObjectOffset()), result.gpr());
6973 cellResult(result.gpr(), node);
6974}
6975
6976void SpeculativeJIT::compileGetGlobalThis(Node* node)
6977{
6978 GPRTemporary result(this);
6979 GPRReg resultGPR = result.gpr();
6980 auto* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
6981 m_jit.loadPtr(globalObject->addressOfGlobalThis(), resultGPR);
6982 cellResult(resultGPR, node);
6983}
6984
6985bool SpeculativeJIT::canBeRope(Edge& edge)
6986{
6987 if (m_state.forNode(edge).isType(SpecStringIdent))
6988 return false;
6989 // If this value is LazyValue, it will be converted to JSString, and the result must be non-rope string.
6990 String string = edge->tryGetString(m_graph);
6991 if (!string.isNull())
6992 return false;
6993 return true;
6994}
6995
6996void SpeculativeJIT::compileGetArrayLength(Node* node)
6997{
6998 switch (node->arrayMode().type()) {
6999 case Array::Undecided:
7000 case Array::Int32:
7001 case Array::Double:
7002 case Array::Contiguous: {
7003 StorageOperand storage(this, node->child2());
7004 GPRTemporary result(this, Reuse, storage);
7005 GPRReg storageReg = storage.gpr();
7006 GPRReg resultReg = result.gpr();
7007 m_jit.load32(MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()), resultReg);
7008
7009 int32Result(resultReg, node);
7010 break;
7011 }
7012 case Array::ArrayStorage:
7013 case Array::SlowPutArrayStorage: {
7014 StorageOperand storage(this, node->child2());
7015 GPRTemporary result(this, Reuse, storage);
7016 GPRReg storageReg = storage.gpr();
7017 GPRReg resultReg = result.gpr();
7018 m_jit.load32(MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()), resultReg);
7019
7020 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, resultReg, MacroAssembler::TrustedImm32(0)));
7021
7022 int32Result(resultReg, node);
7023 break;
7024 }
7025 case Array::String: {
7026 SpeculateCellOperand base(this, node->child1());
7027 GPRTemporary result(this, Reuse, base);
7028 GPRTemporary temp(this);
7029 GPRReg baseGPR = base.gpr();
7030 GPRReg resultGPR = result.gpr();
7031 GPRReg tempGPR = temp.gpr();
7032
7033 bool needsRopeCase = canBeRope(node->child1());
7034
7035 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSString::offsetOfValue()), tempGPR);
7036 CCallHelpers::Jump isRope;
7037 if (needsRopeCase)
7038 isRope = m_jit.branchIfRopeStringImpl(tempGPR);
7039 m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), resultGPR);
7040 if (needsRopeCase) {
7041 auto done = m_jit.jump();
7042
7043 isRope.link(&m_jit);
7044 m_jit.load32(CCallHelpers::Address(baseGPR, JSRopeString::offsetOfLength()), resultGPR);
7045
7046 done.link(&m_jit);
7047 }
7048 int32Result(resultGPR, node);
7049 break;
7050 }
7051 case Array::DirectArguments: {
7052 SpeculateCellOperand base(this, node->child1());
7053 GPRTemporary result(this, Reuse, base);
7054
7055 GPRReg baseReg = base.gpr();
7056 GPRReg resultReg = result.gpr();
7057
7058 if (!m_compileOkay)
7059 return;
7060
7061 ASSERT(ArrayMode(Array::DirectArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1())));
7062
7063 speculationCheck(
7064 ExoticObjectMode, JSValueSource(), 0,
7065 m_jit.branchTestPtr(
7066 MacroAssembler::NonZero,
7067 MacroAssembler::Address(baseReg, DirectArguments::offsetOfMappedArguments())));
7068
7069 m_jit.load32(
7070 MacroAssembler::Address(baseReg, DirectArguments::offsetOfLength()), resultReg);
7071
7072 int32Result(resultReg, node);
7073 break;
7074 }
7075 case Array::ScopedArguments: {
7076 SpeculateCellOperand base(this, node->child1());
7077 GPRTemporary result(this);
7078
7079 GPRReg baseReg = base.gpr();
7080 GPRReg resultReg = result.gpr();
7081
7082 if (!m_compileOkay)
7083 return;
7084
7085 ASSERT(ArrayMode(Array::ScopedArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1())));
7086
7087 m_jit.loadPtr(
7088 MacroAssembler::Address(baseReg, ScopedArguments::offsetOfStorage()), resultReg);
7089
7090 speculationCheck(
7091 ExoticObjectMode, JSValueSource(), 0,
7092 m_jit.branchTest8(
7093 MacroAssembler::NonZero,
7094 MacroAssembler::Address(resultReg, ScopedArguments::offsetOfOverrodeThingsInStorage())));
7095
7096 m_jit.load32(
7097 MacroAssembler::Address(resultReg, ScopedArguments::offsetOfTotalLengthInStorage()), resultReg);
7098
7099 int32Result(resultReg, node);
7100 break;
7101 }
7102 default: {
7103 ASSERT(node->arrayMode().isSomeTypedArrayView());
7104 SpeculateCellOperand base(this, node->child1());
7105 GPRTemporary result(this, Reuse, base);
7106 GPRReg baseGPR = base.gpr();
7107 GPRReg resultGPR = result.gpr();
7108 m_jit.load32(MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfLength()), resultGPR);
7109 int32Result(resultGPR, node);
7110 break;
7111 } }
7112}
7113
7114void SpeculativeJIT::compileCheckStringIdent(Node* node)
7115{
7116 SpeculateCellOperand string(this, node->child1());
7117 GPRTemporary storage(this);
7118
7119 GPRReg stringGPR = string.gpr();
7120 GPRReg storageGPR = storage.gpr();
7121
7122 speculateString(node->child1(), stringGPR);
7123 speculateStringIdentAndLoadStorage(node->child1(), stringGPR, storageGPR);
7124
7125 UniquedStringImpl* uid = node->uidOperand();
7126 speculationCheck(
7127 BadIdent, JSValueSource(), nullptr,
7128 m_jit.branchPtr(JITCompiler::NotEqual, storageGPR, TrustedImmPtr(uid)));
7129 noResult(node);
7130}
7131
7132template <typename ClassType>
7133void SpeculativeJIT::compileNewFunctionCommon(GPRReg resultGPR, RegisteredStructure structure, GPRReg scratch1GPR, GPRReg scratch2GPR, GPRReg scopeGPR, MacroAssembler::JumpList& slowPath, size_t size, FunctionExecutable* executable)
7134{
7135 auto butterfly = TrustedImmPtr(nullptr);
7136 emitAllocateJSObjectWithKnownSize<ClassType>(resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR, slowPath, size);
7137
7138 m_jit.storePtr(scopeGPR, JITCompiler::Address(resultGPR, JSFunction::offsetOfScopeChain()));
7139 m_jit.storePtr(TrustedImmPtr::weakPointer(m_jit.graph(), executable), JITCompiler::Address(resultGPR, JSFunction::offsetOfExecutable()));
7140 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, JSFunction::offsetOfRareData()));
7141
7142 m_jit.mutatorFence(*m_jit.vm());
7143}
7144
7145void SpeculativeJIT::compileNewFunction(Node* node)
7146{
7147 NodeType nodeType = node->op();
7148 ASSERT(nodeType == NewFunction || nodeType == NewGeneratorFunction || nodeType == NewAsyncFunction || nodeType == NewAsyncGeneratorFunction);
7149
7150 SpeculateCellOperand scope(this, node->child1());
7151 GPRReg scopeGPR = scope.gpr();
7152
7153 FunctionExecutable* executable = node->castOperand<FunctionExecutable*>();
7154
7155 if (executable->singletonFunction()->isStillValid()) {
7156 GPRFlushedCallResult result(this);
7157 GPRReg resultGPR = result.gpr();
7158
7159 flushRegisters();
7160
7161 if (nodeType == NewGeneratorFunction)
7162 callOperation(operationNewGeneratorFunction, resultGPR, scopeGPR, executable);
7163 else if (nodeType == NewAsyncFunction)
7164 callOperation(operationNewAsyncFunction, resultGPR, scopeGPR, executable);
7165 else if (nodeType == NewAsyncGeneratorFunction)
7166 callOperation(operationNewAsyncGeneratorFunction, resultGPR, scopeGPR, executable);
7167 else
7168 callOperation(operationNewFunction, resultGPR, scopeGPR, executable);
7169 m_jit.exceptionCheck();
7170 cellResult(resultGPR, node);
7171 return;
7172 }
7173
7174 RegisteredStructure structure = m_jit.graph().registerStructure(
7175 [&] () {
7176 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
7177 switch (nodeType) {
7178 case NewGeneratorFunction:
7179 return globalObject->generatorFunctionStructure();
7180 case NewAsyncFunction:
7181 return globalObject->asyncFunctionStructure();
7182 case NewAsyncGeneratorFunction:
7183 return globalObject->asyncGeneratorFunctionStructure();
7184 case NewFunction:
7185 return JSFunction::selectStructureForNewFuncExp(globalObject, node->castOperand<FunctionExecutable*>());
7186 default:
7187 RELEASE_ASSERT_NOT_REACHED();
7188 }
7189 }());
7190
7191 GPRTemporary result(this);
7192 GPRTemporary scratch1(this);
7193 GPRTemporary scratch2(this);
7194
7195 GPRReg resultGPR = result.gpr();
7196 GPRReg scratch1GPR = scratch1.gpr();
7197 GPRReg scratch2GPR = scratch2.gpr();
7198
7199 JITCompiler::JumpList slowPath;
7200
7201 if (nodeType == NewFunction) {
7202 compileNewFunctionCommon<JSFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSFunction::allocationSize(0), executable);
7203
7204 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable));
7205 }
7206
7207 if (nodeType == NewGeneratorFunction) {
7208 compileNewFunctionCommon<JSGeneratorFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSGeneratorFunction::allocationSize(0), executable);
7209
7210 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewGeneratorFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable));
7211 }
7212
7213 if (nodeType == NewAsyncFunction) {
7214 compileNewFunctionCommon<JSAsyncFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSAsyncFunction::allocationSize(0), executable);
7215
7216 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewAsyncFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable));
7217 }
7218
7219 if (nodeType == NewAsyncGeneratorFunction) {
7220 compileNewFunctionCommon<JSAsyncGeneratorFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSAsyncGeneratorFunction::allocationSize(0), executable);
7221
7222 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewAsyncGeneratorFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable));
7223 }
7224
7225 cellResult(resultGPR, node);
7226}
7227
7228void SpeculativeJIT::compileSetFunctionName(Node* node)
7229{
7230 SpeculateCellOperand func(this, node->child1());
7231 GPRReg funcGPR = func.gpr();
7232 JSValueOperand nameValue(this, node->child2());
7233 JSValueRegs nameValueRegs = nameValue.jsValueRegs();
7234
7235 flushRegisters();
7236 callOperation(operationSetFunctionName, funcGPR, nameValueRegs);
7237 m_jit.exceptionCheck();
7238
7239 noResult(node);
7240}
7241
7242void SpeculativeJIT::compileLoadVarargs(Node* node)
7243{
7244 LoadVarargsData* data = node->loadVarargsData();
7245
7246 JSValueRegs argumentsRegs;
7247 {
7248 JSValueOperand arguments(this, node->child1());
7249 argumentsRegs = arguments.jsValueRegs();
7250 flushRegisters();
7251 }
7252
7253 callOperation(operationSizeOfVarargs, GPRInfo::returnValueGPR, argumentsRegs, data->offset);
7254 m_jit.exceptionCheck();
7255
7256 lock(GPRInfo::returnValueGPR);
7257 {
7258 JSValueOperand arguments(this, node->child1());
7259 argumentsRegs = arguments.jsValueRegs();
7260 flushRegisters();
7261 }
7262 unlock(GPRInfo::returnValueGPR);
7263
7264 // FIXME: There is a chance that we will call an effectful length property twice. This is safe
7265 // from the standpoint of the VM's integrity, but it's subtly wrong from a spec compliance
7266 // standpoint. The best solution would be one where we can exit *into* the op_call_varargs right
7267 // past the sizing.
7268 // https://bugs.webkit.org/show_bug.cgi?id=141448
7269
7270 GPRReg argCountIncludingThisGPR =
7271 JITCompiler::selectScratchGPR(GPRInfo::returnValueGPR, argumentsRegs);
7272
7273 m_jit.add32(TrustedImm32(1), GPRInfo::returnValueGPR, argCountIncludingThisGPR);
7274
7275 speculationCheck(
7276 VarargsOverflow, JSValueSource(), Edge(), m_jit.branch32(
7277 MacroAssembler::Above,
7278 GPRInfo::returnValueGPR,
7279 argCountIncludingThisGPR));
7280
7281 speculationCheck(
7282 VarargsOverflow, JSValueSource(), Edge(), m_jit.branch32(
7283 MacroAssembler::Above,
7284 argCountIncludingThisGPR,
7285 TrustedImm32(data->limit)));
7286
7287 m_jit.store32(argCountIncludingThisGPR, JITCompiler::payloadFor(data->machineCount));
7288
7289 callOperation(operationLoadVarargs, data->machineStart.offset(), argumentsRegs, data->offset, GPRInfo::returnValueGPR, data->mandatoryMinimum);
7290 m_jit.exceptionCheck();
7291
7292 noResult(node);
7293}
7294
7295void SpeculativeJIT::compileForwardVarargs(Node* node)
7296{
7297 LoadVarargsData* data = node->loadVarargsData();
7298 InlineCallFrame* inlineCallFrame;
7299 if (node->child1())
7300 inlineCallFrame = node->child1()->origin.semantic.inlineCallFrame();
7301 else
7302 inlineCallFrame = node->origin.semantic.inlineCallFrame();
7303
7304 GPRTemporary length(this);
7305 JSValueRegsTemporary temp(this);
7306 GPRReg lengthGPR = length.gpr();
7307 JSValueRegs tempRegs = temp.regs();
7308
7309 emitGetLength(inlineCallFrame, lengthGPR, /* includeThis = */ true);
7310 if (data->offset)
7311 m_jit.sub32(TrustedImm32(data->offset), lengthGPR);
7312
7313 speculationCheck(
7314 VarargsOverflow, JSValueSource(), Edge(), m_jit.branch32(
7315 MacroAssembler::Above,
7316 lengthGPR, TrustedImm32(data->limit)));
7317
7318 m_jit.store32(lengthGPR, JITCompiler::payloadFor(data->machineCount));
7319
7320 VirtualRegister sourceStart = JITCompiler::argumentsStart(inlineCallFrame) + data->offset;
7321 VirtualRegister targetStart = data->machineStart;
7322
7323 m_jit.sub32(TrustedImm32(1), lengthGPR);
7324
7325 // First have a loop that fills in the undefined slots in case of an arity check failure.
7326 m_jit.move(TrustedImm32(data->mandatoryMinimum), tempRegs.payloadGPR());
7327 JITCompiler::Jump done = m_jit.branch32(JITCompiler::BelowOrEqual, tempRegs.payloadGPR(), lengthGPR);
7328
7329 JITCompiler::Label loop = m_jit.label();
7330 m_jit.sub32(TrustedImm32(1), tempRegs.payloadGPR());
7331 m_jit.storeTrustedValue(
7332 jsUndefined(),
7333 JITCompiler::BaseIndex(
7334 GPRInfo::callFrameRegister, tempRegs.payloadGPR(), JITCompiler::TimesEight,
7335 targetStart.offset() * sizeof(EncodedJSValue)));
7336 m_jit.branch32(JITCompiler::Above, tempRegs.payloadGPR(), lengthGPR).linkTo(loop, &m_jit);
7337 done.link(&m_jit);
7338
7339 // And then fill in the actual argument values.
7340 done = m_jit.branchTest32(JITCompiler::Zero, lengthGPR);
7341
7342 loop = m_jit.label();
7343 m_jit.sub32(TrustedImm32(1), lengthGPR);
7344 m_jit.loadValue(
7345 JITCompiler::BaseIndex(
7346 GPRInfo::callFrameRegister, lengthGPR, JITCompiler::TimesEight,
7347 sourceStart.offset() * sizeof(EncodedJSValue)),
7348 tempRegs);
7349 m_jit.storeValue(
7350 tempRegs,
7351 JITCompiler::BaseIndex(
7352 GPRInfo::callFrameRegister, lengthGPR, JITCompiler::TimesEight,
7353 targetStart.offset() * sizeof(EncodedJSValue)));
7354 m_jit.branchTest32(JITCompiler::NonZero, lengthGPR).linkTo(loop, &m_jit);
7355
7356 done.link(&m_jit);
7357
7358 noResult(node);
7359}
7360
7361void SpeculativeJIT::compileCreateActivation(Node* node)
7362{
7363 SymbolTable* table = node->castOperand<SymbolTable*>();
7364 RegisteredStructure structure = m_jit.graph().registerStructure(m_jit.graph().globalObjectFor(
7365 node->origin.semantic)->activationStructure());
7366
7367 SpeculateCellOperand scope(this, node->child1());
7368 GPRReg scopeGPR = scope.gpr();
7369 JSValue initializationValue = node->initializationValueForActivation();
7370 ASSERT(initializationValue == jsUndefined() || initializationValue == jsTDZValue());
7371
7372 if (table->singletonScope()->isStillValid()) {
7373 GPRFlushedCallResult result(this);
7374 GPRReg resultGPR = result.gpr();
7375
7376#if USE(JSVALUE32_64)
7377 JSValueRegsTemporary initialization(this);
7378 JSValueRegs initializationRegs = initialization.regs();
7379 m_jit.moveTrustedValue(initializationValue, initializationRegs);
7380#endif
7381
7382 flushRegisters();
7383
7384#if USE(JSVALUE64)
7385 callOperation(operationCreateActivationDirect,
7386 resultGPR, structure, scopeGPR, table, TrustedImm64(JSValue::encode(initializationValue)));
7387#else
7388 callOperation(operationCreateActivationDirect,
7389 resultGPR, structure, scopeGPR, table, initializationRegs);
7390#endif
7391 m_jit.exceptionCheck();
7392 cellResult(resultGPR, node);
7393 return;
7394 }
7395
7396 GPRTemporary result(this);
7397 GPRTemporary scratch1(this);
7398 GPRTemporary scratch2(this);
7399 GPRReg resultGPR = result.gpr();
7400 GPRReg scratch1GPR = scratch1.gpr();
7401 GPRReg scratch2GPR = scratch2.gpr();
7402
7403#if USE(JSVALUE32_64)
7404 JSValueRegsTemporary initialization(this);
7405 JSValueRegs initializationRegs = initialization.regs();
7406 m_jit.moveTrustedValue(initializationValue, initializationRegs);
7407#endif
7408
7409 JITCompiler::JumpList slowPath;
7410 auto butterfly = TrustedImmPtr(nullptr);
7411 emitAllocateJSObjectWithKnownSize<JSLexicalEnvironment>(
7412 resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR,
7413 slowPath, JSLexicalEnvironment::allocationSize(table));
7414
7415 // Don't need a memory barriers since we just fast-created the activation, so the
7416 // activation must be young.
7417 m_jit.storePtr(scopeGPR, JITCompiler::Address(resultGPR, JSScope::offsetOfNext()));
7418 m_jit.storePtr(
7419 TrustedImmPtr(node->cellOperand()),
7420 JITCompiler::Address(resultGPR, JSLexicalEnvironment::offsetOfSymbolTable()));
7421
7422 // Must initialize all members to undefined or the TDZ empty value.
7423 for (unsigned i = 0; i < table->scopeSize(); ++i) {
7424 m_jit.storeTrustedValue(
7425 initializationValue,
7426 JITCompiler::Address(
7427 resultGPR, JSLexicalEnvironment::offsetOfVariable(ScopeOffset(i))));
7428 }
7429
7430 m_jit.mutatorFence(*m_jit.vm());
7431
7432#if USE(JSVALUE64)
7433 addSlowPathGenerator(
7434 slowPathCall(
7435 slowPath, this, operationCreateActivationDirect, resultGPR, structure, scopeGPR, table, TrustedImm64(JSValue::encode(initializationValue))));
7436#else
7437 addSlowPathGenerator(
7438 slowPathCall(
7439 slowPath, this, operationCreateActivationDirect, resultGPR, structure, scopeGPR, table, initializationRegs));
7440#endif
7441
7442 cellResult(resultGPR, node);
7443}
7444
7445void SpeculativeJIT::compileCreateDirectArguments(Node* node)
7446{
7447 // FIXME: A more effective way of dealing with the argument count and callee is to have
7448 // them be explicit arguments to this node.
7449 // https://bugs.webkit.org/show_bug.cgi?id=142207
7450
7451 GPRTemporary result(this);
7452 GPRTemporary scratch1(this);
7453 GPRTemporary scratch2(this);
7454 GPRTemporary length;
7455 GPRReg resultGPR = result.gpr();
7456 GPRReg scratch1GPR = scratch1.gpr();
7457 GPRReg scratch2GPR = scratch2.gpr();
7458 GPRReg lengthGPR = InvalidGPRReg;
7459 JSValueRegs valueRegs = JSValueRegs::withTwoAvailableRegs(scratch1GPR, scratch2GPR);
7460
7461 unsigned minCapacity = m_jit.graph().baselineCodeBlockFor(node->origin.semantic)->numParameters() - 1;
7462
7463 unsigned knownLength;
7464 bool lengthIsKnown; // if false, lengthGPR will have the length.
7465 auto* inlineCallFrame = node->origin.semantic.inlineCallFrame();
7466 if (inlineCallFrame
7467 && !inlineCallFrame->isVarargs()) {
7468 knownLength = inlineCallFrame->argumentCountIncludingThis - 1;
7469 lengthIsKnown = true;
7470 } else {
7471 knownLength = UINT_MAX;
7472 lengthIsKnown = false;
7473
7474 GPRTemporary realLength(this);
7475 length.adopt(realLength);
7476 lengthGPR = length.gpr();
7477
7478 VirtualRegister argumentCountRegister = m_jit.argumentCount(node->origin.semantic);
7479 m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), lengthGPR);
7480 m_jit.sub32(TrustedImm32(1), lengthGPR);
7481 }
7482
7483 RegisteredStructure structure =
7484 m_jit.graph().registerStructure(m_jit.graph().globalObjectFor(node->origin.semantic)->directArgumentsStructure());
7485
7486 // Use a different strategy for allocating the object depending on whether we know its
7487 // size statically.
7488 JITCompiler::JumpList slowPath;
7489 if (lengthIsKnown) {
7490 auto butterfly = TrustedImmPtr(nullptr);
7491 emitAllocateJSObjectWithKnownSize<DirectArguments>(
7492 resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR,
7493 slowPath, DirectArguments::allocationSize(std::max(knownLength, minCapacity)));
7494
7495 m_jit.store32(
7496 TrustedImm32(knownLength),
7497 JITCompiler::Address(resultGPR, DirectArguments::offsetOfLength()));
7498 } else {
7499 JITCompiler::Jump tooFewArguments;
7500 if (minCapacity) {
7501 tooFewArguments =
7502 m_jit.branch32(JITCompiler::Below, lengthGPR, TrustedImm32(minCapacity));
7503 }
7504 m_jit.lshift32(lengthGPR, TrustedImm32(3), scratch1GPR);
7505 m_jit.add32(TrustedImm32(DirectArguments::storageOffset()), scratch1GPR);
7506 if (minCapacity) {
7507 JITCompiler::Jump done = m_jit.jump();
7508 tooFewArguments.link(&m_jit);
7509 m_jit.move(TrustedImm32(DirectArguments::allocationSize(minCapacity)), scratch1GPR);
7510 done.link(&m_jit);
7511 }
7512
7513 emitAllocateVariableSizedJSObject<DirectArguments>(
7514 resultGPR, TrustedImmPtr(structure), scratch1GPR, scratch1GPR, scratch2GPR,
7515 slowPath);
7516
7517 m_jit.store32(
7518 lengthGPR, JITCompiler::Address(resultGPR, DirectArguments::offsetOfLength()));
7519 }
7520
7521 m_jit.store32(
7522 TrustedImm32(minCapacity),
7523 JITCompiler::Address(resultGPR, DirectArguments::offsetOfMinCapacity()));
7524
7525 m_jit.storePtr(
7526 TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, DirectArguments::offsetOfMappedArguments()));
7527
7528 m_jit.storePtr(
7529 TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, DirectArguments::offsetOfModifiedArgumentsDescriptor()));
7530
7531 if (lengthIsKnown) {
7532 addSlowPathGenerator(
7533 slowPathCall(
7534 slowPath, this, operationCreateDirectArguments, resultGPR, structure,
7535 knownLength, minCapacity));
7536 } else {
7537 auto generator = std::make_unique<CallCreateDirectArgumentsSlowPathGenerator>(
7538 slowPath, this, resultGPR, structure, lengthGPR, minCapacity);
7539 addSlowPathGenerator(WTFMove(generator));
7540 }
7541
7542 if (inlineCallFrame) {
7543 if (inlineCallFrame->isClosureCall) {
7544 m_jit.loadPtr(
7545 JITCompiler::addressFor(
7546 inlineCallFrame->calleeRecovery.virtualRegister()),
7547 scratch1GPR);
7548 } else {
7549 m_jit.move(
7550 TrustedImmPtr::weakPointer(
7551 m_jit.graph(), inlineCallFrame->calleeRecovery.constant().asCell()),
7552 scratch1GPR);
7553 }
7554 } else
7555 m_jit.loadPtr(JITCompiler::addressFor(CallFrameSlot::callee), scratch1GPR);
7556
7557 // Don't need a memory barriers since we just fast-created the activation, so the
7558 // activation must be young.
7559 m_jit.storePtr(
7560 scratch1GPR, JITCompiler::Address(resultGPR, DirectArguments::offsetOfCallee()));
7561
7562 VirtualRegister start = m_jit.argumentsStart(node->origin.semantic);
7563 if (lengthIsKnown) {
7564 for (unsigned i = 0; i < std::max(knownLength, minCapacity); ++i) {
7565 m_jit.loadValue(JITCompiler::addressFor(start + i), valueRegs);
7566 m_jit.storeValue(
7567 valueRegs, JITCompiler::Address(resultGPR, DirectArguments::offsetOfSlot(i)));
7568 }
7569 } else {
7570 JITCompiler::Jump done;
7571 if (minCapacity) {
7572 JITCompiler::Jump startLoop = m_jit.branch32(
7573 JITCompiler::AboveOrEqual, lengthGPR, TrustedImm32(minCapacity));
7574 m_jit.move(TrustedImm32(minCapacity), lengthGPR);
7575 startLoop.link(&m_jit);
7576 } else
7577 done = m_jit.branchTest32(MacroAssembler::Zero, lengthGPR);
7578 JITCompiler::Label loop = m_jit.label();
7579 m_jit.sub32(TrustedImm32(1), lengthGPR);
7580 m_jit.loadValue(
7581 JITCompiler::BaseIndex(
7582 GPRInfo::callFrameRegister, lengthGPR, JITCompiler::TimesEight,
7583 start.offset() * static_cast<int>(sizeof(Register))),
7584 valueRegs);
7585 m_jit.storeValue(
7586 valueRegs,
7587 JITCompiler::BaseIndex(
7588 resultGPR, lengthGPR, JITCompiler::TimesEight,
7589 DirectArguments::storageOffset()));
7590 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loop, &m_jit);
7591 if (done.isSet())
7592 done.link(&m_jit);
7593 }
7594
7595 m_jit.mutatorFence(*m_jit.vm());
7596
7597 cellResult(resultGPR, node);
7598}
7599
7600void SpeculativeJIT::compileGetFromArguments(Node* node)
7601{
7602 SpeculateCellOperand arguments(this, node->child1());
7603 JSValueRegsTemporary result(this);
7604
7605 GPRReg argumentsGPR = arguments.gpr();
7606 JSValueRegs resultRegs = result.regs();
7607
7608 m_jit.loadValue(JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfSlot(node->capturedArgumentsOffset().offset())), resultRegs);
7609 jsValueResult(resultRegs, node);
7610}
7611
7612void SpeculativeJIT::compilePutToArguments(Node* node)
7613{
7614 SpeculateCellOperand arguments(this, node->child1());
7615 JSValueOperand value(this, node->child2());
7616
7617 GPRReg argumentsGPR = arguments.gpr();
7618 JSValueRegs valueRegs = value.jsValueRegs();
7619
7620 m_jit.storeValue(valueRegs, JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfSlot(node->capturedArgumentsOffset().offset())));
7621 noResult(node);
7622}
7623
7624void SpeculativeJIT::compileGetArgument(Node* node)
7625{
7626 GPRTemporary argumentCount(this);
7627 JSValueRegsTemporary result(this);
7628 GPRReg argumentCountGPR = argumentCount.gpr();
7629 JSValueRegs resultRegs = result.regs();
7630 m_jit.load32(CCallHelpers::payloadFor(m_jit.argumentCount(node->origin.semantic)), argumentCountGPR);
7631 auto argumentOutOfBounds = m_jit.branch32(CCallHelpers::LessThanOrEqual, argumentCountGPR, CCallHelpers::TrustedImm32(node->argumentIndex()));
7632 m_jit.loadValue(CCallHelpers::addressFor(CCallHelpers::argumentsStart(node->origin.semantic) + node->argumentIndex() - 1), resultRegs);
7633 auto done = m_jit.jump();
7634
7635 argumentOutOfBounds.link(&m_jit);
7636 m_jit.moveValue(jsUndefined(), resultRegs);
7637
7638 done.link(&m_jit);
7639 jsValueResult(resultRegs, node);
7640}
7641
7642void SpeculativeJIT::compileCreateScopedArguments(Node* node)
7643{
7644 SpeculateCellOperand scope(this, node->child1());
7645 GPRReg scopeGPR = scope.gpr();
7646
7647 GPRFlushedCallResult result(this);
7648 GPRReg resultGPR = result.gpr();
7649 flushRegisters();
7650
7651 // We set up the arguments ourselves, because we have the whole register file and we can
7652 // set them up directly into the argument registers. This also means that we don't have to
7653 // invent a four-argument-register shuffle.
7654
7655 // Arguments: 0:exec, 1:structure, 2:start, 3:length, 4:callee, 5:scope
7656
7657 // Do the scopeGPR first, since it might alias an argument register.
7658 m_jit.setupArgument(5, [&] (GPRReg destGPR) { m_jit.move(scopeGPR, destGPR); });
7659
7660 // These other things could be done in any order.
7661 m_jit.setupArgument(4, [&] (GPRReg destGPR) { emitGetCallee(node->origin.semantic, destGPR); });
7662 m_jit.setupArgument(3, [&] (GPRReg destGPR) { emitGetLength(node->origin.semantic, destGPR); });
7663 m_jit.setupArgument(2, [&] (GPRReg destGPR) { emitGetArgumentStart(node->origin.semantic, destGPR); });
7664 m_jit.setupArgument(
7665 1, [&] (GPRReg destGPR) {
7666 m_jit.move(
7667 TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.globalObjectFor(node->origin.semantic)->scopedArgumentsStructure()),
7668 destGPR);
7669 });
7670 m_jit.setupArgument(0, [&] (GPRReg destGPR) { m_jit.move(GPRInfo::callFrameRegister, destGPR); });
7671
7672 appendCallSetResult(operationCreateScopedArguments, resultGPR);
7673 m_jit.exceptionCheck();
7674
7675 cellResult(resultGPR, node);
7676}
7677
7678void SpeculativeJIT::compileCreateClonedArguments(Node* node)
7679{
7680 GPRFlushedCallResult result(this);
7681 GPRReg resultGPR = result.gpr();
7682 flushRegisters();
7683
7684 // We set up the arguments ourselves, because we have the whole register file and we can
7685 // set them up directly into the argument registers.
7686
7687 // Arguments: 0:exec, 1:structure, 2:start, 3:length, 4:callee
7688 m_jit.setupArgument(4, [&] (GPRReg destGPR) { emitGetCallee(node->origin.semantic, destGPR); });
7689 m_jit.setupArgument(3, [&] (GPRReg destGPR) { emitGetLength(node->origin.semantic, destGPR); });
7690 m_jit.setupArgument(2, [&] (GPRReg destGPR) { emitGetArgumentStart(node->origin.semantic, destGPR); });
7691 m_jit.setupArgument(
7692 1, [&] (GPRReg destGPR) {
7693 m_jit.move(
7694 TrustedImmPtr::weakPointer(
7695 m_jit.graph(), m_jit.globalObjectFor(node->origin.semantic)->clonedArgumentsStructure()),
7696 destGPR);
7697 });
7698 m_jit.setupArgument(0, [&] (GPRReg destGPR) { m_jit.move(GPRInfo::callFrameRegister, destGPR); });
7699
7700 appendCallSetResult(operationCreateClonedArguments, resultGPR);
7701 m_jit.exceptionCheck();
7702
7703 cellResult(resultGPR, node);
7704}
7705
7706void SpeculativeJIT::compileCreateRest(Node* node)
7707{
7708 ASSERT(node->op() == CreateRest);
7709
7710#if !CPU(X86)
7711 if (m_jit.graph().isWatchingHavingABadTimeWatchpoint(node)) {
7712 SpeculateStrictInt32Operand arrayLength(this, node->child1());
7713 GPRTemporary arrayResult(this);
7714
7715 GPRReg arrayLengthGPR = arrayLength.gpr();
7716 GPRReg arrayResultGPR = arrayResult.gpr();
7717
7718 // We can tell compileAllocateNewArrayWithSize() that it does not need to check
7719 // for large arrays and use ArrayStorage structure because arrayLength here will
7720 // always be bounded by stack size. Realistically, we won't be able to push enough
7721 // arguments to have arrayLength exceed MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH.
7722 bool shouldAllowForArrayStorageStructureForLargeArrays = false;
7723 ASSERT(m_jit.graph().globalObjectFor(node->origin.semantic)->restParameterStructure()->indexingMode() == ArrayWithContiguous || m_jit.graph().globalObjectFor(node->origin.semantic)->isHavingABadTime());
7724 compileAllocateNewArrayWithSize(m_jit.graph().globalObjectFor(node->origin.semantic), arrayResultGPR, arrayLengthGPR, ArrayWithContiguous, shouldAllowForArrayStorageStructureForLargeArrays);
7725
7726 GPRTemporary argumentsStart(this);
7727 GPRReg argumentsStartGPR = argumentsStart.gpr();
7728
7729 emitGetArgumentStart(node->origin.semantic, argumentsStartGPR);
7730
7731 GPRTemporary butterfly(this);
7732 GPRTemporary currentLength(this);
7733 JSValueRegsTemporary value(this);
7734
7735 JSValueRegs valueRegs = value.regs();
7736 GPRReg currentLengthGPR = currentLength.gpr();
7737 GPRReg butterflyGPR = butterfly.gpr();
7738
7739 m_jit.loadPtr(MacroAssembler::Address(arrayResultGPR, JSObject::butterflyOffset()), butterflyGPR);
7740
7741 CCallHelpers::Jump skipLoop = m_jit.branch32(MacroAssembler::Equal, arrayLengthGPR, TrustedImm32(0));
7742 m_jit.zeroExtend32ToPtr(arrayLengthGPR, currentLengthGPR);
7743 m_jit.addPtr(Imm32(sizeof(Register) * node->numberOfArgumentsToSkip()), argumentsStartGPR);
7744
7745 auto loop = m_jit.label();
7746 m_jit.sub32(TrustedImm32(1), currentLengthGPR);
7747 m_jit.loadValue(JITCompiler::BaseIndex(argumentsStartGPR, currentLengthGPR, MacroAssembler::TimesEight), valueRegs);
7748 m_jit.storeValue(valueRegs, MacroAssembler::BaseIndex(butterflyGPR, currentLengthGPR, MacroAssembler::TimesEight));
7749 m_jit.branch32(MacroAssembler::NotEqual, currentLengthGPR, TrustedImm32(0)).linkTo(loop, &m_jit);
7750
7751 skipLoop.link(&m_jit);
7752 cellResult(arrayResultGPR, node);
7753 return;
7754 }
7755#endif // !CPU(X86)
7756
7757 SpeculateStrictInt32Operand arrayLength(this, node->child1());
7758 GPRTemporary argumentsStart(this);
7759 GPRTemporary numberOfArgumentsToSkip(this);
7760
7761 GPRReg arrayLengthGPR = arrayLength.gpr();
7762 GPRReg argumentsStartGPR = argumentsStart.gpr();
7763
7764 emitGetArgumentStart(node->origin.semantic, argumentsStartGPR);
7765
7766 flushRegisters();
7767
7768 GPRFlushedCallResult result(this);
7769 GPRReg resultGPR = result.gpr();
7770 callOperation(operationCreateRest, resultGPR, argumentsStartGPR, Imm32(node->numberOfArgumentsToSkip()), arrayLengthGPR);
7771 m_jit.exceptionCheck();
7772
7773 cellResult(resultGPR, node);
7774}
7775
7776void SpeculativeJIT::compileSpread(Node* node)
7777{
7778 ASSERT(node->op() == Spread);
7779
7780 SpeculateCellOperand operand(this, node->child1());
7781 GPRReg argument = operand.gpr();
7782
7783 if (node->child1().useKind() == ArrayUse)
7784 speculateArray(node->child1(), argument);
7785
7786 if (m_jit.graph().canDoFastSpread(node, m_state.forNode(node->child1()))) {
7787#if USE(JSVALUE64)
7788 GPRTemporary result(this);
7789 GPRTemporary scratch1(this);
7790 GPRTemporary scratch2(this);
7791 GPRTemporary length(this);
7792 FPRTemporary doubleRegister(this);
7793
7794 GPRReg resultGPR = result.gpr();
7795 GPRReg scratch1GPR = scratch1.gpr();
7796 GPRReg scratch2GPR = scratch2.gpr();
7797 GPRReg lengthGPR = length.gpr();
7798 FPRReg doubleFPR = doubleRegister.fpr();
7799
7800 MacroAssembler::JumpList slowPath;
7801
7802 m_jit.load8(MacroAssembler::Address(argument, JSCell::indexingTypeAndMiscOffset()), scratch1GPR);
7803 m_jit.and32(TrustedImm32(IndexingShapeMask), scratch1GPR);
7804 m_jit.sub32(TrustedImm32(Int32Shape), scratch1GPR);
7805
7806 slowPath.append(m_jit.branch32(MacroAssembler::Above, scratch1GPR, TrustedImm32(ContiguousShape - Int32Shape)));
7807
7808 m_jit.loadPtr(MacroAssembler::Address(argument, JSObject::butterflyOffset()), lengthGPR);
7809 m_jit.load32(MacroAssembler::Address(lengthGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
7810 static_assert(sizeof(JSValue) == 8 && 1 << 3 == 8, "This is strongly assumed in the code below.");
7811 m_jit.move(lengthGPR, scratch1GPR);
7812 m_jit.lshift32(TrustedImm32(3), scratch1GPR);
7813 m_jit.add32(TrustedImm32(JSFixedArray::offsetOfData()), scratch1GPR);
7814
7815 m_jit.emitAllocateVariableSizedCell<JSFixedArray>(*m_jit.vm(), resultGPR, TrustedImmPtr(m_jit.graph().registerStructure(m_jit.graph().m_vm.fixedArrayStructure.get())), scratch1GPR, scratch1GPR, scratch2GPR, slowPath);
7816 m_jit.store32(lengthGPR, MacroAssembler::Address(resultGPR, JSFixedArray::offsetOfSize()));
7817
7818 m_jit.loadPtr(MacroAssembler::Address(argument, JSObject::butterflyOffset()), scratch1GPR);
7819
7820 MacroAssembler::JumpList done;
7821
7822 m_jit.load8(MacroAssembler::Address(argument, JSCell::indexingTypeAndMiscOffset()), scratch2GPR);
7823 m_jit.and32(TrustedImm32(IndexingShapeMask), scratch2GPR);
7824 auto isDoubleArray = m_jit.branch32(MacroAssembler::Equal, scratch2GPR, TrustedImm32(DoubleShape));
7825
7826 {
7827 done.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR));
7828 auto loopStart = m_jit.label();
7829 m_jit.sub32(TrustedImm32(1), lengthGPR);
7830 m_jit.load64(MacroAssembler::BaseIndex(scratch1GPR, lengthGPR, MacroAssembler::TimesEight), scratch2GPR);
7831 auto notEmpty = m_jit.branchIfNotEmpty(scratch2GPR);
7832 m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), scratch2GPR);
7833 notEmpty.link(&m_jit);
7834 m_jit.store64(scratch2GPR, MacroAssembler::BaseIndex(resultGPR, lengthGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()));
7835 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loopStart, &m_jit);
7836 done.append(m_jit.jump());
7837 }
7838
7839 isDoubleArray.link(&m_jit);
7840 {
7841 done.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR));
7842 auto loopStart = m_jit.label();
7843 m_jit.sub32(TrustedImm32(1), lengthGPR);
7844 m_jit.loadDouble(MacroAssembler::BaseIndex(scratch1GPR, lengthGPR, MacroAssembler::TimesEight), doubleFPR);
7845 auto notEmpty = m_jit.branchIfNotNaN(doubleFPR);
7846 m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), scratch2GPR);
7847 auto doStore = m_jit.jump();
7848 notEmpty.link(&m_jit);
7849 m_jit.boxDouble(doubleFPR, scratch2GPR);
7850 doStore.link(&m_jit);
7851 m_jit.store64(scratch2GPR, MacroAssembler::BaseIndex(resultGPR, lengthGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()));
7852 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loopStart, &m_jit);
7853 done.append(m_jit.jump());
7854 }
7855
7856 m_jit.mutatorFence(*m_jit.vm());
7857
7858 slowPath.link(&m_jit);
7859 addSlowPathGenerator(slowPathCall(m_jit.jump(), this, operationSpreadFastArray, resultGPR, argument));
7860
7861 done.link(&m_jit);
7862 cellResult(resultGPR, node);
7863#else
7864 flushRegisters();
7865
7866 GPRFlushedCallResult result(this);
7867 GPRReg resultGPR = result.gpr();
7868 callOperation(operationSpreadFastArray, resultGPR, argument);
7869 m_jit.exceptionCheck();
7870 cellResult(resultGPR, node);
7871#endif // USE(JSVALUE64)
7872 } else {
7873 flushRegisters();
7874
7875 GPRFlushedCallResult result(this);
7876 GPRReg resultGPR = result.gpr();
7877 callOperation(operationSpreadGeneric, resultGPR, argument);
7878 m_jit.exceptionCheck();
7879 cellResult(resultGPR, node);
7880 }
7881}
7882
7883void SpeculativeJIT::compileNewArray(Node* node)
7884{
7885 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
7886 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(node->indexingType())) {
7887 RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
7888 DFG_ASSERT(m_jit.graph(), node, structure->indexingType() == node->indexingType(), structure->indexingType(), node->indexingType());
7889 ASSERT(
7890 hasUndecided(structure->indexingType())
7891 || hasInt32(structure->indexingType())
7892 || hasDouble(structure->indexingType())
7893 || hasContiguous(structure->indexingType()));
7894
7895 unsigned numElements = node->numChildren();
7896 unsigned vectorLengthHint = node->vectorLengthHint();
7897 ASSERT(vectorLengthHint >= numElements);
7898
7899 GPRTemporary result(this);
7900 GPRTemporary storage(this);
7901
7902 GPRReg resultGPR = result.gpr();
7903 GPRReg storageGPR = storage.gpr();
7904
7905 emitAllocateRawObject(resultGPR, structure, storageGPR, numElements, vectorLengthHint);
7906
7907 // At this point, one way or another, resultGPR and storageGPR have pointers to
7908 // the JSArray and the Butterfly, respectively.
7909
7910 ASSERT(!hasUndecided(structure->indexingType()) || !node->numChildren());
7911
7912 for (unsigned operandIdx = 0; operandIdx < node->numChildren(); ++operandIdx) {
7913 Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + operandIdx];
7914 switch (node->indexingType()) {
7915 case ALL_BLANK_INDEXING_TYPES:
7916 case ALL_UNDECIDED_INDEXING_TYPES:
7917 CRASH();
7918 break;
7919 case ALL_DOUBLE_INDEXING_TYPES: {
7920 SpeculateDoubleOperand operand(this, use);
7921 FPRReg opFPR = operand.fpr();
7922 DFG_TYPE_CHECK(
7923 JSValueRegs(), use, SpecDoubleReal,
7924 m_jit.branchIfNaN(opFPR));
7925 m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx));
7926 break;
7927 }
7928 case ALL_INT32_INDEXING_TYPES:
7929 case ALL_CONTIGUOUS_INDEXING_TYPES: {
7930 JSValueOperand operand(this, use, ManualOperandSpeculation);
7931 JSValueRegs operandRegs = operand.jsValueRegs();
7932 if (hasInt32(node->indexingType())) {
7933 DFG_TYPE_CHECK(
7934 operandRegs, use, SpecInt32Only,
7935 m_jit.branchIfNotInt32(operandRegs));
7936 }
7937 m_jit.storeValue(operandRegs, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx));
7938 break;
7939 }
7940 default:
7941 CRASH();
7942 break;
7943 }
7944 }
7945
7946 // Yuck, we should *really* have a way of also returning the storageGPR. But
7947 // that's the least of what's wrong with this code. We really shouldn't be
7948 // allocating the array after having computed - and probably spilled to the
7949 // stack - all of the things that will go into the array. The solution to that
7950 // bigger problem will also likely fix the redundancy in reloading the storage
7951 // pointer that we currently have.
7952
7953 cellResult(resultGPR, node);
7954 return;
7955 }
7956
7957 if (!node->numChildren()) {
7958 flushRegisters();
7959 GPRFlushedCallResult result(this);
7960 callOperation(operationNewEmptyArray, result.gpr(), m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())));
7961 m_jit.exceptionCheck();
7962 cellResult(result.gpr(), node);
7963 return;
7964 }
7965
7966 size_t scratchSize = sizeof(EncodedJSValue) * node->numChildren();
7967 ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
7968 EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : nullptr;
7969
7970 for (unsigned operandIdx = 0; operandIdx < node->numChildren(); ++operandIdx) {
7971 // Need to perform the speculations that this node promises to perform. If we're
7972 // emitting code here and the indexing type is not array storage then there is
7973 // probably something hilarious going on and we're already failing at all the
7974 // things, but at least we're going to be sound.
7975 Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + operandIdx];
7976 switch (node->indexingType()) {
7977 case ALL_BLANK_INDEXING_TYPES:
7978 case ALL_UNDECIDED_INDEXING_TYPES:
7979 CRASH();
7980 break;
7981 case ALL_DOUBLE_INDEXING_TYPES: {
7982 SpeculateDoubleOperand operand(this, use);
7983 FPRReg opFPR = operand.fpr();
7984 DFG_TYPE_CHECK(
7985 JSValueRegs(), use, SpecDoubleReal,
7986 m_jit.branchIfNaN(opFPR));
7987#if USE(JSVALUE64)
7988 JSValueRegsTemporary scratch(this);
7989 JSValueRegs scratchRegs = scratch.regs();
7990 m_jit.boxDouble(opFPR, scratchRegs);
7991 m_jit.storeValue(scratchRegs, buffer + operandIdx);
7992#else
7993 m_jit.storeDouble(opFPR, TrustedImmPtr(buffer + operandIdx));
7994#endif
7995 operand.use();
7996 break;
7997 }
7998 case ALL_INT32_INDEXING_TYPES:
7999 case ALL_CONTIGUOUS_INDEXING_TYPES:
8000 case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
8001 JSValueOperand operand(this, use, ManualOperandSpeculation);
8002 JSValueRegs operandRegs = operand.jsValueRegs();
8003 if (hasInt32(node->indexingType())) {
8004 DFG_TYPE_CHECK(
8005 operandRegs, use, SpecInt32Only,
8006 m_jit.branchIfNotInt32(operandRegs));
8007 }
8008 m_jit.storeValue(operandRegs, buffer + operandIdx);
8009 operand.use();
8010 break;
8011 }
8012 default:
8013 CRASH();
8014 break;
8015 }
8016 }
8017
8018 flushRegisters();
8019
8020 if (scratchSize) {
8021 GPRTemporary scratch(this);
8022
8023 // Tell GC mark phase how much of the scratch buffer is active during call.
8024 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratch.gpr());
8025 m_jit.storePtr(TrustedImmPtr(scratchSize), scratch.gpr());
8026 }
8027
8028 GPRFlushedCallResult result(this);
8029
8030 callOperation(
8031 operationNewArray, result.gpr(), m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())),
8032 static_cast<void*>(buffer), size_t(node->numChildren()));
8033 m_jit.exceptionCheck();
8034
8035 if (scratchSize) {
8036 GPRTemporary scratch(this);
8037
8038 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratch.gpr());
8039 m_jit.storePtr(TrustedImmPtr(nullptr), scratch.gpr());
8040 }
8041
8042 cellResult(result.gpr(), node, UseChildrenCalledExplicitly);
8043}
8044
8045void SpeculativeJIT::compileNewArrayWithSpread(Node* node)
8046{
8047 ASSERT(node->op() == NewArrayWithSpread);
8048
8049#if USE(JSVALUE64)
8050 if (m_jit.graph().isWatchingHavingABadTimeWatchpoint(node)) {
8051 GPRTemporary result(this);
8052 GPRReg resultGPR = result.gpr();
8053
8054 BitVector* bitVector = node->bitVector();
8055 {
8056 unsigned startLength = 0;
8057 for (unsigned i = 0; i < node->numChildren(); ++i) {
8058 if (!bitVector->get(i))
8059 ++startLength;
8060 }
8061
8062 GPRTemporary length(this);
8063 GPRReg lengthGPR = length.gpr();
8064 m_jit.move(TrustedImm32(startLength), lengthGPR);
8065
8066 for (unsigned i = 0; i < node->numChildren(); ++i) {
8067 if (bitVector->get(i)) {
8068 Edge use = m_jit.graph().varArgChild(node, i);
8069 SpeculateCellOperand fixedArray(this, use);
8070 GPRReg fixedArrayGPR = fixedArray.gpr();
8071 speculationCheck(Overflow, JSValueRegs(), nullptr, m_jit.branchAdd32(MacroAssembler::Overflow, MacroAssembler::Address(fixedArrayGPR, JSFixedArray::offsetOfSize()), lengthGPR));
8072 }
8073 }
8074
8075 speculationCheck(Overflow, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::AboveOrEqual, lengthGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)));
8076
8077 // We can tell compileAllocateNewArrayWithSize() that it does not need to
8078 // check for large arrays and use ArrayStorage structure because we already
8079 // ensured above that the spread array length will definitely fit in a
8080 // non-ArrayStorage shaped array.
8081 bool shouldAllowForArrayStorageStructureForLargeArrays = false;
8082 ASSERT(m_jit.graph().globalObjectFor(node->origin.semantic)->restParameterStructure()->indexingType() == ArrayWithContiguous || m_jit.graph().globalObjectFor(node->origin.semantic)->isHavingABadTime());
8083 compileAllocateNewArrayWithSize(m_jit.graph().globalObjectFor(node->origin.semantic), resultGPR, lengthGPR, ArrayWithContiguous, shouldAllowForArrayStorageStructureForLargeArrays);
8084 }
8085
8086 GPRTemporary index(this);
8087 GPRReg indexGPR = index.gpr();
8088
8089 GPRTemporary storage(this);
8090 GPRReg storageGPR = storage.gpr();
8091
8092 m_jit.move(TrustedImm32(0), indexGPR);
8093 m_jit.loadPtr(MacroAssembler::Address(resultGPR, JSObject::butterflyOffset()), storageGPR);
8094
8095 for (unsigned i = 0; i < node->numChildren(); ++i) {
8096 Edge use = m_jit.graph().varArgChild(node, i);
8097 if (bitVector->get(i)) {
8098 SpeculateCellOperand fixedArray(this, use);
8099 GPRReg fixedArrayGPR = fixedArray.gpr();
8100
8101 GPRTemporary fixedIndex(this);
8102 GPRReg fixedIndexGPR = fixedIndex.gpr();
8103
8104 GPRTemporary item(this);
8105 GPRReg itemGPR = item.gpr();
8106
8107 GPRTemporary fixedLength(this);
8108 GPRReg fixedLengthGPR = fixedLength.gpr();
8109
8110 m_jit.load32(MacroAssembler::Address(fixedArrayGPR, JSFixedArray::offsetOfSize()), fixedLengthGPR);
8111 m_jit.move(TrustedImm32(0), fixedIndexGPR);
8112 auto done = m_jit.branchPtr(MacroAssembler::AboveOrEqual, fixedIndexGPR, fixedLengthGPR);
8113 auto loopStart = m_jit.label();
8114 m_jit.load64(
8115 MacroAssembler::BaseIndex(fixedArrayGPR, fixedIndexGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()),
8116 itemGPR);
8117
8118 m_jit.store64(itemGPR, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight));
8119 m_jit.addPtr(TrustedImm32(1), fixedIndexGPR);
8120 m_jit.addPtr(TrustedImm32(1), indexGPR);
8121 m_jit.branchPtr(MacroAssembler::Below, fixedIndexGPR, fixedLengthGPR).linkTo(loopStart, &m_jit);
8122
8123 done.link(&m_jit);
8124 } else {
8125 JSValueOperand item(this, use);
8126 GPRReg itemGPR = item.gpr();
8127 m_jit.store64(itemGPR, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight));
8128 m_jit.addPtr(TrustedImm32(1), indexGPR);
8129 }
8130 }
8131
8132 cellResult(resultGPR, node);
8133 return;
8134 }
8135#endif // USE(JSVALUE64)
8136
8137 ASSERT(node->numChildren());
8138 size_t scratchSize = sizeof(EncodedJSValue) * node->numChildren();
8139 ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
8140 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
8141
8142 BitVector* bitVector = node->bitVector();
8143 for (unsigned i = 0; i < node->numChildren(); ++i) {
8144 Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + i];
8145 if (bitVector->get(i)) {
8146 SpeculateCellOperand fixedArray(this, use);
8147 GPRReg arrayGPR = fixedArray.gpr();
8148#if USE(JSVALUE64)
8149 m_jit.store64(arrayGPR, &buffer[i]);
8150#else
8151 char* pointer = static_cast<char*>(static_cast<void*>(&buffer[i]));
8152 m_jit.store32(arrayGPR, pointer + PayloadOffset);
8153 m_jit.store32(TrustedImm32(JSValue::CellTag), pointer + TagOffset);
8154#endif
8155 } else {
8156 JSValueOperand input(this, use);
8157 JSValueRegs inputRegs = input.jsValueRegs();
8158 m_jit.storeValue(inputRegs, &buffer[i]);
8159 }
8160 }
8161
8162 {
8163 GPRTemporary scratch(this);
8164 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratch.gpr());
8165 m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(scratch.gpr()));
8166 }
8167
8168 flushRegisters();
8169
8170 GPRFlushedCallResult result(this);
8171 GPRReg resultGPR = result.gpr();
8172
8173 callOperation(operationNewArrayWithSpreadSlow, resultGPR, buffer, node->numChildren());
8174 m_jit.exceptionCheck();
8175 {
8176 GPRTemporary scratch(this);
8177 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratch.gpr());
8178 m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(scratch.gpr()));
8179 }
8180
8181 cellResult(resultGPR, node);
8182}
8183
8184void SpeculativeJIT::compileGetRestLength(Node* node)
8185{
8186 ASSERT(node->op() == GetRestLength);
8187
8188 GPRTemporary result(this);
8189 GPRReg resultGPR = result.gpr();
8190
8191 emitGetLength(node->origin.semantic, resultGPR);
8192 CCallHelpers::Jump hasNonZeroLength = m_jit.branch32(MacroAssembler::Above, resultGPR, Imm32(node->numberOfArgumentsToSkip()));
8193 m_jit.move(TrustedImm32(0), resultGPR);
8194 CCallHelpers::Jump done = m_jit.jump();
8195 hasNonZeroLength.link(&m_jit);
8196 if (node->numberOfArgumentsToSkip())
8197 m_jit.sub32(TrustedImm32(node->numberOfArgumentsToSkip()), resultGPR);
8198 done.link(&m_jit);
8199 int32Result(resultGPR, node);
8200}
8201
8202void SpeculativeJIT::emitPopulateSliceIndex(Edge& target, Optional<GPRReg> indexGPR, GPRReg lengthGPR, GPRReg resultGPR)
8203{
8204 if (target->isInt32Constant()) {
8205 int32_t value = target->asInt32();
8206 if (value == 0) {
8207 m_jit.move(TrustedImm32(0), resultGPR);
8208 return;
8209 }
8210
8211 MacroAssembler::JumpList done;
8212 if (value > 0) {
8213 m_jit.move(TrustedImm32(value), resultGPR);
8214 done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, resultGPR, lengthGPR));
8215 m_jit.move(lengthGPR, resultGPR);
8216 } else {
8217 ASSERT(value != 0);
8218 m_jit.move(lengthGPR, resultGPR);
8219 done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, TrustedImm32(value), resultGPR));
8220 m_jit.move(TrustedImm32(0), resultGPR);
8221 }
8222 done.link(&m_jit);
8223 return;
8224 }
8225
8226 Optional<SpeculateInt32Operand> index;
8227 if (!indexGPR) {
8228 index.emplace(this, target);
8229 indexGPR = index->gpr();
8230 }
8231 MacroAssembler::JumpList done;
8232
8233 auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR.value(), TrustedImm32(0));
8234 m_jit.move(lengthGPR, resultGPR);
8235 done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR.value(), resultGPR));
8236 m_jit.move(TrustedImm32(0), resultGPR);
8237 done.append(m_jit.jump());
8238
8239 isPositive.link(&m_jit);
8240 m_jit.move(indexGPR.value(), resultGPR);
8241 done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, resultGPR, lengthGPR));
8242 m_jit.move(lengthGPR, resultGPR);
8243
8244 done.link(&m_jit);
8245}
8246
8247void SpeculativeJIT::compileArraySlice(Node* node)
8248{
8249 ASSERT(node->op() == ArraySlice);
8250
8251 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
8252
8253 GPRTemporary temp(this);
8254 StorageOperand storage(this, m_jit.graph().varArgChild(node, node->numChildren() - 1));
8255 GPRTemporary result(this);
8256
8257 GPRReg storageGPR = storage.gpr();
8258 GPRReg resultGPR = result.gpr();
8259 GPRReg tempGPR = temp.gpr();
8260
8261 if (node->numChildren() == 2)
8262 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempGPR);
8263 else {
8264 ASSERT(node->numChildren() == 3 || node->numChildren() == 4);
8265 GPRTemporary tempLength(this);
8266 GPRReg lengthGPR = tempLength.gpr();
8267 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
8268
8269 if (node->numChildren() == 4)
8270 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, lengthGPR, tempGPR);
8271 else
8272 m_jit.move(lengthGPR, tempGPR);
8273
8274 if (m_jit.graph().varArgChild(node, 1)->isInt32Constant() && m_jit.graph().varArgChild(node, 1)->asInt32() == 0) {
8275 // Do nothing for array.slice(0, end) or array.slice(0) cases.
8276 // `tempGPR` already points to the size of a newly created array.
8277 } else {
8278 GPRTemporary tempStartIndex(this);
8279 GPRReg startGPR = tempStartIndex.gpr();
8280 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), WTF::nullopt, lengthGPR, startGPR);
8281
8282 auto tooBig = m_jit.branch32(MacroAssembler::Above, startGPR, tempGPR);
8283 m_jit.sub32(startGPR, tempGPR); // the size of the array we'll make.
8284 auto done = m_jit.jump();
8285
8286 tooBig.link(&m_jit);
8287 m_jit.move(TrustedImm32(0), tempGPR);
8288 done.link(&m_jit);
8289 }
8290 }
8291
8292
8293 GPRTemporary temp3(this);
8294 GPRReg tempValue = temp3.gpr();
8295 {
8296 SpeculateCellOperand cell(this, m_jit.graph().varArgChild(node, 0));
8297 m_jit.load8(MacroAssembler::Address(cell.gpr(), JSCell::indexingTypeAndMiscOffset()), tempValue);
8298 // We can ignore the writability of the cell since we won't write to the source.
8299 m_jit.and32(TrustedImm32(AllWritableArrayTypesAndHistory), tempValue);
8300 }
8301
8302 {
8303 JSValueRegsTemporary emptyValue(this);
8304 JSValueRegs emptyValueRegs = emptyValue.regs();
8305
8306 GPRTemporary storage(this);
8307 GPRReg storageResultGPR = storage.gpr();
8308
8309 GPRReg sizeGPR = tempGPR;
8310
8311 CCallHelpers::JumpList done;
8312
8313 auto emitMoveEmptyValue = [&] (JSValue v) {
8314 m_jit.moveValue(v, emptyValueRegs);
8315 };
8316
8317 auto isContiguous = m_jit.branch32(MacroAssembler::Equal, tempValue, TrustedImm32(ArrayWithContiguous));
8318 auto isInt32 = m_jit.branch32(MacroAssembler::Equal, tempValue, TrustedImm32(ArrayWithInt32));
8319 // When we emit an ArraySlice, we dominate the use of the array by a CheckStructure
8320 // to ensure the incoming array is one to be one of the original array structures
8321 // with one of the following indexing shapes: Int32, Contiguous, Double. Therefore,
8322 // we're a double array here.
8323 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithDouble))), tempValue);
8324 emitMoveEmptyValue(jsNaN());
8325 done.append(m_jit.jump());
8326
8327 isContiguous.link(&m_jit);
8328 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous))), tempValue);
8329 emitMoveEmptyValue(JSValue());
8330 done.append(m_jit.jump());
8331
8332 isInt32.link(&m_jit);
8333 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithInt32))), tempValue);
8334 emitMoveEmptyValue(JSValue());
8335
8336 done.link(&m_jit);
8337
8338 MacroAssembler::JumpList slowCases;
8339 m_jit.move(TrustedImmPtr(nullptr), storageResultGPR);
8340 // Enable the fast case on 64-bit platforms, where a sufficient amount of GP registers should be available.
8341 // Other platforms could support the same approach with custom code, but that is not currently worth the extra code maintenance.
8342 if (is64Bit()) {
8343 GPRTemporary scratch(this);
8344 GPRTemporary scratch2(this);
8345 GPRReg scratchGPR = scratch.gpr();
8346 GPRReg scratch2GPR = scratch2.gpr();
8347
8348 emitAllocateButterfly(storageResultGPR, sizeGPR, scratchGPR, scratch2GPR, resultGPR, slowCases);
8349 emitInitializeButterfly(storageResultGPR, sizeGPR, emptyValueRegs, scratchGPR);
8350 emitAllocateJSObject<JSArray>(resultGPR, tempValue, storageResultGPR, scratchGPR, scratch2GPR, slowCases);
8351 m_jit.mutatorFence(*m_jit.vm());
8352 } else {
8353 slowCases.append(m_jit.jump());
8354 }
8355
8356 addSlowPathGenerator(std::make_unique<CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator>(
8357 slowCases, this, operationNewArrayWithSize, resultGPR, tempValue, sizeGPR, storageResultGPR));
8358 }
8359
8360 GPRTemporary temp4(this);
8361 GPRReg loadIndex = temp4.gpr();
8362
8363 if (node->numChildren() == 2) {
8364 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempGPR);
8365 m_jit.move(TrustedImm32(0), loadIndex);
8366 } else {
8367 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempValue);
8368 if (node->numChildren() == 4)
8369 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, tempValue, tempGPR);
8370 else
8371 m_jit.move(tempValue, tempGPR);
8372 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), WTF::nullopt, tempValue, loadIndex);
8373 }
8374
8375 GPRTemporary temp5(this);
8376 GPRReg storeIndex = temp5.gpr();
8377 m_jit.move(TrustedImmPtr(nullptr), storeIndex);
8378
8379 GPRTemporary temp2(this);
8380 GPRReg resultButterfly = temp2.gpr();
8381
8382 m_jit.loadPtr(MacroAssembler::Address(resultGPR, JSObject::butterflyOffset()), resultButterfly);
8383 m_jit.zeroExtend32ToPtr(tempGPR, tempGPR);
8384 m_jit.zeroExtend32ToPtr(loadIndex, loadIndex);
8385 auto done = m_jit.branchPtr(MacroAssembler::AboveOrEqual, loadIndex, tempGPR);
8386
8387 auto loop = m_jit.label();
8388#if USE(JSVALUE64)
8389 m_jit.load64(
8390 MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight), tempValue);
8391 m_jit.store64(
8392 tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight));
8393#else
8394 m_jit.load32(
8395 MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight, PayloadOffset), tempValue);
8396 m_jit.store32(
8397 tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight, PayloadOffset));
8398 m_jit.load32(
8399 MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight, TagOffset), tempValue);
8400 m_jit.store32(
8401 tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight, TagOffset));
8402#endif // USE(JSVALUE64)
8403 m_jit.addPtr(TrustedImm32(1), loadIndex);
8404 m_jit.addPtr(TrustedImm32(1), storeIndex);
8405 m_jit.branchPtr(MacroAssembler::Below, loadIndex, tempGPR).linkTo(loop, &m_jit);
8406
8407 done.link(&m_jit);
8408 cellResult(resultGPR, node);
8409}
8410
8411void SpeculativeJIT::compileArrayIndexOf(Node* node)
8412{
8413 ASSERT(node->op() == ArrayIndexOf);
8414
8415 StorageOperand storage(this, m_jit.graph().varArgChild(node, node->numChildren() == 3 ? 2 : 3));
8416 GPRTemporary index(this);
8417 GPRTemporary tempLength(this);
8418
8419 GPRReg storageGPR = storage.gpr();
8420 GPRReg indexGPR = index.gpr();
8421 GPRReg lengthGPR = tempLength.gpr();
8422
8423 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
8424
8425 if (node->numChildren() == 4)
8426 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, lengthGPR, indexGPR);
8427 else
8428 m_jit.move(TrustedImm32(0), indexGPR);
8429
8430 Edge& searchElementEdge = m_jit.graph().varArgChild(node, 1);
8431 switch (searchElementEdge.useKind()) {
8432 case Int32Use:
8433 case ObjectUse:
8434 case SymbolUse:
8435 case OtherUse: {
8436 auto emitLoop = [&] (auto emitCompare) {
8437#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
8438 m_jit.clearRegisterAllocationOffsets();
8439#endif
8440
8441 m_jit.zeroExtend32ToPtr(lengthGPR, lengthGPR);
8442 m_jit.zeroExtend32ToPtr(indexGPR, indexGPR);
8443
8444 auto loop = m_jit.label();
8445 auto notFound = m_jit.branch32(CCallHelpers::Equal, indexGPR, lengthGPR);
8446
8447 auto found = emitCompare();
8448
8449 m_jit.add32(TrustedImm32(1), indexGPR);
8450 m_jit.jump().linkTo(loop, &m_jit);
8451
8452 notFound.link(&m_jit);
8453 m_jit.move(TrustedImm32(-1), indexGPR);
8454 found.link(&m_jit);
8455 int32Result(indexGPR, node);
8456 };
8457
8458 if (searchElementEdge.useKind() == Int32Use) {
8459 ASSERT(node->arrayMode().type() == Array::Int32);
8460#if USE(JSVALUE64)
8461 JSValueOperand searchElement(this, searchElementEdge, ManualOperandSpeculation);
8462 JSValueRegs searchElementRegs = searchElement.jsValueRegs();
8463 speculateInt32(searchElementEdge, searchElementRegs);
8464 GPRReg searchElementGPR = searchElementRegs.payloadGPR();
8465#else
8466 SpeculateInt32Operand searchElement(this, searchElementEdge);
8467 GPRReg searchElementGPR = searchElement.gpr();
8468
8469 GPRTemporary temp(this);
8470 GPRReg tempGPR = temp.gpr();
8471#endif
8472 emitLoop([&] () {
8473#if USE(JSVALUE64)
8474 auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementGPR);
8475#else
8476 auto skip = m_jit.branch32(CCallHelpers::NotEqual, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), TrustedImm32(JSValue::Int32Tag));
8477 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, PayloadOffset), tempGPR);
8478 auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementGPR);
8479 skip.link(&m_jit);
8480#endif
8481 return found;
8482 });
8483 return;
8484 }
8485
8486 if (searchElementEdge.useKind() == OtherUse) {
8487 ASSERT(node->arrayMode().type() == Array::Contiguous);
8488 JSValueOperand searchElement(this, searchElementEdge, ManualOperandSpeculation);
8489 GPRTemporary temp(this);
8490
8491 JSValueRegs searchElementRegs = searchElement.jsValueRegs();
8492 GPRReg tempGPR = temp.gpr();
8493 speculateOther(searchElementEdge, searchElementRegs, tempGPR);
8494
8495 emitLoop([&] () {
8496#if USE(JSVALUE64)
8497 auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementRegs.payloadGPR());
8498#else
8499 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), tempGPR);
8500 auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementRegs.tagGPR());
8501#endif
8502 return found;
8503 });
8504 return;
8505 }
8506
8507 ASSERT(node->arrayMode().type() == Array::Contiguous);
8508 SpeculateCellOperand searchElement(this, searchElementEdge);
8509 GPRReg searchElementGPR = searchElement.gpr();
8510
8511 if (searchElementEdge.useKind() == ObjectUse)
8512 speculateObject(searchElementEdge, searchElementGPR);
8513 else {
8514 ASSERT(searchElementEdge.useKind() == SymbolUse);
8515 speculateSymbol(searchElementEdge, searchElementGPR);
8516 }
8517
8518#if USE(JSVALUE32_64)
8519 GPRTemporary temp(this);
8520 GPRReg tempGPR = temp.gpr();
8521#endif
8522
8523 emitLoop([&] () {
8524#if USE(JSVALUE64)
8525 auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementGPR);
8526#else
8527 auto skip = m_jit.branch32(CCallHelpers::NotEqual, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), TrustedImm32(JSValue::CellTag));
8528 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, PayloadOffset), tempGPR);
8529 auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementGPR);
8530 skip.link(&m_jit);
8531#endif
8532 return found;
8533 });
8534 return;
8535 }
8536
8537 case DoubleRepUse: {
8538 ASSERT(node->arrayMode().type() == Array::Double);
8539 SpeculateDoubleOperand searchElement(this, searchElementEdge);
8540 FPRTemporary tempDouble(this);
8541
8542 FPRReg searchElementFPR = searchElement.fpr();
8543 FPRReg tempFPR = tempDouble.fpr();
8544
8545#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
8546 m_jit.clearRegisterAllocationOffsets();
8547#endif
8548
8549 m_jit.zeroExtend32ToPtr(lengthGPR, lengthGPR);
8550 m_jit.zeroExtend32ToPtr(indexGPR, indexGPR);
8551
8552 auto loop = m_jit.label();
8553 auto notFound = m_jit.branch32(CCallHelpers::Equal, indexGPR, lengthGPR);
8554 m_jit.loadDouble(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), tempFPR);
8555 auto found = m_jit.branchDouble(CCallHelpers::DoubleEqual, tempFPR, searchElementFPR);
8556 m_jit.add32(TrustedImm32(1), indexGPR);
8557 m_jit.jump().linkTo(loop, &m_jit);
8558
8559 notFound.link(&m_jit);
8560 m_jit.move(TrustedImm32(-1), indexGPR);
8561 found.link(&m_jit);
8562 int32Result(indexGPR, node);
8563 return;
8564 }
8565
8566 case StringUse: {
8567 ASSERT(node->arrayMode().type() == Array::Contiguous);
8568 SpeculateCellOperand searchElement(this, searchElementEdge);
8569
8570 GPRReg searchElementGPR = searchElement.gpr();
8571
8572 speculateString(searchElementEdge, searchElementGPR);
8573
8574 flushRegisters();
8575
8576 callOperation(operationArrayIndexOfString, lengthGPR, storageGPR, searchElementGPR, indexGPR);
8577 m_jit.exceptionCheck();
8578
8579 int32Result(lengthGPR, node);
8580 return;
8581 }
8582
8583 case UntypedUse: {
8584 JSValueOperand searchElement(this, searchElementEdge);
8585
8586 JSValueRegs searchElementRegs = searchElement.jsValueRegs();
8587
8588 flushRegisters();
8589 switch (node->arrayMode().type()) {
8590 case Array::Double:
8591 callOperation(operationArrayIndexOfValueDouble, lengthGPR, storageGPR, searchElementRegs, indexGPR);
8592 break;
8593 case Array::Int32:
8594 case Array::Contiguous:
8595 callOperation(operationArrayIndexOfValueInt32OrContiguous, lengthGPR, storageGPR, searchElementRegs, indexGPR);
8596 break;
8597 default:
8598 RELEASE_ASSERT_NOT_REACHED();
8599 break;
8600 }
8601 m_jit.exceptionCheck();
8602
8603 int32Result(lengthGPR, node);
8604 return;
8605 }
8606
8607 default:
8608 RELEASE_ASSERT_NOT_REACHED();
8609 return;
8610 }
8611}
8612
8613void SpeculativeJIT::compileArrayPush(Node* node)
8614{
8615 ASSERT(node->arrayMode().isJSArray());
8616
8617 Edge& storageEdge = m_jit.graph().varArgChild(node, 0);
8618 Edge& arrayEdge = m_jit.graph().varArgChild(node, 1);
8619
8620 SpeculateCellOperand base(this, arrayEdge);
8621 GPRTemporary storageLength(this);
8622
8623 GPRReg baseGPR = base.gpr();
8624 GPRReg storageLengthGPR = storageLength.gpr();
8625
8626 StorageOperand storage(this, storageEdge);
8627 GPRReg storageGPR = storage.gpr();
8628 unsigned elementOffset = 2;
8629 unsigned elementCount = node->numChildren() - elementOffset;
8630
8631#if USE(JSVALUE32_64)
8632 GPRTemporary tag(this);
8633 GPRReg tagGPR = tag.gpr();
8634 JSValueRegs resultRegs { tagGPR, storageLengthGPR };
8635#else
8636 JSValueRegs resultRegs { storageLengthGPR };
8637#endif
8638
8639 auto getStorageBufferAddress = [&] (GPRReg storageGPR, GPRReg indexGPR, int32_t offset, GPRReg bufferGPR) {
8640 static_assert(sizeof(JSValue) == 8 && 1 << 3 == 8, "This is strongly assumed in the code below.");
8641 m_jit.getEffectiveAddress(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, offset), bufferGPR);
8642 };
8643
8644 switch (node->arrayMode().type()) {
8645 case Array::Int32:
8646 case Array::Contiguous: {
8647 if (elementCount == 1) {
8648 Edge& element = m_jit.graph().varArgChild(node, elementOffset);
8649 if (node->arrayMode().type() == Array::Int32) {
8650 ASSERT(element.useKind() == Int32Use);
8651 speculateInt32(element);
8652 }
8653 JSValueOperand value(this, element, ManualOperandSpeculation);
8654 JSValueRegs valueRegs = value.jsValueRegs();
8655
8656 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
8657 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
8658 m_jit.storeValue(valueRegs, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
8659 m_jit.add32(TrustedImm32(1), storageLengthGPR);
8660 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
8661 m_jit.boxInt32(storageLengthGPR, resultRegs);
8662
8663 addSlowPathGenerator(
8664 slowPathCall(slowPath, this, operationArrayPush, resultRegs, valueRegs, baseGPR));
8665
8666 jsValueResult(resultRegs, node);
8667 return;
8668 }
8669
8670 if (node->arrayMode().type() == Array::Int32) {
8671 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8672 Edge element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8673 ASSERT(element.useKind() == Int32Use);
8674 speculateInt32(element);
8675 }
8676 }
8677
8678 GPRTemporary buffer(this);
8679 GPRReg bufferGPR = buffer.gpr();
8680
8681 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
8682 m_jit.move(storageLengthGPR, bufferGPR);
8683 m_jit.add32(TrustedImm32(elementCount), bufferGPR);
8684 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::Above, bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
8685
8686 m_jit.store32(bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
8687 getStorageBufferAddress(storageGPR, storageLengthGPR, 0, bufferGPR);
8688 m_jit.add32(TrustedImm32(elementCount), storageLengthGPR);
8689 m_jit.boxInt32(storageLengthGPR, resultRegs);
8690 auto storageDone = m_jit.jump();
8691
8692 slowPath.link(&m_jit);
8693
8694 size_t scratchSize = sizeof(EncodedJSValue) * elementCount;
8695 ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
8696 m_jit.move(TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())), bufferGPR);
8697 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), storageLengthGPR);
8698 m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(storageLengthGPR));
8699
8700 storageDone.link(&m_jit);
8701 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8702 Edge& element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8703 JSValueOperand value(this, element, ManualOperandSpeculation); // We did type checks above.
8704 JSValueRegs valueRegs = value.jsValueRegs();
8705
8706 m_jit.storeValue(valueRegs, MacroAssembler::Address(bufferGPR, sizeof(EncodedJSValue) * elementIndex));
8707 value.use();
8708 }
8709
8710 MacroAssembler::Jump fastPath = m_jit.branchPtr(MacroAssembler::NotEqual, bufferGPR, TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
8711
8712 addSlowPathGenerator(slowPathCall(m_jit.jump(), this, operationArrayPushMultiple, resultRegs, baseGPR, bufferGPR, TrustedImm32(elementCount)));
8713
8714 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), bufferGPR);
8715 m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(bufferGPR));
8716
8717 base.use();
8718 storage.use();
8719
8720 fastPath.link(&m_jit);
8721 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
8722 return;
8723 }
8724
8725 case Array::Double: {
8726 if (elementCount == 1) {
8727 Edge& element = m_jit.graph().varArgChild(node, elementOffset);
8728 speculate(node, element);
8729 SpeculateDoubleOperand value(this, element);
8730 FPRReg valueFPR = value.fpr();
8731
8732 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
8733 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
8734 m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
8735 m_jit.add32(TrustedImm32(1), storageLengthGPR);
8736 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
8737 m_jit.boxInt32(storageLengthGPR, resultRegs);
8738
8739 addSlowPathGenerator(
8740 slowPathCall(slowPath, this, operationArrayPushDouble, resultRegs, valueFPR, baseGPR));
8741
8742 jsValueResult(resultRegs, node);
8743 return;
8744 }
8745
8746 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8747 Edge element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8748 ASSERT(element.useKind() == DoubleRepRealUse);
8749 speculate(node, element);
8750 }
8751
8752 GPRTemporary buffer(this);
8753 GPRReg bufferGPR = buffer.gpr();
8754
8755 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
8756 m_jit.move(storageLengthGPR, bufferGPR);
8757 m_jit.add32(TrustedImm32(elementCount), bufferGPR);
8758 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::Above, bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
8759
8760 m_jit.store32(bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
8761 getStorageBufferAddress(storageGPR, storageLengthGPR, 0, bufferGPR);
8762 m_jit.add32(TrustedImm32(elementCount), storageLengthGPR);
8763 m_jit.boxInt32(storageLengthGPR, resultRegs);
8764 auto storageDone = m_jit.jump();
8765
8766 slowPath.link(&m_jit);
8767
8768 size_t scratchSize = sizeof(double) * elementCount;
8769 ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
8770 m_jit.move(TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())), bufferGPR);
8771 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), storageLengthGPR);
8772 m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(storageLengthGPR));
8773
8774 storageDone.link(&m_jit);
8775 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8776 Edge& element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8777 SpeculateDoubleOperand value(this, element);
8778 FPRReg valueFPR = value.fpr();
8779
8780 m_jit.storeDouble(valueFPR, MacroAssembler::Address(bufferGPR, sizeof(double) * elementIndex));
8781 value.use();
8782 }
8783
8784 MacroAssembler::Jump fastPath = m_jit.branchPtr(MacroAssembler::NotEqual, bufferGPR, TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
8785
8786 addSlowPathGenerator(slowPathCall(m_jit.jump(), this, operationArrayPushDoubleMultiple, resultRegs, baseGPR, bufferGPR, TrustedImm32(elementCount)));
8787
8788 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), bufferGPR);
8789 m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(bufferGPR));
8790
8791 base.use();
8792 storage.use();
8793
8794 fastPath.link(&m_jit);
8795 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
8796 return;
8797 }
8798
8799 case Array::ArrayStorage: {
8800 // This ensures that the result of ArrayPush is Int32 in AI.
8801 int32_t largestPositiveInt32Length = 0x7fffffff - elementCount;
8802 if (elementCount == 1) {
8803 Edge& element = m_jit.graph().varArgChild(node, elementOffset);
8804 JSValueOperand value(this, element);
8805 JSValueRegs valueRegs = value.jsValueRegs();
8806
8807 m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
8808
8809 // Refuse to handle bizarre lengths.
8810 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(largestPositiveInt32Length)));
8811
8812 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
8813
8814 m_jit.storeValue(valueRegs, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()));
8815
8816 m_jit.add32(TrustedImm32(1), storageLengthGPR);
8817 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
8818 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
8819 m_jit.boxInt32(storageLengthGPR, resultRegs);
8820
8821 addSlowPathGenerator(
8822 slowPathCall(slowPath, this, operationArrayPush, resultRegs, valueRegs, baseGPR));
8823
8824 jsValueResult(resultRegs, node);
8825 return;
8826 }
8827
8828 GPRTemporary buffer(this);
8829 GPRReg bufferGPR = buffer.gpr();
8830
8831 m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
8832
8833 // Refuse to handle bizarre lengths.
8834 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(largestPositiveInt32Length)));
8835
8836 m_jit.move(storageLengthGPR, bufferGPR);
8837 m_jit.add32(TrustedImm32(elementCount), bufferGPR);
8838 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::Above, bufferGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
8839
8840 m_jit.store32(bufferGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
8841 getStorageBufferAddress(storageGPR, storageLengthGPR, ArrayStorage::vectorOffset(), bufferGPR);
8842 m_jit.add32(TrustedImm32(elementCount), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
8843 m_jit.add32(TrustedImm32(elementCount), storageLengthGPR);
8844 m_jit.boxInt32(storageLengthGPR, resultRegs);
8845 auto storageDone = m_jit.jump();
8846
8847 slowPath.link(&m_jit);
8848
8849 size_t scratchSize = sizeof(EncodedJSValue) * elementCount;
8850 ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
8851 m_jit.move(TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())), bufferGPR);
8852 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), storageLengthGPR);
8853 m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(storageLengthGPR));
8854
8855 storageDone.link(&m_jit);
8856 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8857 Edge& element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8858 JSValueOperand value(this, element);
8859 JSValueRegs valueRegs = value.jsValueRegs();
8860
8861 m_jit.storeValue(valueRegs, MacroAssembler::Address(bufferGPR, sizeof(EncodedJSValue) * elementIndex));
8862 value.use();
8863 }
8864
8865 MacroAssembler::Jump fastPath = m_jit.branchPtr(MacroAssembler::NotEqual, bufferGPR, TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
8866
8867 addSlowPathGenerator(
8868 slowPathCall(m_jit.jump(), this, operationArrayPushMultiple, resultRegs, baseGPR, bufferGPR, TrustedImm32(elementCount)));
8869
8870 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), bufferGPR);
8871 m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(bufferGPR));
8872
8873 base.use();
8874 storage.use();
8875
8876 fastPath.link(&m_jit);
8877 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
8878 return;
8879 }
8880
8881 default:
8882 RELEASE_ASSERT_NOT_REACHED();
8883 }
8884}
8885
8886void SpeculativeJIT::compileNotifyWrite(Node* node)
8887{
8888 WatchpointSet* set = node->watchpointSet();
8889
8890 JITCompiler::Jump slowCase = m_jit.branch8(
8891 JITCompiler::NotEqual,
8892 JITCompiler::AbsoluteAddress(set->addressOfState()),
8893 TrustedImm32(IsInvalidated));
8894
8895 addSlowPathGenerator(
8896 slowPathCall(slowCase, this, operationNotifyWrite, NeedToSpill, ExceptionCheckRequirement::CheckNotNeeded, NoResult, set));
8897
8898 noResult(node);
8899}
8900
8901void SpeculativeJIT::compileIsObject(Node* node)
8902{
8903 JSValueOperand value(this, node->child1());
8904 GPRTemporary result(this, Reuse, value, TagWord);
8905
8906 JSValueRegs valueRegs = value.jsValueRegs();
8907 GPRReg resultGPR = result.gpr();
8908
8909 JITCompiler::Jump isNotCell = m_jit.branchIfNotCell(valueRegs);
8910
8911 m_jit.compare8(JITCompiler::AboveOrEqual,
8912 JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoTypeOffset()),
8913 TrustedImm32(ObjectType),
8914 resultGPR);
8915 JITCompiler::Jump done = m_jit.jump();
8916
8917 isNotCell.link(&m_jit);
8918 m_jit.move(TrustedImm32(0), resultGPR);
8919
8920 done.link(&m_jit);
8921 unblessedBooleanResult(resultGPR, node);
8922}
8923
8924void SpeculativeJIT::compileIsObjectOrNull(Node* node)
8925{
8926 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
8927
8928 JSValueOperand value(this, node->child1());
8929 JSValueRegs valueRegs = value.jsValueRegs();
8930
8931 GPRTemporary result(this);
8932 GPRReg resultGPR = result.gpr();
8933
8934 JITCompiler::Jump isCell = m_jit.branchIfCell(valueRegs);
8935
8936 JITCompiler::Jump isNull = m_jit.branchIfEqual(valueRegs, jsNull());
8937 JITCompiler::Jump isNonNullNonCell = m_jit.jump();
8938
8939 isCell.link(&m_jit);
8940 JITCompiler::Jump isFunction = m_jit.branchIfFunction(valueRegs.payloadGPR());
8941 JITCompiler::Jump notObject = m_jit.branchIfNotObject(valueRegs.payloadGPR());
8942
8943 JITCompiler::Jump slowPath = m_jit.branchTest8(
8944 JITCompiler::NonZero,
8945 JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoFlagsOffset()),
8946 TrustedImm32(MasqueradesAsUndefined | OverridesGetCallData));
8947
8948 isNull.link(&m_jit);
8949 m_jit.move(TrustedImm32(1), resultGPR);
8950 JITCompiler::Jump done = m_jit.jump();
8951
8952 isNonNullNonCell.link(&m_jit);
8953 isFunction.link(&m_jit);
8954 notObject.link(&m_jit);
8955 m_jit.move(TrustedImm32(0), resultGPR);
8956
8957 addSlowPathGenerator(
8958 slowPathCall(
8959 slowPath, this, operationObjectIsObject, resultGPR, globalObject,
8960 valueRegs.payloadGPR()));
8961
8962 done.link(&m_jit);
8963
8964 unblessedBooleanResult(resultGPR, node);
8965}
8966
8967void SpeculativeJIT::compileIsFunction(Node* node)
8968{
8969 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
8970
8971 JSValueOperand value(this, node->child1());
8972 JSValueRegs valueRegs = value.jsValueRegs();
8973
8974 GPRTemporary result(this);
8975 GPRReg resultGPR = result.gpr();
8976
8977 JITCompiler::Jump notCell = m_jit.branchIfNotCell(valueRegs);
8978 JITCompiler::Jump isFunction = m_jit.branchIfFunction(valueRegs.payloadGPR());
8979 JITCompiler::Jump notObject = m_jit.branchIfNotObject(valueRegs.payloadGPR());
8980
8981 JITCompiler::Jump slowPath = m_jit.branchTest8(
8982 JITCompiler::NonZero,
8983 JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoFlagsOffset()),
8984 TrustedImm32(MasqueradesAsUndefined | OverridesGetCallData));
8985
8986 notCell.link(&m_jit);
8987 notObject.link(&m_jit);
8988 m_jit.move(TrustedImm32(0), resultGPR);
8989 JITCompiler::Jump done = m_jit.jump();
8990
8991 isFunction.link(&m_jit);
8992 m_jit.move(TrustedImm32(1), resultGPR);
8993
8994 addSlowPathGenerator(
8995 slowPathCall(
8996 slowPath, this, operationObjectIsFunction, resultGPR, globalObject,
8997 valueRegs.payloadGPR()));
8998
8999 done.link(&m_jit);
9000
9001 unblessedBooleanResult(resultGPR, node);
9002}
9003
9004void SpeculativeJIT::compileTypeOf(Node* node)
9005{
9006 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
9007
9008 JSValueOperand value(this, node->child1());
9009 JSValueRegs valueRegs = value.jsValueRegs();
9010
9011 GPRTemporary result(this);
9012 GPRReg resultGPR = result.gpr();
9013
9014 JITCompiler::JumpList done;
9015 JITCompiler::Jump slowPath;
9016 m_jit.emitTypeOf(
9017 valueRegs, resultGPR,
9018 [&] (TypeofType type, bool fallsThrough) {
9019 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->smallStrings.typeString(type)), resultGPR);
9020 if (!fallsThrough)
9021 done.append(m_jit.jump());
9022 },
9023 [&] (JITCompiler::Jump theSlowPath) {
9024 slowPath = theSlowPath;
9025 });
9026 done.link(&m_jit);
9027
9028 addSlowPathGenerator(
9029 slowPathCall(
9030 slowPath, this, operationTypeOfObject, resultGPR, globalObject,
9031 valueRegs.payloadGPR()));
9032
9033 cellResult(resultGPR, node);
9034}
9035
9036void SpeculativeJIT::emitStructureCheck(Node* node, GPRReg cellGPR, GPRReg tempGPR)
9037{
9038 ASSERT(node->structureSet().size());
9039
9040 if (node->structureSet().size() == 1) {
9041 speculationCheck(
9042 BadCache, JSValueSource::unboxedCell(cellGPR), 0,
9043 m_jit.branchWeakStructure(
9044 JITCompiler::NotEqual,
9045 JITCompiler::Address(cellGPR, JSCell::structureIDOffset()),
9046 node->structureSet()[0]));
9047 } else {
9048 std::unique_ptr<GPRTemporary> structure;
9049 GPRReg structureGPR;
9050
9051 if (tempGPR == InvalidGPRReg) {
9052 structure = std::make_unique<GPRTemporary>(this);
9053 structureGPR = structure->gpr();
9054 } else
9055 structureGPR = tempGPR;
9056
9057 m_jit.load32(JITCompiler::Address(cellGPR, JSCell::structureIDOffset()), structureGPR);
9058
9059 JITCompiler::JumpList done;
9060
9061 for (size_t i = 0; i < node->structureSet().size() - 1; ++i) {
9062 done.append(
9063 m_jit.branchWeakStructure(JITCompiler::Equal, structureGPR, node->structureSet()[i]));
9064 }
9065
9066 speculationCheck(
9067 BadCache, JSValueSource::unboxedCell(cellGPR), 0,
9068 m_jit.branchWeakStructure(
9069 JITCompiler::NotEqual, structureGPR, node->structureSet().last()));
9070
9071 done.link(&m_jit);
9072 }
9073}
9074
9075void SpeculativeJIT::compileCheckCell(Node* node)
9076{
9077 SpeculateCellOperand cell(this, node->child1());
9078 speculationCheck(BadCell, JSValueSource::unboxedCell(cell.gpr()), node->child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, cell.gpr(), node->cellOperand()->cell()));
9079 noResult(node);
9080}
9081
9082void SpeculativeJIT::compileCheckNotEmpty(Node* node)
9083{
9084 JSValueOperand operand(this, node->child1());
9085 JSValueRegs regs = operand.jsValueRegs();
9086 speculationCheck(TDZFailure, JSValueSource(), nullptr, m_jit.branchIfEmpty(regs));
9087 noResult(node);
9088}
9089
9090void SpeculativeJIT::compileCheckStructure(Node* node)
9091{
9092 switch (node->child1().useKind()) {
9093 case CellUse:
9094 case KnownCellUse: {
9095 SpeculateCellOperand cell(this, node->child1());
9096 emitStructureCheck(node, cell.gpr(), InvalidGPRReg);
9097 noResult(node);
9098 return;
9099 }
9100
9101 case CellOrOtherUse: {
9102 JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
9103 GPRTemporary temp(this);
9104
9105 JSValueRegs valueRegs = value.jsValueRegs();
9106 GPRReg tempGPR = temp.gpr();
9107
9108 JITCompiler::Jump cell = m_jit.branchIfCell(valueRegs);
9109 DFG_TYPE_CHECK(
9110 valueRegs, node->child1(), SpecCell | SpecOther,
9111 m_jit.branchIfNotOther(valueRegs, tempGPR));
9112 JITCompiler::Jump done = m_jit.jump();
9113 cell.link(&m_jit);
9114 emitStructureCheck(node, valueRegs.payloadGPR(), tempGPR);
9115 done.link(&m_jit);
9116 noResult(node);
9117 return;
9118 }
9119
9120 default:
9121 DFG_CRASH(m_jit.graph(), node, "Bad use kind");
9122 return;
9123 }
9124}
9125
9126void SpeculativeJIT::compileAllocatePropertyStorage(Node* node)
9127{
9128 ASSERT(!node->transition()->previous->outOfLineCapacity());
9129 ASSERT(initialOutOfLineCapacity == node->transition()->next->outOfLineCapacity());
9130
9131 size_t size = initialOutOfLineCapacity * sizeof(JSValue);
9132
9133 Allocator allocator = m_jit.vm()->jsValueGigacageAuxiliarySpace.allocatorForNonVirtual(size, AllocatorForMode::AllocatorIfExists);
9134
9135 if (!allocator || node->transition()->previous->couldHaveIndexingHeader()) {
9136 SpeculateCellOperand base(this, node->child1());
9137
9138 GPRReg baseGPR = base.gpr();
9139
9140 flushRegisters();
9141
9142 GPRFlushedCallResult result(this);
9143 callOperation(operationAllocateComplexPropertyStorageWithInitialCapacity, result.gpr(), baseGPR);
9144 m_jit.exceptionCheck();
9145
9146 storageResult(result.gpr(), node);
9147 return;
9148 }
9149
9150 GPRTemporary scratch1(this);
9151 GPRTemporary scratch2(this);
9152 GPRTemporary scratch3(this);
9153
9154 GPRReg scratchGPR1 = scratch1.gpr();
9155 GPRReg scratchGPR2 = scratch2.gpr();
9156 GPRReg scratchGPR3 = scratch3.gpr();
9157
9158 JITCompiler::JumpList slowPath;
9159 m_jit.emitAllocate(scratchGPR1, JITAllocator::constant(allocator), scratchGPR2, scratchGPR3, slowPath);
9160 m_jit.addPtr(JITCompiler::TrustedImm32(size + sizeof(IndexingHeader)), scratchGPR1);
9161
9162 addSlowPathGenerator(
9163 slowPathCall(slowPath, this, operationAllocateSimplePropertyStorageWithInitialCapacity, scratchGPR1));
9164
9165 for (ptrdiff_t offset = 0; offset < static_cast<ptrdiff_t>(size); offset += sizeof(void*))
9166 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratchGPR1, -(offset + sizeof(JSValue) + sizeof(void*))));
9167
9168 storageResult(scratchGPR1, node);
9169}
9170
9171void SpeculativeJIT::compileReallocatePropertyStorage(Node* node)
9172{
9173 size_t oldSize = node->transition()->previous->outOfLineCapacity() * sizeof(JSValue);
9174 size_t newSize = oldSize * outOfLineGrowthFactor;
9175 ASSERT(newSize == node->transition()->next->outOfLineCapacity() * sizeof(JSValue));
9176
9177 Allocator allocator = m_jit.vm()->jsValueGigacageAuxiliarySpace.allocatorForNonVirtual(newSize, AllocatorForMode::AllocatorIfExists);
9178
9179 if (!allocator || node->transition()->previous->couldHaveIndexingHeader()) {
9180 SpeculateCellOperand base(this, node->child1());
9181
9182 GPRReg baseGPR = base.gpr();
9183
9184 flushRegisters();
9185
9186 GPRFlushedCallResult result(this);
9187 callOperation(operationAllocateComplexPropertyStorage, result.gpr(), baseGPR, newSize / sizeof(JSValue));
9188 m_jit.exceptionCheck();
9189
9190 storageResult(result.gpr(), node);
9191 return;
9192 }
9193
9194 StorageOperand oldStorage(this, node->child2());
9195 GPRTemporary scratch1(this);
9196 GPRTemporary scratch2(this);
9197 GPRTemporary scratch3(this);
9198
9199 GPRReg oldStorageGPR = oldStorage.gpr();
9200 GPRReg scratchGPR1 = scratch1.gpr();
9201 GPRReg scratchGPR2 = scratch2.gpr();
9202 GPRReg scratchGPR3 = scratch3.gpr();
9203
9204 JITCompiler::JumpList slowPath;
9205 m_jit.emitAllocate(scratchGPR1, JITAllocator::constant(allocator), scratchGPR2, scratchGPR3, slowPath);
9206
9207 m_jit.addPtr(JITCompiler::TrustedImm32(newSize + sizeof(IndexingHeader)), scratchGPR1);
9208
9209 addSlowPathGenerator(
9210 slowPathCall(slowPath, this, operationAllocateSimplePropertyStorage, scratchGPR1, newSize / sizeof(JSValue)));
9211
9212 for (ptrdiff_t offset = oldSize; offset < static_cast<ptrdiff_t>(newSize); offset += sizeof(void*))
9213 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratchGPR1, -(offset + sizeof(JSValue) + sizeof(void*))));
9214
9215 // We have scratchGPR1 = new storage, scratchGPR2 = scratch
9216 for (ptrdiff_t offset = 0; offset < static_cast<ptrdiff_t>(oldSize); offset += sizeof(void*)) {
9217 m_jit.loadPtr(JITCompiler::Address(oldStorageGPR, -(offset + sizeof(JSValue) + sizeof(void*))), scratchGPR2);
9218 m_jit.storePtr(scratchGPR2, JITCompiler::Address(scratchGPR1, -(offset + sizeof(JSValue) + sizeof(void*))));
9219 }
9220
9221 storageResult(scratchGPR1, node);
9222}
9223
9224void SpeculativeJIT::compileNukeStructureAndSetButterfly(Node* node)
9225{
9226 SpeculateCellOperand base(this, node->child1());
9227 StorageOperand storage(this, node->child2());
9228
9229 GPRReg baseGPR = base.gpr();
9230 GPRReg storageGPR = storage.gpr();
9231
9232 m_jit.nukeStructureAndStoreButterfly(*m_jit.vm(), storageGPR, baseGPR);
9233
9234 noResult(node);
9235}
9236
9237void SpeculativeJIT::compileGetButterfly(Node* node)
9238{
9239 SpeculateCellOperand base(this, node->child1());
9240 GPRTemporary result(this, Reuse, base);
9241
9242 GPRReg baseGPR = base.gpr();
9243 GPRReg resultGPR = result.gpr();
9244
9245 m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::butterflyOffset()), resultGPR);
9246
9247 storageResult(resultGPR, node);
9248}
9249
9250static void allocateTemporaryRegistersForSnippet(SpeculativeJIT* jit, Vector<GPRTemporary>& gpHolders, Vector<FPRTemporary>& fpHolders, Vector<GPRReg>& gpScratch, Vector<FPRReg>& fpScratch, Snippet& snippet)
9251{
9252 for (unsigned i = 0; i < snippet.numGPScratchRegisters; ++i) {
9253 GPRTemporary temporary(jit);
9254 gpScratch.append(temporary.gpr());
9255 gpHolders.append(WTFMove(temporary));
9256 }
9257
9258 for (unsigned i = 0; i < snippet.numFPScratchRegisters; ++i) {
9259 FPRTemporary temporary(jit);
9260 fpScratch.append(temporary.fpr());
9261 fpHolders.append(WTFMove(temporary));
9262 }
9263}
9264
9265void SpeculativeJIT::compileCallDOM(Node* node)
9266{
9267 const DOMJIT::Signature* signature = node->signature();
9268
9269 // FIXME: We should have a way to call functions with the vector of registers.
9270 // https://bugs.webkit.org/show_bug.cgi?id=163099
9271 Vector<Variant<SpeculateCellOperand, SpeculateInt32Operand, SpeculateBooleanOperand>, JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS_INCLUDING_THIS> operands;
9272 Vector<GPRReg, JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS_INCLUDING_THIS> regs;
9273
9274 auto appendCell = [&](Edge& edge) {
9275 SpeculateCellOperand operand(this, edge);
9276 regs.append(operand.gpr());
9277 operands.append(WTFMove(operand));
9278 };
9279
9280 auto appendString = [&](Edge& edge) {
9281 SpeculateCellOperand operand(this, edge);
9282 GPRReg gpr = operand.gpr();
9283 regs.append(gpr);
9284 speculateString(edge, gpr);
9285 operands.append(WTFMove(operand));
9286 };
9287
9288 auto appendInt32 = [&](Edge& edge) {
9289 SpeculateInt32Operand operand(this, edge);
9290 regs.append(operand.gpr());
9291 operands.append(WTFMove(operand));
9292 };
9293
9294 auto appendBoolean = [&](Edge& edge) {
9295 SpeculateBooleanOperand operand(this, edge);
9296 regs.append(operand.gpr());
9297 operands.append(WTFMove(operand));
9298 };
9299
9300 unsigned index = 0;
9301 m_jit.graph().doToChildren(node, [&](Edge edge) {
9302 if (!index)
9303 appendCell(edge);
9304 else {
9305 switch (signature->arguments[index - 1]) {
9306 case SpecString:
9307 appendString(edge);
9308 break;
9309 case SpecInt32Only:
9310 appendInt32(edge);
9311 break;
9312 case SpecBoolean:
9313 appendBoolean(edge);
9314 break;
9315 default:
9316 RELEASE_ASSERT_NOT_REACHED();
9317 break;
9318 }
9319 }
9320 ++index;
9321 });
9322
9323 JSValueRegsTemporary result(this);
9324 JSValueRegs resultRegs = result.regs();
9325
9326 flushRegisters();
9327 assertIsTaggedWith(reinterpret_cast<void*>(signature->unsafeFunction), CFunctionPtrTag);
9328 unsigned argumentCountIncludingThis = signature->argumentCount + 1;
9329 switch (argumentCountIncludingThis) {
9330 case 1:
9331 callOperation(reinterpret_cast<J_JITOperation_EP>(signature->unsafeFunction), extractResult(resultRegs), regs[0]);
9332 break;
9333 case 2:
9334 callOperation(reinterpret_cast<J_JITOperation_EPP>(signature->unsafeFunction), extractResult(resultRegs), regs[0], regs[1]);
9335 break;
9336 case 3:
9337 callOperation(reinterpret_cast<J_JITOperation_EPPP>(signature->unsafeFunction), extractResult(resultRegs), regs[0], regs[1], regs[2]);
9338 break;
9339 default:
9340 RELEASE_ASSERT_NOT_REACHED();
9341 break;
9342 }
9343
9344 m_jit.exceptionCheck();
9345 jsValueResult(resultRegs, node);
9346}
9347
9348void SpeculativeJIT::compileCallDOMGetter(Node* node)
9349{
9350 DOMJIT::CallDOMGetterSnippet* snippet = node->callDOMGetterData()->snippet;
9351 if (!snippet) {
9352 FunctionPtr<OperationPtrTag> getter = node->callDOMGetterData()->customAccessorGetter;
9353 SpeculateCellOperand base(this, node->child1());
9354 JSValueRegsTemporary result(this);
9355
9356 JSValueRegs resultRegs = result.regs();
9357 GPRReg baseGPR = base.gpr();
9358
9359 flushRegisters();
9360 m_jit.setupArguments<J_JITOperation_EJI>(CCallHelpers::CellValue(baseGPR), identifierUID(node->callDOMGetterData()->identifierNumber));
9361 m_jit.storePtr(GPRInfo::callFrameRegister, &m_jit.vm()->topCallFrame);
9362 m_jit.emitStoreCodeOrigin(m_currentNode->origin.semantic);
9363 m_jit.appendCall(getter.retagged<CFunctionPtrTag>());
9364 m_jit.setupResults(resultRegs);
9365
9366 m_jit.exceptionCheck();
9367 jsValueResult(resultRegs, node);
9368 return;
9369 }
9370
9371 Vector<GPRReg> gpScratch;
9372 Vector<FPRReg> fpScratch;
9373 Vector<SnippetParams::Value> regs;
9374
9375 JSValueRegsTemporary result(this);
9376 regs.append(result.regs());
9377
9378 Edge& baseEdge = node->child1();
9379 SpeculateCellOperand base(this, baseEdge);
9380 regs.append(SnippetParams::Value(base.gpr(), m_state.forNode(baseEdge).value()));
9381
9382 Optional<SpeculateCellOperand> globalObject;
9383 if (snippet->requireGlobalObject) {
9384 Edge& globalObjectEdge = node->child2();
9385 globalObject.emplace(this, globalObjectEdge);
9386 regs.append(SnippetParams::Value(globalObject->gpr(), m_state.forNode(globalObjectEdge).value()));
9387 }
9388
9389 Vector<GPRTemporary> gpTempraries;
9390 Vector<FPRTemporary> fpTempraries;
9391 allocateTemporaryRegistersForSnippet(this, gpTempraries, fpTempraries, gpScratch, fpScratch, *snippet);
9392 SnippetParams params(this, WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
9393 snippet->generator()->run(m_jit, params);
9394 jsValueResult(result.regs(), node);
9395}
9396
9397void SpeculativeJIT::compileCheckSubClass(Node* node)
9398{
9399 const ClassInfo* classInfo = node->classInfo();
9400 if (!classInfo->checkSubClassSnippet) {
9401 SpeculateCellOperand base(this, node->child1());
9402 GPRTemporary other(this);
9403 GPRTemporary specified(this);
9404
9405 GPRReg baseGPR = base.gpr();
9406 GPRReg otherGPR = other.gpr();
9407 GPRReg specifiedGPR = specified.gpr();
9408
9409 m_jit.emitLoadStructure(*m_jit.vm(), baseGPR, otherGPR, specifiedGPR);
9410 m_jit.loadPtr(CCallHelpers::Address(otherGPR, Structure::classInfoOffset()), otherGPR);
9411 m_jit.move(CCallHelpers::TrustedImmPtr(node->classInfo()), specifiedGPR);
9412
9413 CCallHelpers::Label loop = m_jit.label();
9414 auto done = m_jit.branchPtr(CCallHelpers::Equal, otherGPR, specifiedGPR);
9415 m_jit.loadPtr(CCallHelpers::Address(otherGPR, ClassInfo::offsetOfParentClass()), otherGPR);
9416 m_jit.branchTestPtr(CCallHelpers::NonZero, otherGPR).linkTo(loop, &m_jit);
9417 speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node->child1(), m_jit.jump());
9418 done.link(&m_jit);
9419 noResult(node);
9420 return;
9421 }
9422
9423 Ref<Snippet> snippet = classInfo->checkSubClassSnippet();
9424
9425 Vector<GPRReg> gpScratch;
9426 Vector<FPRReg> fpScratch;
9427 Vector<SnippetParams::Value> regs;
9428
9429 SpeculateCellOperand base(this, node->child1());
9430 GPRReg baseGPR = base.gpr();
9431 regs.append(SnippetParams::Value(baseGPR, m_state.forNode(node->child1()).value()));
9432
9433 Vector<GPRTemporary> gpTempraries;
9434 Vector<FPRTemporary> fpTempraries;
9435 allocateTemporaryRegistersForSnippet(this, gpTempraries, fpTempraries, gpScratch, fpScratch, snippet.get());
9436
9437 SnippetParams params(this, WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
9438 CCallHelpers::JumpList failureCases = snippet->generator()->run(m_jit, params);
9439 speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node->child1(), failureCases);
9440 noResult(node);
9441}
9442
9443GPRReg SpeculativeJIT::temporaryRegisterForPutByVal(GPRTemporary& temporary, ArrayMode arrayMode)
9444{
9445 if (!putByValWillNeedExtraRegister(arrayMode))
9446 return InvalidGPRReg;
9447
9448 GPRTemporary realTemporary(this);
9449 temporary.adopt(realTemporary);
9450 return temporary.gpr();
9451}
9452
9453void SpeculativeJIT::compileToStringOrCallStringConstructorOrStringValueOf(Node* node)
9454{
9455 ASSERT(node->op() != StringValueOf || node->child1().useKind() == UntypedUse);
9456 switch (node->child1().useKind()) {
9457 case NotCellUse: {
9458 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
9459 JSValueRegs op1Regs = op1.jsValueRegs();
9460
9461 GPRFlushedCallResult result(this);
9462 GPRReg resultGPR = result.gpr();
9463
9464 speculateNotCell(node->child1(), op1Regs);
9465
9466 flushRegisters();
9467
9468 if (node->op() == ToString)
9469 callOperation(operationToString, resultGPR, op1Regs);
9470 else {
9471 ASSERT(node->op() == CallStringConstructor);
9472 callOperation(operationCallStringConstructor, resultGPR, op1Regs);
9473 }
9474 m_jit.exceptionCheck();
9475 cellResult(resultGPR, node);
9476 return;
9477 }
9478
9479 case UntypedUse: {
9480 JSValueOperand op1(this, node->child1());
9481 JSValueRegs op1Regs = op1.jsValueRegs();
9482 GPRReg op1PayloadGPR = op1Regs.payloadGPR();
9483
9484 GPRFlushedCallResult result(this);
9485 GPRReg resultGPR = result.gpr();
9486
9487 flushRegisters();
9488
9489 JITCompiler::Jump done;
9490 if (node->child1()->prediction() & SpecString) {
9491 JITCompiler::Jump slowPath1 = m_jit.branchIfNotCell(op1.jsValueRegs());
9492 JITCompiler::Jump slowPath2 = m_jit.branchIfNotString(op1PayloadGPR);
9493 m_jit.move(op1PayloadGPR, resultGPR);
9494 done = m_jit.jump();
9495 slowPath1.link(&m_jit);
9496 slowPath2.link(&m_jit);
9497 }
9498 if (node->op() == ToString)
9499 callOperation(operationToString, resultGPR, op1Regs);
9500 else if (node->op() == StringValueOf)
9501 callOperation(operationStringValueOf, resultGPR, op1Regs);
9502 else {
9503 ASSERT(node->op() == CallStringConstructor);
9504 callOperation(operationCallStringConstructor, resultGPR, op1Regs);
9505 }
9506 m_jit.exceptionCheck();
9507 if (done.isSet())
9508 done.link(&m_jit);
9509 cellResult(resultGPR, node);
9510 return;
9511 }
9512
9513 case Int32Use:
9514 case Int52RepUse:
9515 case DoubleRepUse:
9516 compileNumberToStringWithValidRadixConstant(node, 10);
9517 return;
9518
9519 default:
9520 break;
9521 }
9522
9523 SpeculateCellOperand op1(this, node->child1());
9524 GPRReg op1GPR = op1.gpr();
9525
9526 switch (node->child1().useKind()) {
9527 case StringObjectUse: {
9528 GPRTemporary result(this);
9529 GPRReg resultGPR = result.gpr();
9530
9531 speculateStringObject(node->child1(), op1GPR);
9532
9533 m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR);
9534 cellResult(resultGPR, node);
9535 break;
9536 }
9537
9538 case StringOrStringObjectUse: {
9539 GPRTemporary result(this);
9540 GPRReg resultGPR = result.gpr();
9541
9542 m_jit.load8(JITCompiler::Address(op1GPR, JSCell::typeInfoTypeOffset()), resultGPR);
9543 JITCompiler::Jump isString = m_jit.branch32(JITCompiler::Equal, resultGPR, TrustedImm32(StringType));
9544
9545 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1().node(), m_jit.branch32(JITCompiler::NotEqual, resultGPR, TrustedImm32(StringObjectType)));
9546 m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR);
9547 JITCompiler::Jump done = m_jit.jump();
9548
9549 isString.link(&m_jit);
9550 m_jit.move(op1GPR, resultGPR);
9551 done.link(&m_jit);
9552
9553 m_interpreter.filter(node->child1(), SpecString | SpecStringObject);
9554
9555 cellResult(resultGPR, node);
9556 break;
9557 }
9558
9559 case CellUse: {
9560 GPRFlushedCallResult result(this);
9561 GPRReg resultGPR = result.gpr();
9562
9563 // We flush registers instead of silent spill/fill because in this mode we
9564 // believe that most likely the input is not a string, and we need to take
9565 // slow path.
9566 flushRegisters();
9567 JITCompiler::Jump done;
9568 if (node->child1()->prediction() & SpecString) {
9569 JITCompiler::Jump needCall = m_jit.branchIfNotString(op1GPR);
9570 m_jit.move(op1GPR, resultGPR);
9571 done = m_jit.jump();
9572 needCall.link(&m_jit);
9573 }
9574 if (node->op() == ToString)
9575 callOperation(operationToStringOnCell, resultGPR, op1GPR);
9576 else {
9577 ASSERT(node->op() == CallStringConstructor);
9578 callOperation(operationCallStringConstructorOnCell, resultGPR, op1GPR);
9579 }
9580 m_jit.exceptionCheck();
9581 if (done.isSet())
9582 done.link(&m_jit);
9583 cellResult(resultGPR, node);
9584 break;
9585 }
9586
9587 default:
9588 RELEASE_ASSERT_NOT_REACHED();
9589 }
9590}
9591
9592void SpeculativeJIT::compileNumberToStringWithValidRadixConstant(Node* node)
9593{
9594 compileNumberToStringWithValidRadixConstant(node, node->validRadixConstant());
9595}
9596
9597void SpeculativeJIT::compileNumberToStringWithValidRadixConstant(Node* node, int32_t radix)
9598{
9599 auto callToString = [&] (auto operation, GPRReg resultGPR, auto valueReg) {
9600 flushRegisters();
9601 callOperation(operation, resultGPR, valueReg, TrustedImm32(radix));
9602 m_jit.exceptionCheck();
9603 cellResult(resultGPR, node);
9604 };
9605
9606 switch (node->child1().useKind()) {
9607 case Int32Use: {
9608 SpeculateStrictInt32Operand value(this, node->child1());
9609 GPRFlushedCallResult result(this);
9610 callToString(operationInt32ToStringWithValidRadix, result.gpr(), value.gpr());
9611 break;
9612 }
9613
9614#if USE(JSVALUE64)
9615 case Int52RepUse: {
9616 SpeculateStrictInt52Operand value(this, node->child1());
9617 GPRFlushedCallResult result(this);
9618 callToString(operationInt52ToStringWithValidRadix, result.gpr(), value.gpr());
9619 break;
9620 }
9621#endif
9622
9623 case DoubleRepUse: {
9624 SpeculateDoubleOperand value(this, node->child1());
9625 GPRFlushedCallResult result(this);
9626 callToString(operationDoubleToStringWithValidRadix, result.gpr(), value.fpr());
9627 break;
9628 }
9629
9630 default:
9631 RELEASE_ASSERT_NOT_REACHED();
9632 }
9633}
9634
9635void SpeculativeJIT::compileNumberToStringWithRadix(Node* node)
9636{
9637 bool validRadixIsGuaranteed = false;
9638 if (node->child2()->isInt32Constant()) {
9639 int32_t radix = node->child2()->asInt32();
9640 if (radix >= 2 && radix <= 36)
9641 validRadixIsGuaranteed = true;
9642 }
9643
9644 auto callToString = [&] (auto operation, GPRReg resultGPR, auto valueReg, GPRReg radixGPR) {
9645 flushRegisters();
9646 callOperation(operation, resultGPR, valueReg, radixGPR);
9647 m_jit.exceptionCheck();
9648 cellResult(resultGPR, node);
9649 };
9650
9651 switch (node->child1().useKind()) {
9652 case Int32Use: {
9653 SpeculateStrictInt32Operand value(this, node->child1());
9654 SpeculateStrictInt32Operand radix(this, node->child2());
9655 GPRFlushedCallResult result(this);
9656 callToString(validRadixIsGuaranteed ? operationInt32ToStringWithValidRadix : operationInt32ToString, result.gpr(), value.gpr(), radix.gpr());
9657 break;
9658 }
9659
9660#if USE(JSVALUE64)
9661 case Int52RepUse: {
9662 SpeculateStrictInt52Operand value(this, node->child1());
9663 SpeculateStrictInt32Operand radix(this, node->child2());
9664 GPRFlushedCallResult result(this);
9665 callToString(validRadixIsGuaranteed ? operationInt52ToStringWithValidRadix : operationInt52ToString, result.gpr(), value.gpr(), radix.gpr());
9666 break;
9667 }
9668#endif
9669
9670 case DoubleRepUse: {
9671 SpeculateDoubleOperand value(this, node->child1());
9672 SpeculateStrictInt32Operand radix(this, node->child2());
9673 GPRFlushedCallResult result(this);
9674 callToString(validRadixIsGuaranteed ? operationDoubleToStringWithValidRadix : operationDoubleToString, result.gpr(), value.fpr(), radix.gpr());
9675 break;
9676 }
9677
9678 default:
9679 RELEASE_ASSERT_NOT_REACHED();
9680 }
9681}
9682
9683void SpeculativeJIT::compileNewStringObject(Node* node)
9684{
9685 SpeculateCellOperand operand(this, node->child1());
9686
9687 GPRTemporary result(this);
9688 GPRTemporary scratch1(this);
9689 GPRTemporary scratch2(this);
9690
9691 GPRReg operandGPR = operand.gpr();
9692 GPRReg resultGPR = result.gpr();
9693 GPRReg scratch1GPR = scratch1.gpr();
9694 GPRReg scratch2GPR = scratch2.gpr();
9695
9696 JITCompiler::JumpList slowPath;
9697
9698 auto butterfly = TrustedImmPtr(nullptr);
9699 emitAllocateJSObject<StringObject>(
9700 resultGPR, TrustedImmPtr(node->structure()), butterfly, scratch1GPR, scratch2GPR,
9701 slowPath);
9702
9703 m_jit.storePtr(
9704 TrustedImmPtr(StringObject::info()),
9705 JITCompiler::Address(resultGPR, JSDestructibleObject::classInfoOffset()));
9706#if USE(JSVALUE64)
9707 m_jit.store64(
9708 operandGPR, JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset()));
9709#else
9710 m_jit.store32(
9711 TrustedImm32(JSValue::CellTag),
9712 JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
9713 m_jit.store32(
9714 operandGPR,
9715 JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
9716#endif
9717
9718 m_jit.mutatorFence(*m_jit.vm());
9719
9720 addSlowPathGenerator(slowPathCall(
9721 slowPath, this, operationNewStringObject, resultGPR, operandGPR, node->structure()));
9722
9723 cellResult(resultGPR, node);
9724}
9725
9726void SpeculativeJIT::compileNewSymbol(Node* node)
9727{
9728 if (!node->child1()) {
9729 flushRegisters();
9730 GPRFlushedCallResult result(this);
9731 GPRReg resultGPR = result.gpr();
9732 callOperation(operationNewSymbol, resultGPR);
9733 m_jit.exceptionCheck();
9734 cellResult(resultGPR, node);
9735 return;
9736 }
9737
9738
9739 ASSERT(node->child1().useKind() == KnownStringUse);
9740 SpeculateCellOperand operand(this, node->child1());
9741
9742 GPRReg stringGPR = operand.gpr();
9743
9744 flushRegisters();
9745 GPRFlushedCallResult result(this);
9746 GPRReg resultGPR = result.gpr();
9747 callOperation(operationNewSymbolWithDescription, resultGPR, stringGPR);
9748 m_jit.exceptionCheck();
9749 cellResult(resultGPR, node);
9750}
9751
9752void SpeculativeJIT::compileNewTypedArrayWithSize(Node* node)
9753{
9754 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
9755 auto typedArrayType = node->typedArrayType();
9756 RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->typedArrayStructureConcurrently(typedArrayType));
9757 RELEASE_ASSERT(structure.get());
9758
9759 SpeculateInt32Operand size(this, node->child1());
9760 GPRReg sizeGPR = size.gpr();
9761
9762 GPRTemporary result(this);
9763 GPRTemporary storage(this);
9764 GPRTemporary scratch(this);
9765 GPRTemporary scratch2(this);
9766 GPRReg resultGPR = result.gpr();
9767 GPRReg storageGPR = storage.gpr();
9768 GPRReg scratchGPR = scratch.gpr();
9769 GPRReg scratchGPR2 = scratch2.gpr();
9770
9771 JITCompiler::JumpList slowCases;
9772
9773 m_jit.move(TrustedImmPtr(nullptr), storageGPR);
9774
9775 slowCases.append(m_jit.branch32(
9776 MacroAssembler::Above, sizeGPR, TrustedImm32(JSArrayBufferView::fastSizeLimit)));
9777
9778 m_jit.move(sizeGPR, scratchGPR);
9779 m_jit.lshift32(TrustedImm32(logElementSize(typedArrayType)), scratchGPR);
9780 if (elementSize(typedArrayType) < 8) {
9781 m_jit.add32(TrustedImm32(7), scratchGPR);
9782 m_jit.and32(TrustedImm32(~7), scratchGPR);
9783 }
9784 m_jit.emitAllocateVariableSized(
9785 storageGPR, m_jit.vm()->primitiveGigacageAuxiliarySpace, scratchGPR, scratchGPR,
9786 scratchGPR2, slowCases);
9787
9788 MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, sizeGPR);
9789 m_jit.move(sizeGPR, scratchGPR);
9790 if (elementSize(typedArrayType) != 4) {
9791 if (elementSize(typedArrayType) > 4)
9792 m_jit.lshift32(TrustedImm32(logElementSize(typedArrayType) - 2), scratchGPR);
9793 else {
9794 if (elementSize(typedArrayType) > 1)
9795 m_jit.lshift32(TrustedImm32(logElementSize(typedArrayType)), scratchGPR);
9796 m_jit.add32(TrustedImm32(3), scratchGPR);
9797 m_jit.urshift32(TrustedImm32(2), scratchGPR);
9798 }
9799 }
9800 MacroAssembler::Label loop = m_jit.label();
9801 m_jit.sub32(TrustedImm32(1), scratchGPR);
9802 m_jit.store32(
9803 TrustedImm32(0),
9804 MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesFour));
9805 m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
9806 done.link(&m_jit);
9807#if !GIGACAGE_ENABLED && CPU(ARM64E)
9808 // sizeGPR is still boxed as a number and there is no 32-bit variant of the PAC instructions.
9809 m_jit.zeroExtend32ToPtr(sizeGPR, scratchGPR);
9810 m_jit.tagArrayPtr(scratchGPR, storageGPR);
9811#endif
9812
9813 auto butterfly = TrustedImmPtr(nullptr);
9814 emitAllocateJSObject<JSArrayBufferView>(
9815 resultGPR, TrustedImmPtr(structure), butterfly, scratchGPR, scratchGPR2,
9816 slowCases);
9817
9818 m_jit.storePtr(
9819 storageGPR,
9820 MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfVector()));
9821 m_jit.store32(
9822 sizeGPR,
9823 MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfLength()));
9824 m_jit.store32(
9825 TrustedImm32(FastTypedArray),
9826 MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfMode()));
9827
9828 m_jit.mutatorFence(*m_jit.vm());
9829
9830 addSlowPathGenerator(slowPathCall(
9831 slowCases, this, operationNewTypedArrayWithSizeForType(typedArrayType),
9832 resultGPR, structure, sizeGPR, storageGPR));
9833
9834 cellResult(resultGPR, node);
9835}
9836
9837void SpeculativeJIT::compileNewRegexp(Node* node)
9838{
9839 RegExp* regexp = node->castOperand<RegExp*>();
9840
9841 GPRTemporary result(this);
9842 GPRTemporary scratch1(this);
9843 GPRTemporary scratch2(this);
9844 JSValueOperand lastIndex(this, node->child1());
9845
9846 GPRReg resultGPR = result.gpr();
9847 GPRReg scratch1GPR = scratch1.gpr();
9848 GPRReg scratch2GPR = scratch2.gpr();
9849 JSValueRegs lastIndexRegs = lastIndex.jsValueRegs();
9850
9851 JITCompiler::JumpList slowPath;
9852
9853 auto structure = m_jit.graph().registerStructure(m_jit.graph().globalObjectFor(node->origin.semantic)->regExpStructure());
9854 auto butterfly = TrustedImmPtr(nullptr);
9855 emitAllocateJSObject<RegExpObject>(resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR, slowPath);
9856
9857 m_jit.storePtr(
9858 TrustedImmPtr(node->cellOperand()),
9859 CCallHelpers::Address(resultGPR, RegExpObject::offsetOfRegExpAndLastIndexIsNotWritableFlag()));
9860 m_jit.storeValue(lastIndexRegs, CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndex()));
9861 m_jit.mutatorFence(*m_jit.vm());
9862
9863 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewRegexpWithLastIndex, resultGPR, regexp, lastIndexRegs));
9864
9865 cellResult(resultGPR, node);
9866}
9867
9868void SpeculativeJIT::speculateCellTypeWithoutTypeFiltering(
9869 Edge edge, GPRReg cellGPR, JSType jsType)
9870{
9871 speculationCheck(
9872 BadType, JSValueSource::unboxedCell(cellGPR), edge,
9873 m_jit.branchIfNotType(cellGPR, jsType));
9874}
9875
9876void SpeculativeJIT::speculateCellType(
9877 Edge edge, GPRReg cellGPR, SpeculatedType specType, JSType jsType)
9878{
9879 DFG_TYPE_CHECK(
9880 JSValueSource::unboxedCell(cellGPR), edge, specType,
9881 m_jit.branchIfNotType(cellGPR, jsType));
9882}
9883
9884void SpeculativeJIT::speculateInt32(Edge edge)
9885{
9886 if (!needsTypeCheck(edge, SpecInt32Only))
9887 return;
9888
9889 (SpeculateInt32Operand(this, edge)).gpr();
9890}
9891
9892void SpeculativeJIT::speculateNumber(Edge edge)
9893{
9894 if (!needsTypeCheck(edge, SpecBytecodeNumber))
9895 return;
9896
9897 JSValueOperand value(this, edge, ManualOperandSpeculation);
9898#if USE(JSVALUE64)
9899 GPRReg gpr = value.gpr();
9900 typeCheck(
9901 JSValueRegs(gpr), edge, SpecBytecodeNumber,
9902 m_jit.branchIfNotNumber(gpr));
9903#else
9904 IGNORE_WARNINGS_BEGIN("enum-compare")
9905 static_assert(JSValue::Int32Tag >= JSValue::LowestTag, "Int32Tag is included in >= JSValue::LowestTag range.");
9906 IGNORE_WARNINGS_END
9907 GPRReg tagGPR = value.tagGPR();
9908 DFG_TYPE_CHECK(
9909 value.jsValueRegs(), edge, ~SpecInt32Only,
9910 m_jit.branchIfInt32(tagGPR));
9911 DFG_TYPE_CHECK(
9912 value.jsValueRegs(), edge, SpecBytecodeNumber,
9913 m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag)));
9914#endif
9915}
9916
9917void SpeculativeJIT::speculateRealNumber(Edge edge)
9918{
9919 if (!needsTypeCheck(edge, SpecBytecodeRealNumber))
9920 return;
9921
9922 JSValueOperand op1(this, edge, ManualOperandSpeculation);
9923 FPRTemporary result(this);
9924
9925 JSValueRegs op1Regs = op1.jsValueRegs();
9926 FPRReg resultFPR = result.fpr();
9927
9928#if USE(JSVALUE64)
9929 GPRTemporary temp(this);
9930 GPRReg tempGPR = temp.gpr();
9931 m_jit.unboxDoubleWithoutAssertions(op1Regs.gpr(), tempGPR, resultFPR);
9932#else
9933 FPRTemporary temp(this);
9934 FPRReg tempFPR = temp.fpr();
9935 unboxDouble(op1Regs.tagGPR(), op1Regs.payloadGPR(), resultFPR, tempFPR);
9936#endif
9937
9938 JITCompiler::Jump done = m_jit.branchIfNotNaN(resultFPR);
9939
9940 typeCheck(op1Regs, edge, SpecBytecodeRealNumber, m_jit.branchIfNotInt32(op1Regs));
9941
9942 done.link(&m_jit);
9943}
9944
9945void SpeculativeJIT::speculateDoubleRepReal(Edge edge)
9946{
9947 if (!needsTypeCheck(edge, SpecDoubleReal))
9948 return;
9949
9950 SpeculateDoubleOperand operand(this, edge);
9951 FPRReg fpr = operand.fpr();
9952 typeCheck(
9953 JSValueRegs(), edge, SpecDoubleReal,
9954 m_jit.branchIfNaN(fpr));
9955}
9956
9957void SpeculativeJIT::speculateBoolean(Edge edge)
9958{
9959 if (!needsTypeCheck(edge, SpecBoolean))
9960 return;
9961
9962 (SpeculateBooleanOperand(this, edge)).gpr();
9963}
9964
9965void SpeculativeJIT::speculateCell(Edge edge)
9966{
9967 if (!needsTypeCheck(edge, SpecCellCheck))
9968 return;
9969
9970 (SpeculateCellOperand(this, edge)).gpr();
9971}
9972
9973void SpeculativeJIT::speculateCellOrOther(Edge edge)
9974{
9975 if (!needsTypeCheck(edge, SpecCellCheck | SpecOther))
9976 return;
9977
9978 JSValueOperand operand(this, edge, ManualOperandSpeculation);
9979 GPRTemporary temp(this);
9980 GPRReg tempGPR = temp.gpr();
9981
9982 MacroAssembler::Jump ok = m_jit.branchIfCell(operand.jsValueRegs());
9983 DFG_TYPE_CHECK(
9984 operand.jsValueRegs(), edge, SpecCellCheck | SpecOther,
9985 m_jit.branchIfNotOther(operand.jsValueRegs(), tempGPR));
9986 ok.link(&m_jit);
9987}
9988
9989void SpeculativeJIT::speculateObject(Edge edge, GPRReg cell)
9990{
9991 DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, SpecObject, m_jit.branchIfNotObject(cell));
9992}
9993
9994void SpeculativeJIT::speculateObject(Edge edge)
9995{
9996 if (!needsTypeCheck(edge, SpecObject))
9997 return;
9998
9999 SpeculateCellOperand operand(this, edge);
10000 speculateObject(edge, operand.gpr());
10001}
10002
10003void SpeculativeJIT::speculateFunction(Edge edge, GPRReg cell)
10004{
10005 speculateCellType(edge, cell, SpecFunction, JSFunctionType);
10006}
10007
10008void SpeculativeJIT::speculateFunction(Edge edge)
10009{
10010 if (!needsTypeCheck(edge, SpecFunction))
10011 return;
10012
10013 SpeculateCellOperand operand(this, edge);
10014 speculateFunction(edge, operand.gpr());
10015}
10016
10017void SpeculativeJIT::speculateFinalObject(Edge edge, GPRReg cell)
10018{
10019 speculateCellType(edge, cell, SpecFinalObject, FinalObjectType);
10020}
10021
10022void SpeculativeJIT::speculateFinalObject(Edge edge)
10023{
10024 if (!needsTypeCheck(edge, SpecFinalObject))
10025 return;
10026
10027 SpeculateCellOperand operand(this, edge);
10028 speculateFinalObject(edge, operand.gpr());
10029}
10030
10031void SpeculativeJIT::speculateRegExpObject(Edge edge, GPRReg cell)
10032{
10033 speculateCellType(edge, cell, SpecRegExpObject, RegExpObjectType);
10034}
10035
10036void SpeculativeJIT::speculateRegExpObject(Edge edge)
10037{
10038 if (!needsTypeCheck(edge, SpecRegExpObject))
10039 return;
10040
10041 SpeculateCellOperand operand(this, edge);
10042 speculateRegExpObject(edge, operand.gpr());
10043}
10044
10045void SpeculativeJIT::speculateArray(Edge edge, GPRReg cell)
10046{
10047 speculateCellType(edge, cell, SpecArray, ArrayType);
10048}
10049
10050void SpeculativeJIT::speculateArray(Edge edge)
10051{
10052 if (!needsTypeCheck(edge, SpecArray))
10053 return;
10054
10055 SpeculateCellOperand operand(this, edge);
10056 speculateArray(edge, operand.gpr());
10057}
10058
10059void SpeculativeJIT::speculateProxyObject(Edge edge, GPRReg cell)
10060{
10061 speculateCellType(edge, cell, SpecProxyObject, ProxyObjectType);
10062}
10063
10064void SpeculativeJIT::speculateProxyObject(Edge edge)
10065{
10066 if (!needsTypeCheck(edge, SpecProxyObject))
10067 return;
10068
10069 SpeculateCellOperand operand(this, edge);
10070 speculateProxyObject(edge, operand.gpr());
10071}
10072
10073void SpeculativeJIT::speculateDerivedArray(Edge edge, GPRReg cell)
10074{
10075 speculateCellType(edge, cell, SpecDerivedArray, DerivedArrayType);
10076}
10077
10078void SpeculativeJIT::speculateDerivedArray(Edge edge)
10079{
10080 if (!needsTypeCheck(edge, SpecDerivedArray))
10081 return;
10082
10083 SpeculateCellOperand operand(this, edge);
10084 speculateDerivedArray(edge, operand.gpr());
10085}
10086
10087void SpeculativeJIT::speculateMapObject(Edge edge, GPRReg cell)
10088{
10089 speculateCellType(edge, cell, SpecMapObject, JSMapType);
10090}
10091
10092void SpeculativeJIT::speculateMapObject(Edge edge)
10093{
10094 if (!needsTypeCheck(edge, SpecMapObject))
10095 return;
10096
10097 SpeculateCellOperand operand(this, edge);
10098 speculateMapObject(edge, operand.gpr());
10099}
10100
10101void SpeculativeJIT::speculateSetObject(Edge edge, GPRReg cell)
10102{
10103 speculateCellType(edge, cell, SpecSetObject, JSSetType);
10104}
10105
10106void SpeculativeJIT::speculateSetObject(Edge edge)
10107{
10108 if (!needsTypeCheck(edge, SpecSetObject))
10109 return;
10110
10111 SpeculateCellOperand operand(this, edge);
10112 speculateSetObject(edge, operand.gpr());
10113}
10114
10115void SpeculativeJIT::speculateWeakMapObject(Edge edge, GPRReg cell)
10116{
10117 speculateCellType(edge, cell, SpecWeakMapObject, JSWeakMapType);
10118}
10119
10120void SpeculativeJIT::speculateWeakMapObject(Edge edge)
10121{
10122 if (!needsTypeCheck(edge, SpecWeakMapObject))
10123 return;
10124
10125 SpeculateCellOperand operand(this, edge);
10126 speculateWeakMapObject(edge, operand.gpr());
10127}
10128
10129void SpeculativeJIT::speculateWeakSetObject(Edge edge, GPRReg cell)
10130{
10131 speculateCellType(edge, cell, SpecWeakSetObject, JSWeakSetType);
10132}
10133
10134void SpeculativeJIT::speculateWeakSetObject(Edge edge)
10135{
10136 if (!needsTypeCheck(edge, SpecWeakSetObject))
10137 return;
10138
10139 SpeculateCellOperand operand(this, edge);
10140 speculateWeakSetObject(edge, operand.gpr());
10141}
10142
10143void SpeculativeJIT::speculateDataViewObject(Edge edge, GPRReg cell)
10144{
10145 speculateCellType(edge, cell, SpecDataViewObject, DataViewType);
10146}
10147
10148void SpeculativeJIT::speculateDataViewObject(Edge edge)
10149{
10150 if (!needsTypeCheck(edge, SpecDataViewObject))
10151 return;
10152
10153 SpeculateCellOperand operand(this, edge);
10154 speculateDataViewObject(edge, operand.gpr());
10155}
10156
10157void SpeculativeJIT::speculateObjectOrOther(Edge edge)
10158{
10159 if (!needsTypeCheck(edge, SpecObject | SpecOther))
10160 return;
10161
10162 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10163 GPRTemporary temp(this);
10164 GPRReg tempGPR = temp.gpr();
10165 MacroAssembler::Jump notCell = m_jit.branchIfNotCell(operand.jsValueRegs());
10166 GPRReg gpr = operand.jsValueRegs().payloadGPR();
10167 DFG_TYPE_CHECK(
10168 operand.jsValueRegs(), edge, (~SpecCellCheck) | SpecObject, m_jit.branchIfNotObject(gpr));
10169 MacroAssembler::Jump done = m_jit.jump();
10170 notCell.link(&m_jit);
10171 DFG_TYPE_CHECK(
10172 operand.jsValueRegs(), edge, SpecCellCheck | SpecOther,
10173 m_jit.branchIfNotOther(operand.jsValueRegs(), tempGPR));
10174 done.link(&m_jit);
10175}
10176
10177void SpeculativeJIT::speculateString(Edge edge, GPRReg cell)
10178{
10179 DFG_TYPE_CHECK(
10180 JSValueSource::unboxedCell(cell), edge, SpecString | ~SpecCellCheck, m_jit.branchIfNotString(cell));
10181}
10182
10183void SpeculativeJIT::speculateStringOrOther(Edge edge, JSValueRegs regs, GPRReg scratch)
10184{
10185 JITCompiler::Jump notCell = m_jit.branchIfNotCell(regs);
10186 GPRReg cell = regs.payloadGPR();
10187 DFG_TYPE_CHECK(regs, edge, (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cell));
10188 JITCompiler::Jump done = m_jit.jump();
10189 notCell.link(&m_jit);
10190 DFG_TYPE_CHECK(regs, edge, SpecCellCheck | SpecOther, m_jit.branchIfNotOther(regs, scratch));
10191 done.link(&m_jit);
10192}
10193
10194void SpeculativeJIT::speculateStringOrOther(Edge edge)
10195{
10196 if (!needsTypeCheck(edge, SpecString | SpecOther))
10197 return;
10198
10199 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10200 GPRTemporary temp(this);
10201 JSValueRegs regs = operand.jsValueRegs();
10202 GPRReg tempGPR = temp.gpr();
10203 speculateStringOrOther(edge, regs, tempGPR);
10204}
10205
10206void SpeculativeJIT::speculateStringIdentAndLoadStorage(Edge edge, GPRReg string, GPRReg storage)
10207{
10208 m_jit.loadPtr(MacroAssembler::Address(string, JSString::offsetOfValue()), storage);
10209
10210 if (!needsTypeCheck(edge, SpecStringIdent | ~SpecString))
10211 return;
10212
10213 speculationCheck(
10214 BadType, JSValueSource::unboxedCell(string), edge,
10215 m_jit.branchIfRopeStringImpl(storage));
10216 speculationCheck(
10217 BadType, JSValueSource::unboxedCell(string), edge, m_jit.branchTest32(
10218 MacroAssembler::Zero,
10219 MacroAssembler::Address(storage, StringImpl::flagsOffset()),
10220 MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
10221
10222 m_interpreter.filter(edge, SpecStringIdent | ~SpecString);
10223}
10224
10225void SpeculativeJIT::speculateStringIdent(Edge edge, GPRReg string)
10226{
10227 if (!needsTypeCheck(edge, SpecStringIdent))
10228 return;
10229
10230 GPRTemporary temp(this);
10231 speculateStringIdentAndLoadStorage(edge, string, temp.gpr());
10232}
10233
10234void SpeculativeJIT::speculateStringIdent(Edge edge)
10235{
10236 if (!needsTypeCheck(edge, SpecStringIdent))
10237 return;
10238
10239 SpeculateCellOperand operand(this, edge);
10240 GPRReg gpr = operand.gpr();
10241 speculateString(edge, gpr);
10242 speculateStringIdent(edge, gpr);
10243}
10244
10245void SpeculativeJIT::speculateString(Edge edge)
10246{
10247 if (!needsTypeCheck(edge, SpecString))
10248 return;
10249
10250 SpeculateCellOperand operand(this, edge);
10251 speculateString(edge, operand.gpr());
10252}
10253
10254void SpeculativeJIT::speculateStringObject(Edge edge, GPRReg cellGPR)
10255{
10256 DFG_TYPE_CHECK(JSValueSource::unboxedCell(cellGPR), edge, ~SpecCellCheck | SpecStringObject, m_jit.branchIfNotType(cellGPR, StringObjectType));
10257}
10258
10259void SpeculativeJIT::speculateStringObject(Edge edge)
10260{
10261 if (!needsTypeCheck(edge, SpecStringObject))
10262 return;
10263
10264 SpeculateCellOperand operand(this, edge);
10265 GPRReg gpr = operand.gpr();
10266 speculateStringObject(edge, gpr);
10267}
10268
10269void SpeculativeJIT::speculateStringOrStringObject(Edge edge)
10270{
10271 if (!needsTypeCheck(edge, SpecString | SpecStringObject))
10272 return;
10273
10274 SpeculateCellOperand operand(this, edge);
10275 GPRReg gpr = operand.gpr();
10276 if (!needsTypeCheck(edge, SpecString | SpecStringObject))
10277 return;
10278
10279 GPRTemporary typeTemp(this);
10280 GPRReg typeGPR = typeTemp.gpr();
10281
10282 m_jit.load8(JITCompiler::Address(gpr, JSCell::typeInfoTypeOffset()), typeGPR);
10283
10284 JITCompiler::Jump isString = m_jit.branch32(JITCompiler::Equal, typeGPR, TrustedImm32(StringType));
10285 speculationCheck(BadType, JSValueSource::unboxedCell(gpr), edge.node(), m_jit.branch32(JITCompiler::NotEqual, typeGPR, TrustedImm32(StringObjectType)));
10286 isString.link(&m_jit);
10287
10288 m_interpreter.filter(edge, SpecString | SpecStringObject);
10289}
10290
10291void SpeculativeJIT::speculateNotStringVar(Edge edge)
10292{
10293 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10294 GPRTemporary temp(this);
10295 GPRReg tempGPR = temp.gpr();
10296
10297 JITCompiler::Jump notCell = m_jit.branchIfNotCell(operand.jsValueRegs());
10298 GPRReg cell = operand.jsValueRegs().payloadGPR();
10299
10300 JITCompiler::Jump notString = m_jit.branchIfNotString(cell);
10301
10302 speculateStringIdentAndLoadStorage(edge, cell, tempGPR);
10303
10304 notString.link(&m_jit);
10305 notCell.link(&m_jit);
10306}
10307
10308void SpeculativeJIT::speculateNotSymbol(Edge edge)
10309{
10310 if (!needsTypeCheck(edge, ~SpecSymbol))
10311 return;
10312
10313 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10314 auto valueRegs = operand.jsValueRegs();
10315 GPRReg value = valueRegs.payloadGPR();
10316 JITCompiler::Jump notCell;
10317
10318 bool needsCellCheck = needsTypeCheck(edge, SpecCell);
10319 if (needsCellCheck)
10320 notCell = m_jit.branchIfNotCell(valueRegs);
10321
10322 speculationCheck(BadType, JSValueSource::unboxedCell(value), edge.node(), m_jit.branchIfSymbol(value));
10323
10324 if (needsCellCheck)
10325 notCell.link(&m_jit);
10326
10327 m_interpreter.filter(edge, ~SpecSymbol);
10328}
10329
10330void SpeculativeJIT::speculateSymbol(Edge edge, GPRReg cell)
10331{
10332 DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, ~SpecCellCheck | SpecSymbol, m_jit.branchIfNotSymbol(cell));
10333}
10334
10335void SpeculativeJIT::speculateSymbol(Edge edge)
10336{
10337 if (!needsTypeCheck(edge, SpecSymbol))
10338 return;
10339
10340 SpeculateCellOperand operand(this, edge);
10341 speculateSymbol(edge, operand.gpr());
10342}
10343
10344void SpeculativeJIT::speculateBigInt(Edge edge, GPRReg cell)
10345{
10346 DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, ~SpecCellCheck | SpecBigInt, m_jit.branchIfNotBigInt(cell));
10347}
10348
10349void SpeculativeJIT::speculateBigInt(Edge edge)
10350{
10351 if (!needsTypeCheck(edge, SpecBigInt))
10352 return;
10353
10354 SpeculateCellOperand operand(this, edge);
10355 speculateBigInt(edge, operand.gpr());
10356}
10357
10358void SpeculativeJIT::speculateNotCell(Edge edge, JSValueRegs regs)
10359{
10360 DFG_TYPE_CHECK(regs, edge, ~SpecCellCheck, m_jit.branchIfCell(regs));
10361}
10362
10363void SpeculativeJIT::speculateNotCell(Edge edge)
10364{
10365 if (!needsTypeCheck(edge, ~SpecCellCheck))
10366 return;
10367
10368 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10369 speculateNotCell(edge, operand.jsValueRegs());
10370}
10371
10372void SpeculativeJIT::speculateOther(Edge edge, JSValueRegs regs, GPRReg tempGPR)
10373{
10374 DFG_TYPE_CHECK(regs, edge, SpecOther, m_jit.branchIfNotOther(regs, tempGPR));
10375}
10376
10377void SpeculativeJIT::speculateOther(Edge edge, JSValueRegs regs)
10378{
10379 if (!needsTypeCheck(edge, SpecOther))
10380 return;
10381
10382 GPRTemporary temp(this);
10383 GPRReg tempGPR = temp.gpr();
10384 speculateOther(edge, regs, tempGPR);
10385}
10386
10387void SpeculativeJIT::speculateOther(Edge edge)
10388{
10389 if (!needsTypeCheck(edge, SpecOther))
10390 return;
10391
10392 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10393 speculateOther(edge, operand.jsValueRegs());
10394}
10395
10396void SpeculativeJIT::speculateMisc(Edge edge, JSValueRegs regs)
10397{
10398#if USE(JSVALUE64)
10399 DFG_TYPE_CHECK(
10400 regs, edge, SpecMisc,
10401 m_jit.branch64(MacroAssembler::Above, regs.gpr(), MacroAssembler::TrustedImm64(TagBitTypeOther | TagBitBool | TagBitUndefined)));
10402#else
10403 IGNORE_WARNINGS_BEGIN("enum-compare")
10404 static_assert(JSValue::Int32Tag >= JSValue::UndefinedTag, "Int32Tag is included in >= JSValue::UndefinedTag range.");
10405 IGNORE_WARNINGS_END
10406 DFG_TYPE_CHECK(
10407 regs, edge, ~SpecInt32Only,
10408 m_jit.branchIfInt32(regs.tagGPR()));
10409 DFG_TYPE_CHECK(
10410 regs, edge, SpecMisc,
10411 m_jit.branch32(MacroAssembler::Below, regs.tagGPR(), MacroAssembler::TrustedImm32(JSValue::UndefinedTag)));
10412#endif
10413}
10414
10415void SpeculativeJIT::speculateMisc(Edge edge)
10416{
10417 if (!needsTypeCheck(edge, SpecMisc))
10418 return;
10419
10420 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10421 speculateMisc(edge, operand.jsValueRegs());
10422}
10423
10424void SpeculativeJIT::speculate(Node*, Edge edge)
10425{
10426 switch (edge.useKind()) {
10427 case UntypedUse:
10428 break;
10429 case DoubleRepUse:
10430 case Int52RepUse:
10431 case KnownInt32Use:
10432 case KnownCellUse:
10433 case KnownStringUse:
10434 case KnownPrimitiveUse:
10435 case KnownOtherUse:
10436 case KnownBooleanUse:
10437 ASSERT(!m_interpreter.needsTypeCheck(edge));
10438 break;
10439 case Int32Use:
10440 speculateInt32(edge);
10441 break;
10442 case NumberUse:
10443 speculateNumber(edge);
10444 break;
10445 case RealNumberUse:
10446 speculateRealNumber(edge);
10447 break;
10448 case DoubleRepRealUse:
10449 speculateDoubleRepReal(edge);
10450 break;
10451#if USE(JSVALUE64)
10452 case AnyIntUse:
10453 speculateAnyInt(edge);
10454 break;
10455 case DoubleRepAnyIntUse:
10456 speculateDoubleRepAnyInt(edge);
10457 break;
10458#endif
10459 case BooleanUse:
10460 speculateBoolean(edge);
10461 break;
10462 case CellUse:
10463 speculateCell(edge);
10464 break;
10465 case CellOrOtherUse:
10466 speculateCellOrOther(edge);
10467 break;
10468 case ObjectUse:
10469 speculateObject(edge);
10470 break;
10471 case FunctionUse:
10472 speculateFunction(edge);
10473 break;
10474 case ArrayUse:
10475 speculateArray(edge);
10476 break;
10477 case FinalObjectUse:
10478 speculateFinalObject(edge);
10479 break;
10480 case RegExpObjectUse:
10481 speculateRegExpObject(edge);
10482 break;
10483 case ProxyObjectUse:
10484 speculateProxyObject(edge);
10485 break;
10486 case DerivedArrayUse:
10487 speculateDerivedArray(edge);
10488 break;
10489 case MapObjectUse:
10490 speculateMapObject(edge);
10491 break;
10492 case SetObjectUse:
10493 speculateSetObject(edge);
10494 break;
10495 case WeakMapObjectUse:
10496 speculateWeakMapObject(edge);
10497 break;
10498 case WeakSetObjectUse:
10499 speculateWeakSetObject(edge);
10500 break;
10501 case DataViewObjectUse:
10502 speculateDataViewObject(edge);
10503 break;
10504 case ObjectOrOtherUse:
10505 speculateObjectOrOther(edge);
10506 break;
10507 case StringIdentUse:
10508 speculateStringIdent(edge);
10509 break;
10510 case StringUse:
10511 speculateString(edge);
10512 break;
10513 case StringOrOtherUse:
10514 speculateStringOrOther(edge);
10515 break;
10516 case SymbolUse:
10517 speculateSymbol(edge);
10518 break;
10519 case BigIntUse:
10520 speculateBigInt(edge);
10521 break;
10522 case StringObjectUse:
10523 speculateStringObject(edge);
10524 break;
10525 case StringOrStringObjectUse:
10526 speculateStringOrStringObject(edge);
10527 break;
10528 case NotStringVarUse:
10529 speculateNotStringVar(edge);
10530 break;
10531 case NotSymbolUse:
10532 speculateNotSymbol(edge);
10533 break;
10534 case NotCellUse:
10535 speculateNotCell(edge);
10536 break;
10537 case OtherUse:
10538 speculateOther(edge);
10539 break;
10540 case MiscUse:
10541 speculateMisc(edge);
10542 break;
10543 default:
10544 RELEASE_ASSERT_NOT_REACHED();
10545 break;
10546 }
10547}
10548
10549void SpeculativeJIT::emitSwitchIntJump(
10550 SwitchData* data, GPRReg value, GPRReg scratch)
10551{
10552 SimpleJumpTable& table = m_jit.codeBlock()->switchJumpTable(data->switchTableIndex);
10553 table.ensureCTITable();
10554 m_jit.sub32(Imm32(table.min), value);
10555 addBranch(
10556 m_jit.branch32(JITCompiler::AboveOrEqual, value, Imm32(table.ctiOffsets.size())),
10557 data->fallThrough.block);
10558 m_jit.move(TrustedImmPtr(table.ctiOffsets.begin()), scratch);
10559 m_jit.loadPtr(JITCompiler::BaseIndex(scratch, value, JITCompiler::timesPtr()), scratch);
10560
10561 m_jit.jump(scratch, JSSwitchPtrTag);
10562 data->didUseJumpTable = true;
10563}
10564
10565void SpeculativeJIT::emitSwitchImm(Node* node, SwitchData* data)
10566{
10567 switch (node->child1().useKind()) {
10568 case Int32Use: {
10569 SpeculateInt32Operand value(this, node->child1());
10570 GPRTemporary temp(this);
10571 emitSwitchIntJump(data, value.gpr(), temp.gpr());
10572 noResult(node);
10573 break;
10574 }
10575
10576 case UntypedUse: {
10577 JSValueOperand value(this, node->child1());
10578 GPRTemporary temp(this);
10579 JSValueRegs valueRegs = value.jsValueRegs();
10580 GPRReg scratch = temp.gpr();
10581
10582 value.use();
10583
10584 auto notInt32 = m_jit.branchIfNotInt32(valueRegs);
10585 emitSwitchIntJump(data, valueRegs.payloadGPR(), scratch);
10586 notInt32.link(&m_jit);
10587 addBranch(m_jit.branchIfNotNumber(valueRegs, scratch), data->fallThrough.block);
10588 silentSpillAllRegisters(scratch);
10589 callOperation(operationFindSwitchImmTargetForDouble, scratch, valueRegs, data->switchTableIndex);
10590 silentFillAllRegisters();
10591
10592 m_jit.jump(scratch, JSSwitchPtrTag);
10593 noResult(node, UseChildrenCalledExplicitly);
10594 break;
10595 }
10596
10597 default:
10598 RELEASE_ASSERT_NOT_REACHED();
10599 break;
10600 }
10601}
10602
10603void SpeculativeJIT::emitSwitchCharStringJump(
10604 SwitchData* data, GPRReg value, GPRReg scratch)
10605{
10606 m_jit.loadPtr(MacroAssembler::Address(value, JSString::offsetOfValue()), scratch);
10607 auto isRope = m_jit.branchIfRopeStringImpl(scratch);
10608
10609 addBranch(
10610 m_jit.branch32(
10611 MacroAssembler::NotEqual,
10612 MacroAssembler::Address(scratch, StringImpl::lengthMemoryOffset()),
10613 TrustedImm32(1)),
10614 data->fallThrough.block);
10615
10616 addSlowPathGenerator(slowPathCall(isRope, this, operationResolveRope, scratch, value));
10617
10618 m_jit.loadPtr(MacroAssembler::Address(scratch, StringImpl::dataOffset()), value);
10619
10620 JITCompiler::Jump is8Bit = m_jit.branchTest32(
10621 MacroAssembler::NonZero,
10622 MacroAssembler::Address(scratch, StringImpl::flagsOffset()),
10623 TrustedImm32(StringImpl::flagIs8Bit()));
10624
10625 m_jit.load16(MacroAssembler::Address(value), scratch);
10626
10627 JITCompiler::Jump ready = m_jit.jump();
10628
10629 is8Bit.link(&m_jit);
10630 m_jit.load8(MacroAssembler::Address(value), scratch);
10631
10632 ready.link(&m_jit);
10633 emitSwitchIntJump(data, scratch, value);
10634}
10635
10636void SpeculativeJIT::emitSwitchChar(Node* node, SwitchData* data)
10637{
10638 switch (node->child1().useKind()) {
10639 case StringUse: {
10640 SpeculateCellOperand op1(this, node->child1());
10641 GPRTemporary temp(this);
10642
10643 GPRReg op1GPR = op1.gpr();
10644 GPRReg tempGPR = temp.gpr();
10645
10646 op1.use();
10647
10648 speculateString(node->child1(), op1GPR);
10649 emitSwitchCharStringJump(data, op1GPR, tempGPR);
10650 noResult(node, UseChildrenCalledExplicitly);
10651 break;
10652 }
10653
10654 case UntypedUse: {
10655 JSValueOperand op1(this, node->child1());
10656 GPRTemporary temp(this);
10657
10658 JSValueRegs op1Regs = op1.jsValueRegs();
10659 GPRReg tempGPR = temp.gpr();
10660
10661 op1.use();
10662
10663 addBranch(m_jit.branchIfNotCell(op1Regs), data->fallThrough.block);
10664
10665 addBranch(m_jit.branchIfNotString(op1Regs.payloadGPR()), data->fallThrough.block);
10666
10667 emitSwitchCharStringJump(data, op1Regs.payloadGPR(), tempGPR);
10668 noResult(node, UseChildrenCalledExplicitly);
10669 break;
10670 }
10671
10672 default:
10673 RELEASE_ASSERT_NOT_REACHED();
10674 break;
10675 }
10676}
10677
10678namespace {
10679
10680struct CharacterCase {
10681 bool operator<(const CharacterCase& other) const
10682 {
10683 return character < other.character;
10684 }
10685
10686 LChar character;
10687 unsigned begin;
10688 unsigned end;
10689};
10690
10691} // anonymous namespace
10692
10693void SpeculativeJIT::emitBinarySwitchStringRecurse(
10694 SwitchData* data, const Vector<SpeculativeJIT::StringSwitchCase>& cases,
10695 unsigned numChecked, unsigned begin, unsigned end, GPRReg buffer, GPRReg length,
10696 GPRReg temp, unsigned alreadyCheckedLength, bool checkedExactLength)
10697{
10698 static const bool verbose = false;
10699
10700 if (verbose) {
10701 dataLog("We're down to the following cases, alreadyCheckedLength = ", alreadyCheckedLength, ":\n");
10702 for (unsigned i = begin; i < end; ++i) {
10703 dataLog(" ", cases[i].string, "\n");
10704 }
10705 }
10706
10707 if (begin == end) {
10708 jump(data->fallThrough.block, ForceJump);
10709 return;
10710 }
10711
10712 unsigned minLength = cases[begin].string->length();
10713 unsigned commonChars = minLength;
10714 bool allLengthsEqual = true;
10715 for (unsigned i = begin + 1; i < end; ++i) {
10716 unsigned myCommonChars = numChecked;
10717 for (unsigned j = numChecked;
10718 j < std::min(cases[begin].string->length(), cases[i].string->length());
10719 ++j) {
10720 if (cases[begin].string->at(j) != cases[i].string->at(j)) {
10721 if (verbose)
10722 dataLog("string(", cases[i].string, ")[", j, "] != string(", cases[begin].string, ")[", j, "]\n");
10723 break;
10724 }
10725 myCommonChars++;
10726 }
10727 commonChars = std::min(commonChars, myCommonChars);
10728 if (minLength != cases[i].string->length())
10729 allLengthsEqual = false;
10730 minLength = std::min(minLength, cases[i].string->length());
10731 }
10732
10733 if (checkedExactLength) {
10734 RELEASE_ASSERT(alreadyCheckedLength == minLength);
10735 RELEASE_ASSERT(allLengthsEqual);
10736 }
10737
10738 RELEASE_ASSERT(minLength >= commonChars);
10739
10740 if (verbose)
10741 dataLog("length = ", minLength, ", commonChars = ", commonChars, ", allLengthsEqual = ", allLengthsEqual, "\n");
10742
10743 if (!allLengthsEqual && alreadyCheckedLength < minLength)
10744 branch32(MacroAssembler::Below, length, Imm32(minLength), data->fallThrough.block);
10745 if (allLengthsEqual && (alreadyCheckedLength < minLength || !checkedExactLength))
10746 branch32(MacroAssembler::NotEqual, length, Imm32(minLength), data->fallThrough.block);
10747
10748 for (unsigned i = numChecked; i < commonChars; ++i) {
10749 branch8(
10750 MacroAssembler::NotEqual, MacroAssembler::Address(buffer, i),
10751 TrustedImm32(cases[begin].string->at(i)), data->fallThrough.block);
10752 }
10753
10754 if (minLength == commonChars) {
10755 // This is the case where one of the cases is a prefix of all of the other cases.
10756 // We've already checked that the input string is a prefix of all of the cases,
10757 // so we just check length to jump to that case.
10758
10759 if (!ASSERT_DISABLED) {
10760 ASSERT(cases[begin].string->length() == commonChars);
10761 for (unsigned i = begin + 1; i < end; ++i)
10762 ASSERT(cases[i].string->length() > commonChars);
10763 }
10764
10765 if (allLengthsEqual) {
10766 RELEASE_ASSERT(end == begin + 1);
10767 jump(cases[begin].target, ForceJump);
10768 return;
10769 }
10770
10771 branch32(MacroAssembler::Equal, length, Imm32(commonChars), cases[begin].target);
10772
10773 // We've checked if the length is >= minLength, and then we checked if the
10774 // length is == commonChars. We get to this point if it is >= minLength but not
10775 // == commonChars. Hence we know that it now must be > minLength, i.e., that
10776 // it's >= minLength + 1.
10777 emitBinarySwitchStringRecurse(
10778 data, cases, commonChars, begin + 1, end, buffer, length, temp, minLength + 1, false);
10779 return;
10780 }
10781
10782 // At this point we know that the string is longer than commonChars, and we've only
10783 // verified commonChars. Use a binary switch on the next unchecked character, i.e.
10784 // string[commonChars].
10785
10786 RELEASE_ASSERT(end >= begin + 2);
10787
10788 m_jit.load8(MacroAssembler::Address(buffer, commonChars), temp);
10789
10790 Vector<CharacterCase> characterCases;
10791 CharacterCase currentCase;
10792 currentCase.character = cases[begin].string->at(commonChars);
10793 currentCase.begin = begin;
10794 currentCase.end = begin + 1;
10795 for (unsigned i = begin + 1; i < end; ++i) {
10796 if (cases[i].string->at(commonChars) != currentCase.character) {
10797 if (verbose)
10798 dataLog("string(", cases[i].string, ")[", commonChars, "] != string(", cases[begin].string, ")[", commonChars, "]\n");
10799 currentCase.end = i;
10800 characterCases.append(currentCase);
10801 currentCase.character = cases[i].string->at(commonChars);
10802 currentCase.begin = i;
10803 currentCase.end = i + 1;
10804 } else
10805 currentCase.end = i + 1;
10806 }
10807 characterCases.append(currentCase);
10808
10809 Vector<int64_t> characterCaseValues;
10810 for (unsigned i = 0; i < characterCases.size(); ++i)
10811 characterCaseValues.append(characterCases[i].character);
10812
10813 BinarySwitch binarySwitch(temp, characterCaseValues, BinarySwitch::Int32);
10814 while (binarySwitch.advance(m_jit)) {
10815 const CharacterCase& myCase = characterCases[binarySwitch.caseIndex()];
10816 emitBinarySwitchStringRecurse(
10817 data, cases, commonChars + 1, myCase.begin, myCase.end, buffer, length,
10818 temp, minLength, allLengthsEqual);
10819 }
10820
10821 addBranch(binarySwitch.fallThrough(), data->fallThrough.block);
10822}
10823
10824void SpeculativeJIT::emitSwitchStringOnString(SwitchData* data, GPRReg string)
10825{
10826 data->didUseJumpTable = true;
10827
10828 bool canDoBinarySwitch = true;
10829 unsigned totalLength = 0;
10830
10831 for (unsigned i = data->cases.size(); i--;) {
10832 StringImpl* string = data->cases[i].value.stringImpl();
10833 if (!string->is8Bit()) {
10834 canDoBinarySwitch = false;
10835 break;
10836 }
10837 if (string->length() > Options::maximumBinaryStringSwitchCaseLength()) {
10838 canDoBinarySwitch = false;
10839 break;
10840 }
10841 totalLength += string->length();
10842 }
10843
10844 if (!canDoBinarySwitch || totalLength > Options::maximumBinaryStringSwitchTotalLength()) {
10845 flushRegisters();
10846 callOperation(
10847 operationSwitchString, string, static_cast<size_t>(data->switchTableIndex), string);
10848 m_jit.exceptionCheck();
10849 m_jit.jump(string, JSSwitchPtrTag);
10850 return;
10851 }
10852
10853 GPRTemporary length(this);
10854 GPRTemporary temp(this);
10855
10856 GPRReg lengthGPR = length.gpr();
10857 GPRReg tempGPR = temp.gpr();
10858
10859 MacroAssembler::JumpList slowCases;
10860 m_jit.loadPtr(MacroAssembler::Address(string, JSString::offsetOfValue()), tempGPR);
10861 slowCases.append(m_jit.branchIfRopeStringImpl(tempGPR));
10862 m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), lengthGPR);
10863
10864 slowCases.append(m_jit.branchTest32(
10865 MacroAssembler::Zero,
10866 MacroAssembler::Address(tempGPR, StringImpl::flagsOffset()),
10867 TrustedImm32(StringImpl::flagIs8Bit())));
10868
10869 m_jit.loadPtr(MacroAssembler::Address(tempGPR, StringImpl::dataOffset()), string);
10870
10871 Vector<StringSwitchCase> cases;
10872 for (unsigned i = 0; i < data->cases.size(); ++i) {
10873 cases.append(
10874 StringSwitchCase(data->cases[i].value.stringImpl(), data->cases[i].target.block));
10875 }
10876
10877 std::sort(cases.begin(), cases.end());
10878
10879 emitBinarySwitchStringRecurse(
10880 data, cases, 0, 0, cases.size(), string, lengthGPR, tempGPR, 0, false);
10881
10882 slowCases.link(&m_jit);
10883 silentSpillAllRegisters(string);
10884 callOperation(operationSwitchString, string, static_cast<size_t>(data->switchTableIndex), string);
10885 silentFillAllRegisters();
10886 m_jit.exceptionCheck();
10887 m_jit.jump(string, JSSwitchPtrTag);
10888}
10889
10890void SpeculativeJIT::emitSwitchString(Node* node, SwitchData* data)
10891{
10892 switch (node->child1().useKind()) {
10893 case StringIdentUse: {
10894 SpeculateCellOperand op1(this, node->child1());
10895 GPRTemporary temp(this);
10896
10897 GPRReg op1GPR = op1.gpr();
10898 GPRReg tempGPR = temp.gpr();
10899
10900 speculateString(node->child1(), op1GPR);
10901 speculateStringIdentAndLoadStorage(node->child1(), op1GPR, tempGPR);
10902
10903 Vector<int64_t> identifierCaseValues;
10904 for (unsigned i = 0; i < data->cases.size(); ++i) {
10905 identifierCaseValues.append(
10906 static_cast<int64_t>(bitwise_cast<intptr_t>(data->cases[i].value.stringImpl())));
10907 }
10908
10909 BinarySwitch binarySwitch(tempGPR, identifierCaseValues, BinarySwitch::IntPtr);
10910 while (binarySwitch.advance(m_jit))
10911 jump(data->cases[binarySwitch.caseIndex()].target.block, ForceJump);
10912 addBranch(binarySwitch.fallThrough(), data->fallThrough.block);
10913
10914 noResult(node);
10915 break;
10916 }
10917
10918 case StringUse: {
10919 SpeculateCellOperand op1(this, node->child1());
10920
10921 GPRReg op1GPR = op1.gpr();
10922
10923 op1.use();
10924
10925 speculateString(node->child1(), op1GPR);
10926 emitSwitchStringOnString(data, op1GPR);
10927 noResult(node, UseChildrenCalledExplicitly);
10928 break;
10929 }
10930
10931 case UntypedUse: {
10932 JSValueOperand op1(this, node->child1());
10933
10934 JSValueRegs op1Regs = op1.jsValueRegs();
10935
10936 op1.use();
10937
10938 addBranch(m_jit.branchIfNotCell(op1Regs), data->fallThrough.block);
10939
10940 addBranch(m_jit.branchIfNotString(op1Regs.payloadGPR()), data->fallThrough.block);
10941
10942 emitSwitchStringOnString(data, op1Regs.payloadGPR());
10943 noResult(node, UseChildrenCalledExplicitly);
10944 break;
10945 }
10946
10947 default:
10948 RELEASE_ASSERT_NOT_REACHED();
10949 break;
10950 }
10951}
10952
10953void SpeculativeJIT::emitSwitch(Node* node)
10954{
10955 SwitchData* data = node->switchData();
10956 switch (data->kind) {
10957 case SwitchImm: {
10958 emitSwitchImm(node, data);
10959 return;
10960 }
10961 case SwitchChar: {
10962 emitSwitchChar(node, data);
10963 return;
10964 }
10965 case SwitchString: {
10966 emitSwitchString(node, data);
10967 return;
10968 }
10969 case SwitchCell: {
10970 DFG_CRASH(m_jit.graph(), node, "Bad switch kind");
10971 return;
10972 } }
10973 RELEASE_ASSERT_NOT_REACHED();
10974}
10975
10976void SpeculativeJIT::addBranch(const MacroAssembler::JumpList& jump, BasicBlock* destination)
10977{
10978 for (unsigned i = jump.jumps().size(); i--;)
10979 addBranch(jump.jumps()[i], destination);
10980}
10981
10982void SpeculativeJIT::linkBranches()
10983{
10984 for (auto& branch : m_branches)
10985 branch.jump.linkTo(m_jit.blockHeads()[branch.destination->index], &m_jit);
10986}
10987
10988void SpeculativeJIT::compileStoreBarrier(Node* node)
10989{
10990 ASSERT(node->op() == StoreBarrier || node->op() == FencedStoreBarrier);
10991
10992 bool isFenced = node->op() == FencedStoreBarrier;
10993
10994 SpeculateCellOperand base(this, node->child1());
10995 GPRTemporary scratch1(this);
10996
10997 GPRReg baseGPR = base.gpr();
10998 GPRReg scratch1GPR = scratch1.gpr();
10999
11000 JITCompiler::JumpList ok;
11001
11002 if (isFenced) {
11003 ok.append(m_jit.barrierBranch(*m_jit.vm(), baseGPR, scratch1GPR));
11004
11005 JITCompiler::Jump noFence = m_jit.jumpIfMutatorFenceNotNeeded(*m_jit.vm());
11006 m_jit.memoryFence();
11007 ok.append(m_jit.barrierBranchWithoutFence(baseGPR));
11008 noFence.link(&m_jit);
11009 } else
11010 ok.append(m_jit.barrierBranchWithoutFence(baseGPR));
11011
11012 silentSpillAllRegisters(InvalidGPRReg);
11013 callOperation(operationWriteBarrierSlowPath, baseGPR);
11014 silentFillAllRegisters();
11015
11016 ok.link(&m_jit);
11017
11018 noResult(node);
11019}
11020
11021void SpeculativeJIT::compilePutAccessorById(Node* node)
11022{
11023 SpeculateCellOperand base(this, node->child1());
11024 SpeculateCellOperand accessor(this, node->child2());
11025
11026 GPRReg baseGPR = base.gpr();
11027 GPRReg accessorGPR = accessor.gpr();
11028
11029 flushRegisters();
11030 callOperation(node->op() == PutGetterById ? operationPutGetterById : operationPutSetterById, NoResult, baseGPR, identifierUID(node->identifierNumber()), node->accessorAttributes(), accessorGPR);
11031 m_jit.exceptionCheck();
11032
11033 noResult(node);
11034}
11035
11036void SpeculativeJIT::compilePutGetterSetterById(Node* node)
11037{
11038 SpeculateCellOperand base(this, node->child1());
11039 JSValueOperand getter(this, node->child2());
11040 JSValueOperand setter(this, node->child3());
11041
11042#if USE(JSVALUE64)
11043 GPRReg baseGPR = base.gpr();
11044 GPRReg getterGPR = getter.gpr();
11045 GPRReg setterGPR = setter.gpr();
11046
11047 flushRegisters();
11048 callOperation(operationPutGetterSetter, NoResult, baseGPR, identifierUID(node->identifierNumber()), node->accessorAttributes(), getterGPR, setterGPR);
11049#else
11050 // These JSValues may be JSUndefined OR JSFunction*.
11051 // At that time,
11052 // 1. If the JSValue is JSUndefined, its payload becomes nullptr.
11053 // 2. If the JSValue is JSFunction*, its payload becomes JSFunction*.
11054 // So extract payload and pass it to operationPutGetterSetter. This hack is used as the same way in baseline JIT.
11055 GPRReg baseGPR = base.gpr();
11056 JSValueRegs getterRegs = getter.jsValueRegs();
11057 JSValueRegs setterRegs = setter.jsValueRegs();
11058
11059 flushRegisters();
11060 callOperation(operationPutGetterSetter, NoResult, baseGPR, identifierUID(node->identifierNumber()), node->accessorAttributes(), getterRegs.payloadGPR(), setterRegs.payloadGPR());
11061#endif
11062 m_jit.exceptionCheck();
11063
11064 noResult(node);
11065}
11066
11067void SpeculativeJIT::compileResolveScope(Node* node)
11068{
11069 SpeculateCellOperand scope(this, node->child1());
11070 GPRReg scopeGPR = scope.gpr();
11071 GPRFlushedCallResult result(this);
11072 GPRReg resultGPR = result.gpr();
11073 flushRegisters();
11074 callOperation(operationResolveScope, resultGPR, scopeGPR, identifierUID(node->identifierNumber()));
11075 m_jit.exceptionCheck();
11076 cellResult(resultGPR, node);
11077}
11078
11079void SpeculativeJIT::compileResolveScopeForHoistingFuncDeclInEval(Node* node)
11080{
11081 SpeculateCellOperand scope(this, node->child1());
11082 GPRReg scopeGPR = scope.gpr();
11083 flushRegisters();
11084 JSValueRegsFlushedCallResult result(this);
11085 JSValueRegs resultRegs = result.regs();
11086 callOperation(operationResolveScopeForHoistingFuncDeclInEval, resultRegs, scopeGPR, identifierUID(node->identifierNumber()));
11087 m_jit.exceptionCheck();
11088 jsValueResult(resultRegs, node);
11089}
11090
11091void SpeculativeJIT::compileGetGlobalVariable(Node* node)
11092{
11093 JSValueRegsTemporary result(this);
11094 JSValueRegs resultRegs = result.regs();
11095 m_jit.loadValue(node->variablePointer(), resultRegs);
11096 jsValueResult(resultRegs, node);
11097}
11098
11099void SpeculativeJIT::compilePutGlobalVariable(Node* node)
11100{
11101 JSValueOperand value(this, node->child2());
11102 JSValueRegs valueRegs = value.jsValueRegs();
11103 m_jit.storeValue(valueRegs, node->variablePointer());
11104 noResult(node);
11105}
11106
11107void SpeculativeJIT::compileGetDynamicVar(Node* node)
11108{
11109 SpeculateCellOperand scope(this, node->child1());
11110 GPRReg scopeGPR = scope.gpr();
11111 flushRegisters();
11112 JSValueRegsFlushedCallResult result(this);
11113 JSValueRegs resultRegs = result.regs();
11114 callOperation(operationGetDynamicVar, resultRegs, scopeGPR, identifierUID(node->identifierNumber()), node->getPutInfo());
11115 m_jit.exceptionCheck();
11116 jsValueResult(resultRegs, node);
11117}
11118
11119void SpeculativeJIT::compilePutDynamicVar(Node* node)
11120{
11121 SpeculateCellOperand scope(this, node->child1());
11122 JSValueOperand value(this, node->child2());
11123
11124 GPRReg scopeGPR = scope.gpr();
11125 JSValueRegs valueRegs = value.jsValueRegs();
11126
11127 flushRegisters();
11128 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutDynamicVarStrict : operationPutDynamicVarNonStrict, NoResult, scopeGPR, valueRegs, identifierUID(node->identifierNumber()), node->getPutInfo());
11129 m_jit.exceptionCheck();
11130 noResult(node);
11131}
11132
11133void SpeculativeJIT::compileGetClosureVar(Node* node)
11134{
11135 SpeculateCellOperand base(this, node->child1());
11136 JSValueRegsTemporary result(this);
11137
11138 GPRReg baseGPR = base.gpr();
11139 JSValueRegs resultRegs = result.regs();
11140
11141 m_jit.loadValue(JITCompiler::Address(baseGPR, JSLexicalEnvironment::offsetOfVariable(node->scopeOffset())), resultRegs);
11142 jsValueResult(resultRegs, node);
11143}
11144
11145void SpeculativeJIT::compilePutClosureVar(Node* node)
11146{
11147 SpeculateCellOperand base(this, node->child1());
11148 JSValueOperand value(this, node->child2());
11149
11150 GPRReg baseGPR = base.gpr();
11151 JSValueRegs valueRegs = value.jsValueRegs();
11152
11153 m_jit.storeValue(valueRegs, JITCompiler::Address(baseGPR, JSLexicalEnvironment::offsetOfVariable(node->scopeOffset())));
11154 noResult(node);
11155}
11156
11157void SpeculativeJIT::compilePutAccessorByVal(Node* node)
11158{
11159 SpeculateCellOperand base(this, node->child1());
11160 JSValueOperand subscript(this, node->child2());
11161 SpeculateCellOperand accessor(this, node->child3());
11162
11163 auto operation = node->op() == PutGetterByVal ? operationPutGetterByVal : operationPutSetterByVal;
11164
11165 GPRReg baseGPR = base.gpr();
11166 JSValueRegs subscriptRegs = subscript.jsValueRegs();
11167 GPRReg accessorGPR = accessor.gpr();
11168
11169 flushRegisters();
11170 callOperation(operation, NoResult, baseGPR, subscriptRegs, node->accessorAttributes(), accessorGPR);
11171 m_jit.exceptionCheck();
11172
11173 noResult(node);
11174}
11175
11176void SpeculativeJIT::compileGetRegExpObjectLastIndex(Node* node)
11177{
11178 SpeculateCellOperand regExp(this, node->child1());
11179 JSValueRegsTemporary result(this);
11180 GPRReg regExpGPR = regExp.gpr();
11181 JSValueRegs resultRegs = result.regs();
11182 speculateRegExpObject(node->child1(), regExpGPR);
11183 m_jit.loadValue(JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndex()), resultRegs);
11184 jsValueResult(resultRegs, node);
11185}
11186
11187void SpeculativeJIT::compileSetRegExpObjectLastIndex(Node* node)
11188{
11189 SpeculateCellOperand regExp(this, node->child1());
11190 JSValueOperand value(this, node->child2());
11191 GPRReg regExpGPR = regExp.gpr();
11192 JSValueRegs valueRegs = value.jsValueRegs();
11193
11194 if (!node->ignoreLastIndexIsWritable()) {
11195 speculateRegExpObject(node->child1(), regExpGPR);
11196 speculationCheck(
11197 ExoticObjectMode, JSValueRegs(), nullptr,
11198 m_jit.branchTestPtr(
11199 JITCompiler::NonZero,
11200 JITCompiler::Address(regExpGPR, RegExpObject::offsetOfRegExpAndLastIndexIsNotWritableFlag()),
11201 JITCompiler::TrustedImm32(RegExpObject::lastIndexIsNotWritableFlag)));
11202 }
11203
11204 m_jit.storeValue(valueRegs, JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndex()));
11205 noResult(node);
11206}
11207
11208void SpeculativeJIT::compileRegExpExec(Node* node)
11209{
11210 bool sample = false;
11211 if (sample)
11212 m_jit.incrementSuperSamplerCount();
11213
11214 SpeculateCellOperand globalObject(this, node->child1());
11215 GPRReg globalObjectGPR = globalObject.gpr();
11216
11217 if (node->child2().useKind() == RegExpObjectUse) {
11218 if (node->child3().useKind() == StringUse) {
11219 SpeculateCellOperand base(this, node->child2());
11220 SpeculateCellOperand argument(this, node->child3());
11221 GPRReg baseGPR = base.gpr();
11222 GPRReg argumentGPR = argument.gpr();
11223 speculateRegExpObject(node->child2(), baseGPR);
11224 speculateString(node->child3(), argumentGPR);
11225
11226 flushRegisters();
11227 JSValueRegsFlushedCallResult result(this);
11228 JSValueRegs resultRegs = result.regs();
11229 callOperation(operationRegExpExecString, resultRegs, globalObjectGPR, baseGPR, argumentGPR);
11230 m_jit.exceptionCheck();
11231
11232 jsValueResult(resultRegs, node);
11233
11234 if (sample)
11235 m_jit.decrementSuperSamplerCount();
11236 return;
11237 }
11238
11239 SpeculateCellOperand base(this, node->child2());
11240 JSValueOperand argument(this, node->child3());
11241 GPRReg baseGPR = base.gpr();
11242 JSValueRegs argumentRegs = argument.jsValueRegs();
11243 speculateRegExpObject(node->child2(), baseGPR);
11244
11245 flushRegisters();
11246 JSValueRegsFlushedCallResult result(this);
11247 JSValueRegs resultRegs = result.regs();
11248 callOperation(operationRegExpExec, resultRegs, globalObjectGPR, baseGPR, argumentRegs);
11249 m_jit.exceptionCheck();
11250
11251 jsValueResult(resultRegs, node);
11252
11253 if (sample)
11254 m_jit.decrementSuperSamplerCount();
11255 return;
11256 }
11257
11258 JSValueOperand base(this, node->child2());
11259 JSValueOperand argument(this, node->child3());
11260 JSValueRegs baseRegs = base.jsValueRegs();
11261 JSValueRegs argumentRegs = argument.jsValueRegs();
11262
11263 flushRegisters();
11264 JSValueRegsFlushedCallResult result(this);
11265 JSValueRegs resultRegs = result.regs();
11266 callOperation(operationRegExpExecGeneric, resultRegs, globalObjectGPR, baseRegs, argumentRegs);
11267 m_jit.exceptionCheck();
11268
11269 jsValueResult(resultRegs, node);
11270
11271 if (sample)
11272 m_jit.decrementSuperSamplerCount();
11273}
11274
11275void SpeculativeJIT::compileRegExpTest(Node* node)
11276{
11277 SpeculateCellOperand globalObject(this, node->child1());
11278 GPRReg globalObjectGPR = globalObject.gpr();
11279
11280 if (node->child2().useKind() == RegExpObjectUse) {
11281 if (node->child3().useKind() == StringUse) {
11282 SpeculateCellOperand base(this, node->child2());
11283 SpeculateCellOperand argument(this, node->child3());
11284 GPRReg baseGPR = base.gpr();
11285 GPRReg argumentGPR = argument.gpr();
11286 speculateRegExpObject(node->child2(), baseGPR);
11287 speculateString(node->child3(), argumentGPR);
11288
11289 flushRegisters();
11290 GPRFlushedCallResult result(this);
11291 callOperation(operationRegExpTestString, result.gpr(), globalObjectGPR, baseGPR, argumentGPR);
11292 m_jit.exceptionCheck();
11293
11294 unblessedBooleanResult(result.gpr(), node);
11295 return;
11296 }
11297
11298 SpeculateCellOperand base(this, node->child2());
11299 JSValueOperand argument(this, node->child3());
11300 GPRReg baseGPR = base.gpr();
11301 JSValueRegs argumentRegs = argument.jsValueRegs();
11302 speculateRegExpObject(node->child2(), baseGPR);
11303
11304 flushRegisters();
11305 GPRFlushedCallResult result(this);
11306 callOperation(operationRegExpTest, result.gpr(), globalObjectGPR, baseGPR, argumentRegs);
11307 m_jit.exceptionCheck();
11308
11309 unblessedBooleanResult(result.gpr(), node);
11310 return;
11311 }
11312
11313 JSValueOperand base(this, node->child2());
11314 JSValueOperand argument(this, node->child3());
11315 JSValueRegs baseRegs = base.jsValueRegs();
11316 JSValueRegs argumentRegs = argument.jsValueRegs();
11317
11318 flushRegisters();
11319 GPRFlushedCallResult result(this);
11320 callOperation(operationRegExpTestGeneric, result.gpr(), globalObjectGPR, baseRegs, argumentRegs);
11321 m_jit.exceptionCheck();
11322
11323 unblessedBooleanResult(result.gpr(), node);
11324}
11325
11326void SpeculativeJIT::compileStringReplace(Node* node)
11327{
11328 ASSERT(node->op() == StringReplace || node->op() == StringReplaceRegExp);
11329 bool sample = false;
11330 if (sample)
11331 m_jit.incrementSuperSamplerCount();
11332
11333 if (node->child1().useKind() == StringUse
11334 && node->child2().useKind() == RegExpObjectUse
11335 && node->child3().useKind() == StringUse) {
11336 if (JSString* replace = node->child3()->dynamicCastConstant<JSString*>(*m_jit.vm())) {
11337 if (!replace->length()) {
11338 SpeculateCellOperand string(this, node->child1());
11339 SpeculateCellOperand regExp(this, node->child2());
11340 GPRReg stringGPR = string.gpr();
11341 GPRReg regExpGPR = regExp.gpr();
11342 speculateString(node->child1(), stringGPR);
11343 speculateRegExpObject(node->child2(), regExpGPR);
11344
11345 flushRegisters();
11346 GPRFlushedCallResult result(this);
11347 callOperation(operationStringProtoFuncReplaceRegExpEmptyStr, result.gpr(), stringGPR, regExpGPR);
11348 m_jit.exceptionCheck();
11349 cellResult(result.gpr(), node);
11350 if (sample)
11351 m_jit.decrementSuperSamplerCount();
11352 return;
11353 }
11354 }
11355
11356 SpeculateCellOperand string(this, node->child1());
11357 SpeculateCellOperand regExp(this, node->child2());
11358 SpeculateCellOperand replace(this, node->child3());
11359 GPRReg stringGPR = string.gpr();
11360 GPRReg regExpGPR = regExp.gpr();
11361 GPRReg replaceGPR = replace.gpr();
11362 speculateString(node->child1(), stringGPR);
11363 speculateRegExpObject(node->child2(), regExpGPR);
11364 speculateString(node->child3(), replaceGPR);
11365
11366 flushRegisters();
11367 GPRFlushedCallResult result(this);
11368 callOperation(operationStringProtoFuncReplaceRegExpString, result.gpr(), stringGPR, regExpGPR, replaceGPR);
11369 m_jit.exceptionCheck();
11370 cellResult(result.gpr(), node);
11371 if (sample)
11372 m_jit.decrementSuperSamplerCount();
11373 return;
11374 }
11375
11376 // If we fixed up the edge of child2, we inserted a Check(@child2, String).
11377 OperandSpeculationMode child2SpeculationMode = AutomaticOperandSpeculation;
11378 if (node->child2().useKind() == StringUse)
11379 child2SpeculationMode = ManualOperandSpeculation;
11380
11381 JSValueOperand string(this, node->child1());
11382 JSValueOperand search(this, node->child2(), child2SpeculationMode);
11383 JSValueOperand replace(this, node->child3());
11384 JSValueRegs stringRegs = string.jsValueRegs();
11385 JSValueRegs searchRegs = search.jsValueRegs();
11386 JSValueRegs replaceRegs = replace.jsValueRegs();
11387
11388 flushRegisters();
11389 GPRFlushedCallResult result(this);
11390 callOperation(operationStringProtoFuncReplaceGeneric, result.gpr(), stringRegs, searchRegs, replaceRegs);
11391 m_jit.exceptionCheck();
11392 cellResult(result.gpr(), node);
11393 if (sample)
11394 m_jit.decrementSuperSamplerCount();
11395}
11396
11397void SpeculativeJIT::compileRegExpExecNonGlobalOrSticky(Node* node)
11398{
11399 SpeculateCellOperand globalObject(this, node->child1());
11400 SpeculateCellOperand argument(this, node->child2());
11401 GPRReg globalObjectGPR = globalObject.gpr();
11402 GPRReg argumentGPR = argument.gpr();
11403
11404 speculateString(node->child2(), argumentGPR);
11405
11406 flushRegisters();
11407 JSValueRegsFlushedCallResult result(this);
11408 JSValueRegs resultRegs = result.regs();
11409 callOperation(
11410 operationRegExpExecNonGlobalOrSticky, resultRegs,
11411 globalObjectGPR, TrustedImmPtr(node->cellOperand()), argumentGPR);
11412 m_jit.exceptionCheck();
11413
11414 jsValueResult(resultRegs, node);
11415}
11416
11417void SpeculativeJIT::compileRegExpMatchFastGlobal(Node* node)
11418{
11419 SpeculateCellOperand globalObject(this, node->child1());
11420 SpeculateCellOperand argument(this, node->child2());
11421 GPRReg globalObjectGPR = globalObject.gpr();
11422 GPRReg argumentGPR = argument.gpr();
11423
11424 speculateString(node->child2(), argumentGPR);
11425
11426 flushRegisters();
11427 JSValueRegsFlushedCallResult result(this);
11428 JSValueRegs resultRegs = result.regs();
11429 callOperation(
11430 operationRegExpMatchFastGlobalString, resultRegs,
11431 globalObjectGPR, TrustedImmPtr(node->cellOperand()), argumentGPR);
11432 m_jit.exceptionCheck();
11433
11434 jsValueResult(resultRegs, node);
11435}
11436
11437void SpeculativeJIT::compileRegExpMatchFast(Node* node)
11438{
11439 SpeculateCellOperand globalObject(this, node->child1());
11440 SpeculateCellOperand base(this, node->child2());
11441 SpeculateCellOperand argument(this, node->child3());
11442 GPRReg globalObjectGPR = globalObject.gpr();
11443 GPRReg baseGPR = base.gpr();
11444 GPRReg argumentGPR = argument.gpr();
11445 speculateRegExpObject(node->child2(), baseGPR);
11446 speculateString(node->child3(), argumentGPR);
11447
11448 flushRegisters();
11449 JSValueRegsFlushedCallResult result(this);
11450 JSValueRegs resultRegs = result.regs();
11451 callOperation(
11452 operationRegExpMatchFastString, resultRegs,
11453 globalObjectGPR, baseGPR, argumentGPR);
11454 m_jit.exceptionCheck();
11455
11456 jsValueResult(resultRegs, node);
11457}
11458
11459void SpeculativeJIT::compileLazyJSConstant(Node* node)
11460{
11461 JSValueRegsTemporary result(this);
11462 JSValueRegs resultRegs = result.regs();
11463 node->lazyJSValue().emit(m_jit, resultRegs);
11464 jsValueResult(resultRegs, node);
11465}
11466
11467void SpeculativeJIT::compileMaterializeNewObject(Node* node)
11468{
11469 RegisteredStructure structure = node->structureSet().at(0);
11470 ASSERT(m_jit.graph().varArgChild(node, 0)->dynamicCastConstant<Structure*>(*m_jit.vm()) == structure.get());
11471
11472 ObjectMaterializationData& data = node->objectMaterializationData();
11473
11474 IndexingType indexingType = structure->indexingType();
11475 bool hasIndexingHeader = hasIndexedProperties(indexingType);
11476 int32_t publicLength = 0;
11477 int32_t vectorLength = 0;
11478
11479 if (hasIndexingHeader) {
11480 for (unsigned i = data.m_properties.size(); i--;) {
11481 Edge edge = m_jit.graph().varArgChild(node, 1 + i);
11482 switch (data.m_properties[i].kind()) {
11483 case PublicLengthPLoc:
11484 publicLength = edge->asInt32();
11485 break;
11486 case VectorLengthPLoc:
11487 vectorLength = edge->asInt32();
11488 break;
11489 default:
11490 break;
11491 }
11492 }
11493 }
11494
11495 GPRTemporary result(this);
11496 GPRTemporary storage(this);
11497 GPRReg resultGPR = result.gpr();
11498 GPRReg storageGPR = storage.gpr();
11499
11500 emitAllocateRawObject(resultGPR, structure, storageGPR, 0, vectorLength);
11501
11502 m_jit.store32(
11503 JITCompiler::TrustedImm32(publicLength),
11504 JITCompiler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
11505
11506 for (unsigned i = data.m_properties.size(); i--;) {
11507 Edge edge = m_jit.graph().varArgChild(node, 1 + i);
11508 PromotedLocationDescriptor descriptor = data.m_properties[i];
11509 switch (descriptor.kind()) {
11510 case IndexedPropertyPLoc: {
11511 JSValueOperand value(this, edge);
11512 m_jit.storeValue(
11513 value.jsValueRegs(),
11514 JITCompiler::Address(storageGPR, sizeof(EncodedJSValue) * descriptor.info()));
11515 break;
11516 }
11517
11518 case NamedPropertyPLoc: {
11519 StringImpl* uid = m_jit.graph().identifiers()[descriptor.info()];
11520 for (PropertyMapEntry entry : structure->getPropertiesConcurrently()) {
11521 if (uid != entry.key)
11522 continue;
11523
11524 JSValueOperand value(this, edge);
11525 GPRReg baseGPR = isInlineOffset(entry.offset) ? resultGPR : storageGPR;
11526 m_jit.storeValue(
11527 value.jsValueRegs(),
11528 JITCompiler::Address(baseGPR, offsetRelativeToBase(entry.offset)));
11529 }
11530 break;
11531 }
11532
11533 default:
11534 break;
11535 }
11536 }
11537
11538 cellResult(resultGPR, node);
11539}
11540
11541void SpeculativeJIT::compileRecordRegExpCachedResult(Node* node)
11542{
11543 Edge globalObjectEdge = m_jit.graph().varArgChild(node, 0);
11544 Edge regExpEdge = m_jit.graph().varArgChild(node, 1);
11545 Edge stringEdge = m_jit.graph().varArgChild(node, 2);
11546 Edge startEdge = m_jit.graph().varArgChild(node, 3);
11547 Edge endEdge = m_jit.graph().varArgChild(node, 4);
11548
11549 SpeculateCellOperand globalObject(this, globalObjectEdge);
11550 SpeculateCellOperand regExp(this, regExpEdge);
11551 SpeculateCellOperand string(this, stringEdge);
11552 SpeculateInt32Operand start(this, startEdge);
11553 SpeculateInt32Operand end(this, endEdge);
11554
11555 GPRReg globalObjectGPR = globalObject.gpr();
11556 GPRReg regExpGPR = regExp.gpr();
11557 GPRReg stringGPR = string.gpr();
11558 GPRReg startGPR = start.gpr();
11559 GPRReg endGPR = end.gpr();
11560
11561 ptrdiff_t offset = JSGlobalObject::regExpGlobalDataOffset() + RegExpGlobalData::offsetOfCachedResult();
11562
11563 m_jit.storePtr(
11564 regExpGPR,
11565 JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfLastRegExp()));
11566 m_jit.storePtr(
11567 stringGPR,
11568 JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfLastInput()));
11569 m_jit.store32(
11570 startGPR,
11571 JITCompiler::Address(
11572 globalObjectGPR,
11573 offset + RegExpCachedResult::offsetOfResult() + OBJECT_OFFSETOF(MatchResult, start)));
11574 m_jit.store32(
11575 endGPR,
11576 JITCompiler::Address(
11577 globalObjectGPR,
11578 offset + RegExpCachedResult::offsetOfResult() + OBJECT_OFFSETOF(MatchResult, end)));
11579 m_jit.store8(
11580 TrustedImm32(0),
11581 JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfReified()));
11582
11583 noResult(node);
11584}
11585
11586void SpeculativeJIT::compileDefineDataProperty(Node* node)
11587{
11588#if USE(JSVALUE64)
11589 static_assert(GPRInfo::numberOfRegisters >= 5, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
11590#else
11591 static_assert(GPRInfo::numberOfRegisters >= 6, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
11592#endif
11593
11594 SpeculateCellOperand base(this, m_jit.graph().varArgChild(node, 0));
11595 GPRReg baseGPR = base.gpr();
11596
11597 JSValueOperand value(this, m_jit.graph().varArgChild(node, 2));
11598 JSValueRegs valueRegs = value.jsValueRegs();
11599
11600 SpeculateInt32Operand attributes(this, m_jit.graph().varArgChild(node, 3));
11601 GPRReg attributesGPR = attributes.gpr();
11602
11603 Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
11604 switch (propertyEdge.useKind()) {
11605 case StringUse: {
11606 SpeculateCellOperand property(this, propertyEdge);
11607 GPRReg propertyGPR = property.gpr();
11608 speculateString(propertyEdge, propertyGPR);
11609
11610 useChildren(node);
11611
11612 flushRegisters();
11613 callOperation(operationDefineDataPropertyString, NoResult, baseGPR, propertyGPR, valueRegs, attributesGPR);
11614 m_jit.exceptionCheck();
11615 break;
11616 }
11617 case StringIdentUse: {
11618 SpeculateCellOperand property(this, propertyEdge);
11619 GPRTemporary ident(this);
11620
11621 GPRReg propertyGPR = property.gpr();
11622 GPRReg identGPR = ident.gpr();
11623
11624 speculateString(propertyEdge, propertyGPR);
11625 speculateStringIdentAndLoadStorage(propertyEdge, propertyGPR, identGPR);
11626
11627 useChildren(node);
11628
11629 flushRegisters();
11630 callOperation(operationDefineDataPropertyStringIdent, NoResult, baseGPR, identGPR, valueRegs, attributesGPR);
11631 m_jit.exceptionCheck();
11632 break;
11633 }
11634 case SymbolUse: {
11635 SpeculateCellOperand property(this, propertyEdge);
11636 GPRReg propertyGPR = property.gpr();
11637 speculateSymbol(propertyEdge, propertyGPR);
11638
11639 useChildren(node);
11640
11641 flushRegisters();
11642 callOperation(operationDefineDataPropertySymbol, NoResult, baseGPR, propertyGPR, valueRegs, attributesGPR);
11643 m_jit.exceptionCheck();
11644 break;
11645 }
11646 case UntypedUse: {
11647 JSValueOperand property(this, propertyEdge);
11648 JSValueRegs propertyRegs = property.jsValueRegs();
11649
11650 useChildren(node);
11651
11652 flushRegisters();
11653 callOperation(operationDefineDataProperty, NoResult, baseGPR, propertyRegs, valueRegs, attributesGPR);
11654 m_jit.exceptionCheck();
11655 break;
11656 }
11657 default:
11658 RELEASE_ASSERT_NOT_REACHED();
11659 }
11660
11661 noResult(node, UseChildrenCalledExplicitly);
11662}
11663
11664void SpeculativeJIT::compileDefineAccessorProperty(Node* node)
11665{
11666#if USE(JSVALUE64)
11667 static_assert(GPRInfo::numberOfRegisters >= 5, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
11668#else
11669 static_assert(GPRInfo::numberOfRegisters >= 6, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
11670#endif
11671
11672 SpeculateCellOperand base(this, m_jit.graph().varArgChild(node, 0));
11673 GPRReg baseGPR = base.gpr();
11674
11675 SpeculateCellOperand getter(this, m_jit.graph().varArgChild(node, 2));
11676 GPRReg getterGPR = getter.gpr();
11677
11678 SpeculateCellOperand setter(this, m_jit.graph().varArgChild(node, 3));
11679 GPRReg setterGPR = setter.gpr();
11680
11681 SpeculateInt32Operand attributes(this, m_jit.graph().varArgChild(node, 4));
11682 GPRReg attributesGPR = attributes.gpr();
11683
11684 Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
11685 switch (propertyEdge.useKind()) {
11686 case StringUse: {
11687 SpeculateCellOperand property(this, propertyEdge);
11688 GPRReg propertyGPR = property.gpr();
11689 speculateString(propertyEdge, propertyGPR);
11690
11691 useChildren(node);
11692
11693 flushRegisters();
11694 callOperation(operationDefineAccessorPropertyString, NoResult, baseGPR, propertyGPR, getterGPR, setterGPR, attributesGPR);
11695 m_jit.exceptionCheck();
11696 break;
11697 }
11698 case StringIdentUse: {
11699 SpeculateCellOperand property(this, propertyEdge);
11700 GPRTemporary ident(this);
11701
11702 GPRReg propertyGPR = property.gpr();
11703 GPRReg identGPR = ident.gpr();
11704
11705 speculateString(propertyEdge, propertyGPR);
11706 speculateStringIdentAndLoadStorage(propertyEdge, propertyGPR, identGPR);
11707
11708 useChildren(node);
11709
11710 flushRegisters();
11711 callOperation(operationDefineAccessorPropertyStringIdent, NoResult, baseGPR, identGPR, getterGPR, setterGPR, attributesGPR);
11712 m_jit.exceptionCheck();
11713 break;
11714 }
11715 case SymbolUse: {
11716 SpeculateCellOperand property(this, propertyEdge);
11717 GPRReg propertyGPR = property.gpr();
11718 speculateSymbol(propertyEdge, propertyGPR);
11719
11720 useChildren(node);
11721
11722 flushRegisters();
11723 callOperation(operationDefineAccessorPropertySymbol, NoResult, baseGPR, propertyGPR, getterGPR, setterGPR, attributesGPR);
11724 m_jit.exceptionCheck();
11725 break;
11726 }
11727 case UntypedUse: {
11728 JSValueOperand property(this, propertyEdge);
11729 JSValueRegs propertyRegs = property.jsValueRegs();
11730
11731 useChildren(node);
11732
11733 flushRegisters();
11734 callOperation(operationDefineAccessorProperty, NoResult, baseGPR, propertyRegs, getterGPR, setterGPR, attributesGPR);
11735 m_jit.exceptionCheck();
11736 break;
11737 }
11738 default:
11739 RELEASE_ASSERT_NOT_REACHED();
11740 }
11741
11742 noResult(node, UseChildrenCalledExplicitly);
11743}
11744
11745void SpeculativeJIT::emitAllocateButterfly(GPRReg storageResultGPR, GPRReg sizeGPR, GPRReg scratch1, GPRReg scratch2, GPRReg scratch3, MacroAssembler::JumpList& slowCases)
11746{
11747 RELEASE_ASSERT(RegisterSet(storageResultGPR, sizeGPR, scratch1, scratch2, scratch3).numberOfSetGPRs() == 5);
11748 ASSERT((1 << 3) == sizeof(JSValue));
11749 m_jit.zeroExtend32ToPtr(sizeGPR, scratch1);
11750 m_jit.lshift32(TrustedImm32(3), scratch1);
11751 m_jit.add32(TrustedImm32(sizeof(IndexingHeader)), scratch1, scratch2);
11752#if !ASSERT_DISABLED
11753 MacroAssembler::Jump didNotOverflow = m_jit.branch32(MacroAssembler::AboveOrEqual, scratch2, sizeGPR);
11754 m_jit.abortWithReason(UncheckedOverflow);
11755 didNotOverflow.link(&m_jit);
11756#endif
11757 m_jit.emitAllocateVariableSized(
11758 storageResultGPR, m_jit.vm()->jsValueGigacageAuxiliarySpace, scratch2, scratch1, scratch3, slowCases);
11759 m_jit.addPtr(TrustedImm32(sizeof(IndexingHeader)), storageResultGPR);
11760
11761 m_jit.store32(sizeGPR, MacroAssembler::Address(storageResultGPR, Butterfly::offsetOfPublicLength()));
11762 m_jit.store32(sizeGPR, MacroAssembler::Address(storageResultGPR, Butterfly::offsetOfVectorLength()));
11763}
11764
11765void SpeculativeJIT::compileNormalizeMapKey(Node* node)
11766{
11767 ASSERT(node->child1().useKind() == UntypedUse);
11768 JSValueOperand key(this, node->child1());
11769 JSValueRegsTemporary result(this, Reuse, key);
11770 GPRTemporary scratch(this);
11771 FPRTemporary doubleValue(this);
11772 FPRTemporary temp(this);
11773
11774 JSValueRegs keyRegs = key.jsValueRegs();
11775 JSValueRegs resultRegs = result.regs();
11776 GPRReg scratchGPR = scratch.gpr();
11777 FPRReg doubleValueFPR = doubleValue.fpr();
11778 FPRReg tempFPR = temp.fpr();
11779
11780 CCallHelpers::JumpList passThroughCases;
11781 CCallHelpers::JumpList doneCases;
11782
11783 passThroughCases.append(m_jit.branchIfNotNumber(keyRegs, scratchGPR));
11784 passThroughCases.append(m_jit.branchIfInt32(keyRegs));
11785
11786#if USE(JSVALUE64)
11787 m_jit.unboxDoubleWithoutAssertions(keyRegs.gpr(), scratchGPR, doubleValueFPR);
11788#else
11789 unboxDouble(keyRegs.tagGPR(), keyRegs.payloadGPR(), doubleValueFPR, tempFPR);
11790#endif
11791 auto notNaN = m_jit.branchIfNotNaN(doubleValueFPR);
11792 m_jit.moveTrustedValue(jsNaN(), resultRegs);
11793 doneCases.append(m_jit.jump());
11794
11795 notNaN.link(&m_jit);
11796 m_jit.truncateDoubleToInt32(doubleValueFPR, scratchGPR);
11797 m_jit.convertInt32ToDouble(scratchGPR, tempFPR);
11798 passThroughCases.append(m_jit.branchDouble(JITCompiler::DoubleNotEqual, doubleValueFPR, tempFPR));
11799
11800 m_jit.boxInt32(scratchGPR, resultRegs);
11801 doneCases.append(m_jit.jump());
11802
11803 passThroughCases.link(&m_jit);
11804 m_jit.moveValueRegs(keyRegs, resultRegs);
11805
11806 doneCases.link(&m_jit);
11807 jsValueResult(resultRegs, node);
11808}
11809
11810void SpeculativeJIT::compileGetMapBucketHead(Node* node)
11811{
11812 SpeculateCellOperand map(this, node->child1());
11813 GPRTemporary bucket(this);
11814
11815 GPRReg mapGPR = map.gpr();
11816 GPRReg bucketGPR = bucket.gpr();
11817
11818 if (node->child1().useKind() == MapObjectUse)
11819 speculateMapObject(node->child1(), mapGPR);
11820 else if (node->child1().useKind() == SetObjectUse)
11821 speculateSetObject(node->child1(), mapGPR);
11822 else
11823 RELEASE_ASSERT_NOT_REACHED();
11824
11825 ASSERT(HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfHead() == HashMapImpl<HashMapBucket<HashMapBucketDataKeyValue>>::offsetOfHead());
11826 m_jit.loadPtr(MacroAssembler::Address(mapGPR, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfHead()), bucketGPR);
11827 cellResult(bucketGPR, node);
11828}
11829
11830void SpeculativeJIT::compileGetMapBucketNext(Node* node)
11831{
11832 SpeculateCellOperand bucket(this, node->child1());
11833 GPRTemporary result(this);
11834
11835 GPRReg bucketGPR = bucket.gpr();
11836 GPRReg resultGPR = result.gpr();
11837
11838 ASSERT(HashMapBucket<HashMapBucketDataKey>::offsetOfNext() == HashMapBucket<HashMapBucketDataKeyValue>::offsetOfNext());
11839 ASSERT(HashMapBucket<HashMapBucketDataKey>::offsetOfKey() == HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey());
11840 m_jit.loadPtr(MacroAssembler::Address(bucketGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfNext()), resultGPR);
11841
11842 MacroAssembler::Label loop = m_jit.label();
11843 auto notBucket = m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR);
11844#if USE(JSVALUE32_64)
11845 auto done = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::Address(resultGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey() + TagOffset), TrustedImm32(JSValue::EmptyValueTag));
11846#else
11847 auto done = m_jit.branchTest64(MacroAssembler::NonZero, MacroAssembler::Address(resultGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey()));
11848#endif
11849 m_jit.loadPtr(MacroAssembler::Address(resultGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfNext()), resultGPR);
11850 m_jit.jump().linkTo(loop, &m_jit);
11851
11852 notBucket.link(&m_jit);
11853 JSCell* sentinel = nullptr;
11854 if (node->bucketOwnerType() == BucketOwnerType::Map)
11855 sentinel = m_jit.vm()->sentinelMapBucket();
11856 else {
11857 ASSERT(node->bucketOwnerType() == BucketOwnerType::Set);
11858 sentinel = m_jit.vm()->sentinelSetBucket();
11859 }
11860 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), sentinel), resultGPR);
11861 done.link(&m_jit);
11862
11863 cellResult(resultGPR, node);
11864}
11865
11866void SpeculativeJIT::compileLoadKeyFromMapBucket(Node* node)
11867{
11868 SpeculateCellOperand bucket(this, node->child1());
11869 JSValueRegsTemporary result(this);
11870
11871 GPRReg bucketGPR = bucket.gpr();
11872 JSValueRegs resultRegs = result.regs();
11873
11874 m_jit.loadValue(MacroAssembler::Address(bucketGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey()), resultRegs);
11875 jsValueResult(resultRegs, node);
11876}
11877
11878void SpeculativeJIT::compileLoadValueFromMapBucket(Node* node)
11879{
11880 SpeculateCellOperand bucket(this, node->child1());
11881 JSValueRegsTemporary result(this);
11882
11883 GPRReg bucketGPR = bucket.gpr();
11884 JSValueRegs resultRegs = result.regs();
11885
11886 m_jit.loadValue(MacroAssembler::Address(bucketGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfValue()), resultRegs);
11887 jsValueResult(resultRegs, node);
11888}
11889
11890void SpeculativeJIT::compileExtractValueFromWeakMapGet(Node* node)
11891{
11892 JSValueOperand value(this, node->child1());
11893 JSValueRegsTemporary result(this, Reuse, value);
11894
11895 JSValueRegs valueRegs = value.jsValueRegs();
11896 JSValueRegs resultRegs = result.regs();
11897
11898#if USE(JSVALUE64)
11899 m_jit.moveValueRegs(valueRegs, resultRegs);
11900 auto done = m_jit.branchTestPtr(CCallHelpers::NonZero, resultRegs.payloadGPR());
11901 m_jit.moveValue(jsUndefined(), resultRegs);
11902 done.link(&m_jit);
11903#else
11904 auto isEmpty = m_jit.branchIfEmpty(valueRegs.tagGPR());
11905 m_jit.moveValueRegs(valueRegs, resultRegs);
11906 auto done = m_jit.jump();
11907
11908 isEmpty.link(&m_jit);
11909 m_jit.moveValue(jsUndefined(), resultRegs);
11910
11911 done.link(&m_jit);
11912#endif
11913
11914 jsValueResult(resultRegs, node, DataFormatJS);
11915}
11916
11917void SpeculativeJIT::compileThrow(Node* node)
11918{
11919 JSValueOperand value(this, node->child1());
11920 JSValueRegs valueRegs = value.jsValueRegs();
11921 flushRegisters();
11922 callOperation(operationThrowDFG, valueRegs);
11923 m_jit.exceptionCheck();
11924 m_jit.breakpoint();
11925 noResult(node);
11926}
11927
11928void SpeculativeJIT::compileThrowStaticError(Node* node)
11929{
11930 SpeculateCellOperand message(this, node->child1());
11931 GPRReg messageGPR = message.gpr();
11932 speculateString(node->child1(), messageGPR);
11933 flushRegisters();
11934 callOperation(operationThrowStaticError, messageGPR, node->errorType());
11935 m_jit.exceptionCheck();
11936 m_jit.breakpoint();
11937 noResult(node);
11938}
11939
11940void SpeculativeJIT::compileGetEnumerableLength(Node* node)
11941{
11942 SpeculateCellOperand enumerator(this, node->child1());
11943 GPRFlushedCallResult result(this);
11944 GPRReg resultGPR = result.gpr();
11945
11946 m_jit.load32(MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::indexedLengthOffset()), resultGPR);
11947 int32Result(resultGPR, node);
11948}
11949
11950void SpeculativeJIT::compileHasGenericProperty(Node* node)
11951{
11952 JSValueOperand base(this, node->child1());
11953 SpeculateCellOperand property(this, node->child2());
11954
11955 JSValueRegs baseRegs = base.jsValueRegs();
11956 GPRReg propertyGPR = property.gpr();
11957
11958 flushRegisters();
11959 JSValueRegsFlushedCallResult result(this);
11960 JSValueRegs resultRegs = result.regs();
11961 callOperation(operationHasGenericProperty, resultRegs, baseRegs, propertyGPR);
11962 m_jit.exceptionCheck();
11963 blessedBooleanResult(resultRegs.payloadGPR(), node);
11964}
11965
11966void SpeculativeJIT::compileToIndexString(Node* node)
11967{
11968 SpeculateInt32Operand index(this, node->child1());
11969 GPRReg indexGPR = index.gpr();
11970
11971 flushRegisters();
11972 GPRFlushedCallResult result(this);
11973 GPRReg resultGPR = result.gpr();
11974 callOperation(operationToIndexString, resultGPR, indexGPR);
11975 m_jit.exceptionCheck();
11976 cellResult(resultGPR, node);
11977}
11978
11979void SpeculativeJIT::compilePutByIdFlush(Node* node)
11980{
11981 SpeculateCellOperand base(this, node->child1());
11982 JSValueOperand value(this, node->child2());
11983 GPRTemporary scratch(this);
11984
11985 GPRReg baseGPR = base.gpr();
11986 JSValueRegs valueRegs = value.jsValueRegs();
11987 GPRReg scratchGPR = scratch.gpr();
11988 flushRegisters();
11989
11990 cachedPutById(node->origin.semantic, baseGPR, valueRegs, scratchGPR, node->identifierNumber(), NotDirect, MacroAssembler::Jump(), DontSpill);
11991
11992 noResult(node);
11993}
11994
11995void SpeculativeJIT::compilePutById(Node* node)
11996{
11997 SpeculateCellOperand base(this, node->child1());
11998 JSValueOperand value(this, node->child2());
11999 GPRTemporary scratch(this);
12000
12001 GPRReg baseGPR = base.gpr();
12002 JSValueRegs valueRegs = value.jsValueRegs();
12003 GPRReg scratchGPR = scratch.gpr();
12004
12005 cachedPutById(node->origin.semantic, baseGPR, valueRegs, scratchGPR, node->identifierNumber(), NotDirect);
12006
12007 noResult(node);
12008}
12009
12010void SpeculativeJIT::compilePutByIdDirect(Node* node)
12011{
12012 SpeculateCellOperand base(this, node->child1());
12013 JSValueOperand value(this, node->child2());
12014 GPRTemporary scratch(this);
12015
12016 GPRReg baseGPR = base.gpr();
12017 JSValueRegs valueRegs = value.jsValueRegs();
12018 GPRReg scratchGPR = scratch.gpr();
12019
12020 cachedPutById(node->origin.semantic, baseGPR, valueRegs, scratchGPR, node->identifierNumber(), Direct);
12021
12022 noResult(node);
12023}
12024
12025void SpeculativeJIT::compilePutByIdWithThis(Node* node)
12026{
12027 JSValueOperand base(this, node->child1());
12028 JSValueRegs baseRegs = base.jsValueRegs();
12029 JSValueOperand thisValue(this, node->child2());
12030 JSValueRegs thisRegs = thisValue.jsValueRegs();
12031 JSValueOperand value(this, node->child3());
12032 JSValueRegs valueRegs = value.jsValueRegs();
12033
12034 flushRegisters();
12035 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByIdWithThisStrict : operationPutByIdWithThis,
12036 NoResult, baseRegs, thisRegs, valueRegs, identifierUID(node->identifierNumber()));
12037 m_jit.exceptionCheck();
12038
12039 noResult(node);
12040}
12041
12042void SpeculativeJIT::compileGetByOffset(Node* node)
12043{
12044 StorageOperand storage(this, node->child1());
12045 JSValueRegsTemporary result(this, Reuse, storage);
12046
12047 GPRReg storageGPR = storage.gpr();
12048 JSValueRegs resultRegs = result.regs();
12049
12050 StorageAccessData& storageAccessData = node->storageAccessData();
12051
12052 m_jit.loadValue(JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset)), resultRegs);
12053
12054 jsValueResult(resultRegs, node);
12055}
12056
12057void SpeculativeJIT::compilePutByOffset(Node* node)
12058{
12059 StorageOperand storage(this, node->child1());
12060 JSValueOperand value(this, node->child3());
12061
12062 GPRReg storageGPR = storage.gpr();
12063 JSValueRegs valueRegs = value.jsValueRegs();
12064
12065 speculate(node, node->child2());
12066
12067 StorageAccessData& storageAccessData = node->storageAccessData();
12068
12069 m_jit.storeValue(valueRegs, JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset)));
12070
12071 noResult(node);
12072}
12073
12074void SpeculativeJIT::compileMatchStructure(Node* node)
12075{
12076 SpeculateCellOperand base(this, node->child1());
12077 GPRTemporary temp(this);
12078 GPRReg baseGPR = base.gpr();
12079 GPRReg tempGPR = temp.gpr();
12080
12081 m_jit.load32(JITCompiler::Address(baseGPR, JSCell::structureIDOffset()), tempGPR);
12082
12083 auto& variants = node->matchStructureData().variants;
12084 Vector<int64_t> cases;
12085 for (MatchStructureVariant& variant : variants)
12086 cases.append(bitwise_cast<int32_t>(variant.structure->id()));
12087
12088 BinarySwitch binarySwitch(tempGPR, cases, BinarySwitch::Int32);
12089 JITCompiler::JumpList done;
12090 while (binarySwitch.advance(m_jit)) {
12091 m_jit.boxBooleanPayload(variants[binarySwitch.caseIndex()].result, tempGPR);
12092 done.append(m_jit.jump());
12093 }
12094 speculationCheck(BadCache, JSValueRegs(), node, binarySwitch.fallThrough());
12095
12096 done.link(&m_jit);
12097
12098 blessedBooleanResult(tempGPR, node);
12099}
12100
12101void SpeculativeJIT::compileHasStructureProperty(Node* node)
12102{
12103 JSValueOperand base(this, node->child1());
12104 SpeculateCellOperand property(this, node->child2());
12105 SpeculateCellOperand enumerator(this, node->child3());
12106 JSValueRegsTemporary result(this);
12107
12108 JSValueRegs baseRegs = base.jsValueRegs();
12109 GPRReg propertyGPR = property.gpr();
12110 JSValueRegs resultRegs = result.regs();
12111
12112 CCallHelpers::JumpList wrongStructure;
12113
12114 wrongStructure.append(m_jit.branchIfNotCell(baseRegs));
12115
12116 m_jit.load32(MacroAssembler::Address(baseRegs.payloadGPR(), JSCell::structureIDOffset()), resultRegs.payloadGPR());
12117 wrongStructure.append(m_jit.branch32(MacroAssembler::NotEqual,
12118 resultRegs.payloadGPR(),
12119 MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::cachedStructureIDOffset())));
12120
12121 moveTrueTo(resultRegs.payloadGPR());
12122 MacroAssembler::Jump done = m_jit.jump();
12123
12124 done.link(&m_jit);
12125
12126 addSlowPathGenerator(slowPathCall(wrongStructure, this, operationHasGenericProperty, resultRegs, baseRegs, propertyGPR));
12127 blessedBooleanResult(resultRegs.payloadGPR(), node);
12128}
12129
12130void SpeculativeJIT::compileGetPropertyEnumerator(Node* node)
12131{
12132 if (node->child1().useKind() == CellUse) {
12133 SpeculateCellOperand base(this, node->child1());
12134 GPRReg baseGPR = base.gpr();
12135
12136 flushRegisters();
12137 GPRFlushedCallResult result(this);
12138 GPRReg resultGPR = result.gpr();
12139 callOperation(operationGetPropertyEnumeratorCell, resultGPR, baseGPR);
12140 m_jit.exceptionCheck();
12141 cellResult(resultGPR, node);
12142 return;
12143 }
12144
12145 JSValueOperand base(this, node->child1());
12146 JSValueRegs baseRegs = base.jsValueRegs();
12147
12148 flushRegisters();
12149 GPRFlushedCallResult result(this);
12150 GPRReg resultGPR = result.gpr();
12151 callOperation(operationGetPropertyEnumerator, resultGPR, baseRegs);
12152 m_jit.exceptionCheck();
12153 cellResult(resultGPR, node);
12154}
12155
12156void SpeculativeJIT::compileGetEnumeratorPname(Node* node)
12157{
12158 ASSERT(node->op() == GetEnumeratorStructurePname || node->op() == GetEnumeratorGenericPname);
12159 SpeculateCellOperand enumerator(this, node->child1());
12160 SpeculateStrictInt32Operand index(this, node->child2());
12161 GPRTemporary scratch(this);
12162 JSValueRegsTemporary result(this);
12163
12164 GPRReg enumeratorGPR = enumerator.gpr();
12165 GPRReg indexGPR = index.gpr();
12166 GPRReg scratchGPR = scratch.gpr();
12167 JSValueRegs resultRegs = result.regs();
12168
12169 MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, indexGPR,
12170 MacroAssembler::Address(enumeratorGPR, (node->op() == GetEnumeratorStructurePname)
12171 ? JSPropertyNameEnumerator::endStructurePropertyIndexOffset()
12172 : JSPropertyNameEnumerator::endGenericPropertyIndexOffset()));
12173
12174 m_jit.moveValue(jsNull(), resultRegs);
12175
12176 MacroAssembler::Jump done = m_jit.jump();
12177 inBounds.link(&m_jit);
12178
12179 m_jit.loadPtr(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), scratchGPR);
12180 m_jit.loadPtr(MacroAssembler::BaseIndex(scratchGPR, indexGPR, MacroAssembler::ScalePtr), resultRegs.payloadGPR());
12181#if USE(JSVALUE32_64)
12182 m_jit.move(MacroAssembler::TrustedImm32(JSValue::CellTag), resultRegs.tagGPR());
12183#endif
12184
12185 done.link(&m_jit);
12186 jsValueResult(resultRegs, node);
12187}
12188
12189void SpeculativeJIT::compileGetExecutable(Node* node)
12190{
12191 SpeculateCellOperand function(this, node->child1());
12192 GPRTemporary result(this, Reuse, function);
12193 GPRReg functionGPR = function.gpr();
12194 GPRReg resultGPR = result.gpr();
12195 speculateCellType(node->child1(), functionGPR, SpecFunction, JSFunctionType);
12196 m_jit.loadPtr(JITCompiler::Address(functionGPR, JSFunction::offsetOfExecutable()), resultGPR);
12197 cellResult(resultGPR, node);
12198}
12199
12200void SpeculativeJIT::compileGetGetter(Node* node)
12201{
12202 SpeculateCellOperand op1(this, node->child1());
12203 GPRTemporary result(this, Reuse, op1);
12204
12205 GPRReg op1GPR = op1.gpr();
12206 GPRReg resultGPR = result.gpr();
12207
12208 m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfGetter()), resultGPR);
12209
12210 cellResult(resultGPR, node);
12211}
12212
12213void SpeculativeJIT::compileGetSetter(Node* node)
12214{
12215 SpeculateCellOperand op1(this, node->child1());
12216 GPRTemporary result(this, Reuse, op1);
12217
12218 GPRReg op1GPR = op1.gpr();
12219 GPRReg resultGPR = result.gpr();
12220
12221 m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfSetter()), resultGPR);
12222
12223 cellResult(resultGPR, node);
12224}
12225
12226void SpeculativeJIT::compileGetCallee(Node* node)
12227{
12228 GPRTemporary result(this);
12229 m_jit.loadPtr(JITCompiler::payloadFor(CallFrameSlot::callee), result.gpr());
12230 cellResult(result.gpr(), node);
12231}
12232
12233void SpeculativeJIT::compileSetCallee(Node* node)
12234{
12235 SpeculateCellOperand callee(this, node->child1());
12236 m_jit.storeCell(callee.gpr(), JITCompiler::payloadFor(CallFrameSlot::callee));
12237 noResult(node);
12238}
12239
12240void SpeculativeJIT::compileGetArgumentCountIncludingThis(Node* node)
12241{
12242 GPRTemporary result(this);
12243 VirtualRegister argumentCountRegister;
12244 if (InlineCallFrame* inlineCallFrame = node->argumentsInlineCallFrame())
12245 argumentCountRegister = inlineCallFrame->argumentCountRegister;
12246 else
12247 argumentCountRegister = VirtualRegister(CallFrameSlot::argumentCount);
12248 m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), result.gpr());
12249 int32Result(result.gpr(), node);
12250}
12251
12252void SpeculativeJIT::compileSetArgumentCountIncludingThis(Node* node)
12253{
12254 m_jit.store32(TrustedImm32(node->argumentCountIncludingThis()), JITCompiler::payloadFor(CallFrameSlot::argumentCount));
12255 noResult(node);
12256}
12257
12258void SpeculativeJIT::compileStrCat(Node* node)
12259{
12260 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
12261 JSValueOperand op2(this, node->child2(), ManualOperandSpeculation);
12262 JSValueOperand op3(this, node->child3(), ManualOperandSpeculation);
12263
12264 JSValueRegs op1Regs = op1.jsValueRegs();
12265 JSValueRegs op2Regs = op2.jsValueRegs();
12266 JSValueRegs op3Regs;
12267
12268 if (node->child3())
12269 op3Regs = op3.jsValueRegs();
12270
12271 flushRegisters();
12272
12273 GPRFlushedCallResult result(this);
12274 if (node->child3())
12275 callOperation(operationStrCat3, result.gpr(), op1Regs, op2Regs, op3Regs);
12276 else
12277 callOperation(operationStrCat2, result.gpr(), op1Regs, op2Regs);
12278 m_jit.exceptionCheck();
12279
12280 cellResult(result.gpr(), node);
12281}
12282
12283void SpeculativeJIT::compileNewArrayBuffer(Node* node)
12284{
12285 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
12286 auto* array = node->castOperand<JSImmutableButterfly*>();
12287
12288 IndexingType indexingMode = node->indexingMode();
12289 RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingMode));
12290
12291 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(indexingMode)) {
12292 GPRTemporary result(this);
12293 GPRTemporary scratch1(this);
12294 GPRTemporary scratch2(this);
12295
12296 GPRReg resultGPR = result.gpr();
12297 GPRReg scratch1GPR = scratch1.gpr();
12298 GPRReg scratch2GPR = scratch2.gpr();
12299
12300 MacroAssembler::JumpList slowCases;
12301
12302 emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), TrustedImmPtr(array->toButterfly()), scratch1GPR, scratch2GPR, slowCases);
12303
12304 addSlowPathGenerator(slowPathCall(slowCases, this, operationNewArrayBuffer, result.gpr(), structure, array));
12305
12306 DFG_ASSERT(m_jit.graph(), node, indexingMode & IsArray, indexingMode);
12307 cellResult(resultGPR, node);
12308 return;
12309 }
12310
12311 flushRegisters();
12312 GPRFlushedCallResult result(this);
12313
12314 callOperation(operationNewArrayBuffer, result.gpr(), structure, TrustedImmPtr(node->cellOperand()));
12315 m_jit.exceptionCheck();
12316
12317 cellResult(result.gpr(), node);
12318}
12319
12320void SpeculativeJIT::compileNewArrayWithSize(Node* node)
12321{
12322 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
12323 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(node->indexingType())) {
12324 SpeculateStrictInt32Operand size(this, node->child1());
12325 GPRTemporary result(this);
12326
12327 GPRReg sizeGPR = size.gpr();
12328 GPRReg resultGPR = result.gpr();
12329
12330 compileAllocateNewArrayWithSize(globalObject, resultGPR, sizeGPR, node->indexingType());
12331 cellResult(resultGPR, node);
12332 return;
12333 }
12334
12335 SpeculateStrictInt32Operand size(this, node->child1());
12336 GPRReg sizeGPR = size.gpr();
12337 flushRegisters();
12338 GPRFlushedCallResult result(this);
12339 GPRReg resultGPR = result.gpr();
12340 GPRReg structureGPR = AssemblyHelpers::selectScratchGPR(sizeGPR);
12341 MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH));
12342 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()))), structureGPR);
12343 MacroAssembler::Jump done = m_jit.jump();
12344 bigLength.link(&m_jit);
12345 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage))), structureGPR);
12346 done.link(&m_jit);
12347 callOperation(operationNewArrayWithSize, resultGPR, structureGPR, sizeGPR, nullptr);
12348 m_jit.exceptionCheck();
12349 cellResult(resultGPR, node);
12350}
12351
12352void SpeculativeJIT::compileNewTypedArray(Node* node)
12353{
12354 switch (node->child1().useKind()) {
12355 case Int32Use:
12356 compileNewTypedArrayWithSize(node);
12357 break;
12358 case UntypedUse: {
12359 JSValueOperand argument(this, node->child1());
12360 JSValueRegs argumentRegs = argument.jsValueRegs();
12361
12362 flushRegisters();
12363
12364 GPRFlushedCallResult result(this);
12365 GPRReg resultGPR = result.gpr();
12366
12367 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
12368 callOperation(
12369 operationNewTypedArrayWithOneArgumentForType(node->typedArrayType()),
12370 resultGPR, m_jit.graph().registerStructure(globalObject->typedArrayStructureConcurrently(node->typedArrayType())), argumentRegs);
12371 m_jit.exceptionCheck();
12372
12373 cellResult(resultGPR, node);
12374 break;
12375 }
12376 default:
12377 RELEASE_ASSERT_NOT_REACHED();
12378 break;
12379 }
12380}
12381
12382void SpeculativeJIT::compileToThis(Node* node)
12383{
12384 ASSERT(node->child1().useKind() == UntypedUse);
12385 JSValueOperand thisValue(this, node->child1());
12386 JSValueRegsTemporary temp(this);
12387
12388 JSValueRegs thisValueRegs = thisValue.jsValueRegs();
12389 JSValueRegs tempRegs = temp.regs();
12390
12391 MacroAssembler::JumpList slowCases;
12392 slowCases.append(m_jit.branchIfNotCell(thisValueRegs));
12393 slowCases.append(
12394 m_jit.branchTest8(
12395 MacroAssembler::NonZero,
12396 MacroAssembler::Address(thisValueRegs.payloadGPR(), JSCell::typeInfoFlagsOffset()),
12397 MacroAssembler::TrustedImm32(OverridesToThis)));
12398 m_jit.moveValueRegs(thisValueRegs, tempRegs);
12399
12400 J_JITOperation_EJ function;
12401 if (m_jit.isStrictModeFor(node->origin.semantic))
12402 function = operationToThisStrict;
12403 else
12404 function = operationToThis;
12405 addSlowPathGenerator(slowPathCall(slowCases, this, function, tempRegs, thisValueRegs));
12406
12407 jsValueResult(tempRegs, node);
12408}
12409
12410void SpeculativeJIT::compileObjectKeys(Node* node)
12411{
12412 switch (node->child1().useKind()) {
12413 case ObjectUse: {
12414 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
12415 SpeculateCellOperand object(this, node->child1());
12416 GPRTemporary structure(this);
12417 GPRTemporary scratch(this);
12418 GPRTemporary scratch2(this);
12419 GPRTemporary scratch3(this);
12420 GPRTemporary result(this);
12421
12422 GPRReg objectGPR = object.gpr();
12423 GPRReg structureGPR = structure.gpr();
12424 GPRReg scratchGPR = scratch.gpr();
12425 GPRReg scratch2GPR = scratch2.gpr();
12426 GPRReg scratch3GPR = scratch3.gpr();
12427 GPRReg resultGPR = result.gpr();
12428
12429 speculateObject(node->child1(), objectGPR);
12430
12431 CCallHelpers::JumpList slowCases;
12432 m_jit.emitLoadStructure(*m_jit.vm(), objectGPR, structureGPR, scratchGPR);
12433 m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::previousOrRareDataOffset()), scratchGPR);
12434
12435 slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR));
12436 slowCases.append(m_jit.branch32(CCallHelpers::Equal, CCallHelpers::Address(scratchGPR, JSCell::structureIDOffset()), TrustedImm32(bitwise_cast<int32_t>(m_jit.vm()->structureStructure->structureID()))));
12437
12438 m_jit.loadPtr(CCallHelpers::Address(scratchGPR, StructureRareData::offsetOfCachedOwnKeys()), scratchGPR);
12439
12440 ASSERT(bitwise_cast<uintptr_t>(StructureRareData::cachedOwnKeysSentinel()) == 1);
12441 slowCases.append(m_jit.branchPtr(CCallHelpers::BelowOrEqual, scratchGPR, TrustedImmPtr(bitwise_cast<void*>(StructureRareData::cachedOwnKeysSentinel()))));
12442
12443 MacroAssembler::JumpList slowButArrayBufferCases;
12444
12445 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
12446 RegisteredStructure arrayStructure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous));
12447
12448 m_jit.move(scratchGPR, scratch3GPR);
12449 m_jit.addPtr(TrustedImmPtr(JSImmutableButterfly::offsetOfData()), scratchGPR);
12450
12451 emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(arrayStructure), scratchGPR, structureGPR, scratch2GPR, slowButArrayBufferCases);
12452
12453 addSlowPathGenerator(slowPathCall(slowButArrayBufferCases, this, operationNewArrayBuffer, resultGPR, arrayStructure, scratch3GPR));
12454
12455 addSlowPathGenerator(slowPathCall(slowCases, this, operationObjectKeysObject, resultGPR, objectGPR));
12456
12457 cellResult(resultGPR, node);
12458 break;
12459 }
12460
12461 SpeculateCellOperand object(this, node->child1());
12462
12463 GPRReg objectGPR = object.gpr();
12464
12465 speculateObject(node->child1(), objectGPR);
12466
12467 flushRegisters();
12468 GPRFlushedCallResult result(this);
12469 GPRReg resultGPR = result.gpr();
12470 callOperation(operationObjectKeysObject, resultGPR, objectGPR);
12471 m_jit.exceptionCheck();
12472
12473 cellResult(resultGPR, node);
12474 break;
12475 }
12476
12477 case UntypedUse: {
12478 JSValueOperand object(this, node->child1());
12479
12480 JSValueRegs objectRegs = object.jsValueRegs();
12481
12482 flushRegisters();
12483 GPRFlushedCallResult result(this);
12484 GPRReg resultGPR = result.gpr();
12485 callOperation(operationObjectKeys, resultGPR, objectRegs);
12486 m_jit.exceptionCheck();
12487
12488 cellResult(resultGPR, node);
12489 break;
12490 }
12491
12492 default:
12493 RELEASE_ASSERT_NOT_REACHED();
12494 break;
12495 }
12496}
12497
12498void SpeculativeJIT::compileObjectCreate(Node* node)
12499{
12500 switch (node->child1().useKind()) {
12501 case ObjectUse: {
12502 SpeculateCellOperand prototype(this, node->child1());
12503
12504 GPRReg prototypeGPR = prototype.gpr();
12505
12506 speculateObject(node->child1(), prototypeGPR);
12507
12508 flushRegisters();
12509 GPRFlushedCallResult result(this);
12510 GPRReg resultGPR = result.gpr();
12511 callOperation(operationObjectCreateObject, resultGPR, prototypeGPR);
12512 m_jit.exceptionCheck();
12513
12514 cellResult(resultGPR, node);
12515 break;
12516 }
12517
12518 case UntypedUse: {
12519 JSValueOperand prototype(this, node->child1());
12520
12521 JSValueRegs prototypeRegs = prototype.jsValueRegs();
12522
12523 flushRegisters();
12524 GPRFlushedCallResult result(this);
12525 GPRReg resultGPR = result.gpr();
12526 callOperation(operationObjectCreate, resultGPR, prototypeRegs);
12527 m_jit.exceptionCheck();
12528
12529 cellResult(resultGPR, node);
12530 break;
12531 }
12532
12533 default:
12534 RELEASE_ASSERT_NOT_REACHED();
12535 break;
12536 }
12537}
12538
12539void SpeculativeJIT::compileCreateThis(Node* node)
12540{
12541 // Note that there is not so much profit to speculate here. The only things we
12542 // speculate on are (1) that it's a cell, since that eliminates cell checks
12543 // later if the proto is reused, and (2) if we have a FinalObject prediction
12544 // then we speculate because we want to get recompiled if it isn't (since
12545 // otherwise we'd start taking slow path a lot).
12546
12547 SpeculateCellOperand callee(this, node->child1());
12548 GPRTemporary result(this);
12549 GPRTemporary allocator(this);
12550 GPRTemporary structure(this);
12551 GPRTemporary scratch(this);
12552
12553 GPRReg calleeGPR = callee.gpr();
12554 GPRReg resultGPR = result.gpr();
12555 GPRReg allocatorGPR = allocator.gpr();
12556 GPRReg structureGPR = structure.gpr();
12557 GPRReg scratchGPR = scratch.gpr();
12558 // Rare data is only used to access the allocator & structure
12559 // We can avoid using an additional GPR this way
12560 GPRReg rareDataGPR = structureGPR;
12561 GPRReg inlineCapacityGPR = rareDataGPR;
12562
12563 MacroAssembler::JumpList slowPath;
12564
12565 slowPath.append(m_jit.branchIfNotFunction(calleeGPR));
12566 m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfRareData()), rareDataGPR);
12567 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, rareDataGPR));
12568 m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorGPR);
12569 m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureGPR);
12570
12571 auto butterfly = TrustedImmPtr(nullptr);
12572 emitAllocateJSObject(resultGPR, JITAllocator::variable(), allocatorGPR, structureGPR, butterfly, scratchGPR, slowPath);
12573
12574 m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfRareData()), rareDataGPR);
12575 m_jit.load32(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfile::offsetOfInlineCapacity()), inlineCapacityGPR);
12576 m_jit.emitInitializeInlineStorage(resultGPR, inlineCapacityGPR);
12577 m_jit.mutatorFence(*m_jit.vm());
12578
12579 addSlowPathGenerator(slowPathCall(slowPath, this, operationCreateThis, resultGPR, calleeGPR, node->inlineCapacity()));
12580
12581 cellResult(resultGPR, node);
12582}
12583
12584void SpeculativeJIT::compileNewObject(Node* node)
12585{
12586 GPRTemporary result(this);
12587 GPRTemporary allocator(this);
12588 GPRTemporary scratch(this);
12589
12590 GPRReg resultGPR = result.gpr();
12591 GPRReg allocatorGPR = allocator.gpr();
12592 GPRReg scratchGPR = scratch.gpr();
12593
12594 MacroAssembler::JumpList slowPath;
12595
12596 RegisteredStructure structure = node->structure();
12597 size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity());
12598 Allocator allocatorValue = allocatorForNonVirtualConcurrently<JSFinalObject>(*m_jit.vm(), allocationSize, AllocatorForMode::AllocatorIfExists);
12599 if (!allocatorValue)
12600 slowPath.append(m_jit.jump());
12601 else {
12602 auto butterfly = TrustedImmPtr(nullptr);
12603 emitAllocateJSObject(resultGPR, JITAllocator::constant(allocatorValue), allocatorGPR, TrustedImmPtr(structure), butterfly, scratchGPR, slowPath);
12604 m_jit.emitInitializeInlineStorage(resultGPR, structure->inlineCapacity());
12605 m_jit.mutatorFence(*m_jit.vm());
12606 }
12607
12608 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewObject, resultGPR, structure));
12609
12610 cellResult(resultGPR, node);
12611}
12612
12613void SpeculativeJIT::compileToPrimitive(Node* node)
12614{
12615 DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse, node->child1().useKind());
12616 JSValueOperand argument(this, node->child1());
12617 JSValueRegsTemporary result(this, Reuse, argument);
12618
12619 JSValueRegs argumentRegs = argument.jsValueRegs();
12620 JSValueRegs resultRegs = result.regs();
12621
12622 argument.use();
12623
12624 MacroAssembler::Jump alreadyPrimitive = m_jit.branchIfNotCell(argumentRegs);
12625 MacroAssembler::Jump notPrimitive = m_jit.branchIfObject(argumentRegs.payloadGPR());
12626
12627 alreadyPrimitive.link(&m_jit);
12628 m_jit.moveValueRegs(argumentRegs, resultRegs);
12629
12630 addSlowPathGenerator(slowPathCall(notPrimitive, this, operationToPrimitive, resultRegs, argumentRegs));
12631
12632 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
12633}
12634
12635void SpeculativeJIT::compileLogShadowChickenPrologue(Node* node)
12636{
12637 flushRegisters();
12638 prepareForExternalCall();
12639 m_jit.emitStoreCodeOrigin(node->origin.semantic);
12640
12641 GPRTemporary scratch1(this, GPRInfo::nonArgGPR0); // This must be a non-argument GPR.
12642 GPRReg scratch1Reg = scratch1.gpr();
12643 GPRTemporary scratch2(this);
12644 GPRReg scratch2Reg = scratch2.gpr();
12645 GPRTemporary shadowPacket(this);
12646 GPRReg shadowPacketReg = shadowPacket.gpr();
12647
12648 m_jit.ensureShadowChickenPacket(*m_jit.vm(), shadowPacketReg, scratch1Reg, scratch2Reg);
12649
12650 SpeculateCellOperand scope(this, node->child1());
12651 GPRReg scopeReg = scope.gpr();
12652
12653 m_jit.logShadowChickenProloguePacket(shadowPacketReg, scratch1Reg, scopeReg);
12654 noResult(node);
12655}
12656
12657void SpeculativeJIT::compileLogShadowChickenTail(Node* node)
12658{
12659 flushRegisters();
12660 prepareForExternalCall();
12661 CallSiteIndex callSiteIndex = m_jit.emitStoreCodeOrigin(node->origin.semantic);
12662
12663 GPRTemporary scratch1(this, GPRInfo::nonArgGPR0); // This must be a non-argument GPR.
12664 GPRReg scratch1Reg = scratch1.gpr();
12665 GPRTemporary scratch2(this);
12666 GPRReg scratch2Reg = scratch2.gpr();
12667 GPRTemporary shadowPacket(this);
12668 GPRReg shadowPacketReg = shadowPacket.gpr();
12669
12670 m_jit.ensureShadowChickenPacket(*m_jit.vm(), shadowPacketReg, scratch1Reg, scratch2Reg);
12671
12672 JSValueOperand thisValue(this, node->child1());
12673 JSValueRegs thisRegs = thisValue.jsValueRegs();
12674 SpeculateCellOperand scope(this, node->child2());
12675 GPRReg scopeReg = scope.gpr();
12676
12677 m_jit.logShadowChickenTailPacket(shadowPacketReg, thisRegs, scopeReg, m_jit.codeBlock(), callSiteIndex);
12678 noResult(node);
12679}
12680
12681void SpeculativeJIT::compileSetAdd(Node* node)
12682{
12683 SpeculateCellOperand set(this, node->child1());
12684 JSValueOperand key(this, node->child2());
12685 SpeculateInt32Operand hash(this, node->child3());
12686
12687 GPRReg setGPR = set.gpr();
12688 JSValueRegs keyRegs = key.jsValueRegs();
12689 GPRReg hashGPR = hash.gpr();
12690
12691 speculateSetObject(node->child1(), setGPR);
12692
12693 flushRegisters();
12694 GPRFlushedCallResult result(this);
12695 GPRReg resultGPR = result.gpr();
12696 callOperation(operationSetAdd, resultGPR, setGPR, keyRegs, hashGPR);
12697 m_jit.exceptionCheck();
12698 cellResult(resultGPR, node);
12699}
12700
12701void SpeculativeJIT::compileMapSet(Node* node)
12702{
12703 SpeculateCellOperand map(this, m_jit.graph().varArgChild(node, 0));
12704 JSValueOperand key(this, m_jit.graph().varArgChild(node, 1));
12705 JSValueOperand value(this, m_jit.graph().varArgChild(node, 2));
12706 SpeculateInt32Operand hash(this, m_jit.graph().varArgChild(node, 3));
12707
12708 GPRReg mapGPR = map.gpr();
12709 JSValueRegs keyRegs = key.jsValueRegs();
12710 JSValueRegs valueRegs = value.jsValueRegs();
12711 GPRReg hashGPR = hash.gpr();
12712
12713 speculateMapObject(m_jit.graph().varArgChild(node, 0), mapGPR);
12714
12715 flushRegisters();
12716 GPRFlushedCallResult result(this);
12717 GPRReg resultGPR = result.gpr();
12718 callOperation(operationMapSet, resultGPR, mapGPR, keyRegs, valueRegs, hashGPR);
12719 m_jit.exceptionCheck();
12720 cellResult(resultGPR, node);
12721}
12722
12723void SpeculativeJIT::compileWeakMapGet(Node* node)
12724{
12725 GPRTemporary mask(this);
12726 GPRTemporary buffer(this);
12727 JSValueRegsTemporary result(this);
12728
12729 GPRReg maskGPR = mask.gpr();
12730 GPRReg bufferGPR = buffer.gpr();
12731 JSValueRegs resultRegs = result.regs();
12732
12733 GPRTemporary index;
12734 GPRReg indexGPR { InvalidGPRReg };
12735 {
12736 SpeculateInt32Operand hash(this, node->child3());
12737 GPRReg hashGPR = hash.gpr();
12738 index = GPRTemporary(this, Reuse, hash);
12739 indexGPR = index.gpr();
12740 m_jit.move(hashGPR, indexGPR);
12741 }
12742
12743 {
12744 SpeculateCellOperand weakMap(this, node->child1());
12745 GPRReg weakMapGPR = weakMap.gpr();
12746 if (node->child1().useKind() == WeakMapObjectUse)
12747 speculateWeakMapObject(node->child1(), weakMapGPR);
12748 else
12749 speculateWeakSetObject(node->child1(), weakMapGPR);
12750
12751 ASSERT(WeakMapImpl<WeakMapBucket<WeakMapBucketDataKey>>::offsetOfCapacity() == WeakMapImpl<WeakMapBucket<WeakMapBucketDataKeyValue>>::offsetOfCapacity());
12752 ASSERT(WeakMapImpl<WeakMapBucket<WeakMapBucketDataKey>>::offsetOfBuffer() == WeakMapImpl<WeakMapBucket<WeakMapBucketDataKeyValue>>::offsetOfBuffer());
12753 m_jit.load32(MacroAssembler::Address(weakMapGPR, WeakMapImpl<WeakMapBucket<WeakMapBucketDataKey>>::offsetOfCapacity()), maskGPR);
12754 m_jit.loadPtr(MacroAssembler::Address(weakMapGPR, WeakMapImpl<WeakMapBucket<WeakMapBucketDataKey>>::offsetOfBuffer()), bufferGPR);
12755 }
12756
12757 SpeculateCellOperand key(this, node->child2());
12758 GPRReg keyGPR = key.gpr();
12759 speculateObject(node->child2(), keyGPR);
12760
12761#if USE(JSVALUE32_64)
12762 GPRReg bucketGPR = resultRegs.tagGPR();
12763#else
12764 GPRTemporary bucket(this);
12765 GPRReg bucketGPR = bucket.gpr();
12766#endif
12767
12768 m_jit.sub32(TrustedImm32(1), maskGPR);
12769
12770 MacroAssembler::Label loop = m_jit.label();
12771 m_jit.and32(maskGPR, indexGPR);
12772 if (node->child1().useKind() == WeakSetObjectUse) {
12773 static_assert(sizeof(WeakMapBucket<WeakMapBucketDataKey>) == sizeof(void*), "");
12774 m_jit.zeroExtend32ToPtr(indexGPR, bucketGPR);
12775 m_jit.lshiftPtr(MacroAssembler::Imm32(sizeof(void*) == 4 ? 2 : 3), bucketGPR);
12776 m_jit.addPtr(bufferGPR, bucketGPR);
12777 } else {
12778 ASSERT(node->child1().useKind() == WeakMapObjectUse);
12779 static_assert(sizeof(WeakMapBucket<WeakMapBucketDataKeyValue>) == 16, "");
12780 m_jit.zeroExtend32ToPtr(indexGPR, bucketGPR);
12781 m_jit.lshiftPtr(MacroAssembler::Imm32(4), bucketGPR);
12782 m_jit.addPtr(bufferGPR, bucketGPR);
12783 }
12784
12785 m_jit.loadPtr(MacroAssembler::Address(bucketGPR, WeakMapBucket<WeakMapBucketDataKeyValue>::offsetOfKey()), resultRegs.payloadGPR());
12786
12787 // They're definitely the same value, we found the bucket we were looking for!
12788 // The deleted key comparison is also done with this.
12789 auto found = m_jit.branchPtr(MacroAssembler::Equal, resultRegs.payloadGPR(), keyGPR);
12790
12791 auto notPresentInTable = m_jit.branchTestPtr(MacroAssembler::Zero, resultRegs.payloadGPR());
12792
12793 m_jit.add32(TrustedImm32(1), indexGPR);
12794 m_jit.jump().linkTo(loop, &m_jit);
12795
12796#if USE(JSVALUE32_64)
12797 notPresentInTable.link(&m_jit);
12798 m_jit.moveValue(JSValue(), resultRegs);
12799 auto notPresentInTableDone = m_jit.jump();
12800
12801 found.link(&m_jit);
12802 if (node->child1().useKind() == WeakSetObjectUse)
12803 m_jit.move(TrustedImm32(JSValue::CellTag), resultRegs.tagGPR());
12804 else
12805 m_jit.loadValue(MacroAssembler::Address(bucketGPR, WeakMapBucket<WeakMapBucketDataKeyValue>::offsetOfValue()), resultRegs);
12806
12807 notPresentInTableDone.link(&m_jit);
12808#else
12809 notPresentInTable.link(&m_jit);
12810 found.link(&m_jit);
12811
12812 // In 64bit environment, Empty bucket has JSEmpty value. Empty key is JSEmpty.
12813 // If empty bucket is found, we can use the same path used for the case of finding a bucket.
12814 if (node->child1().useKind() == WeakMapObjectUse)
12815 m_jit.loadValue(MacroAssembler::Address(bucketGPR, WeakMapBucket<WeakMapBucketDataKeyValue>::offsetOfValue()), resultRegs);
12816#endif
12817
12818 jsValueResult(resultRegs, node);
12819}
12820
12821void SpeculativeJIT::compileWeakSetAdd(Node* node)
12822{
12823 SpeculateCellOperand set(this, node->child1());
12824 SpeculateCellOperand key(this, node->child2());
12825 SpeculateInt32Operand hash(this, node->child3());
12826
12827 GPRReg setGPR = set.gpr();
12828 GPRReg keyGPR = key.gpr();
12829 GPRReg hashGPR = hash.gpr();
12830
12831 speculateWeakSetObject(node->child1(), setGPR);
12832 speculateObject(node->child2(), keyGPR);
12833
12834 flushRegisters();
12835 callOperation(operationWeakSetAdd, setGPR, keyGPR, hashGPR);
12836 m_jit.exceptionCheck();
12837 noResult(node);
12838}
12839
12840void SpeculativeJIT::compileWeakMapSet(Node* node)
12841{
12842 SpeculateCellOperand map(this, m_jit.graph().varArgChild(node, 0));
12843 SpeculateCellOperand key(this, m_jit.graph().varArgChild(node, 1));
12844 JSValueOperand value(this, m_jit.graph().varArgChild(node, 2));
12845 SpeculateInt32Operand hash(this, m_jit.graph().varArgChild(node, 3));
12846
12847 GPRReg mapGPR = map.gpr();
12848 GPRReg keyGPR = key.gpr();
12849 JSValueRegs valueRegs = value.jsValueRegs();
12850 GPRReg hashGPR = hash.gpr();
12851
12852 speculateWeakMapObject(m_jit.graph().varArgChild(node, 0), mapGPR);
12853 speculateObject(m_jit.graph().varArgChild(node, 1), keyGPR);
12854
12855 flushRegisters();
12856 callOperation(operationWeakMapSet, mapGPR, keyGPR, valueRegs, hashGPR);
12857 m_jit.exceptionCheck();
12858 noResult(node);
12859}
12860
12861void SpeculativeJIT::compileGetPrototypeOf(Node* node)
12862{
12863 switch (node->child1().useKind()) {
12864 case ArrayUse:
12865 case FunctionUse:
12866 case FinalObjectUse: {
12867 SpeculateCellOperand object(this, node->child1());
12868 GPRTemporary temp(this);
12869 GPRTemporary temp2(this);
12870
12871 GPRReg objectGPR = object.gpr();
12872 GPRReg tempGPR = temp.gpr();
12873 GPRReg temp2GPR = temp2.gpr();
12874
12875 switch (node->child1().useKind()) {
12876 case ArrayUse:
12877 speculateArray(node->child1(), objectGPR);
12878 break;
12879 case FunctionUse:
12880 speculateFunction(node->child1(), objectGPR);
12881 break;
12882 case FinalObjectUse:
12883 speculateFinalObject(node->child1(), objectGPR);
12884 break;
12885 default:
12886 RELEASE_ASSERT_NOT_REACHED();
12887 break;
12888 }
12889
12890 m_jit.emitLoadStructure(*m_jit.vm(), objectGPR, tempGPR, temp2GPR);
12891
12892 AbstractValue& value = m_state.forNode(node->child1());
12893 if ((value.m_type && !(value.m_type & ~SpecObject)) && value.m_structure.isFinite()) {
12894 bool hasPolyProto = false;
12895 bool hasMonoProto = false;
12896 value.m_structure.forEach([&] (RegisteredStructure structure) {
12897 if (structure->hasPolyProto())
12898 hasPolyProto = true;
12899 else
12900 hasMonoProto = true;
12901 });
12902
12903 if (hasMonoProto && !hasPolyProto) {
12904#if USE(JSVALUE64)
12905 m_jit.load64(MacroAssembler::Address(tempGPR, Structure::prototypeOffset()), tempGPR);
12906 jsValueResult(tempGPR, node);
12907#else
12908 m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + TagOffset), temp2GPR);
12909 m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + PayloadOffset), tempGPR);
12910 jsValueResult(temp2GPR, tempGPR, node);
12911#endif
12912 return;
12913 }
12914
12915 if (hasPolyProto && !hasMonoProto) {
12916#if USE(JSVALUE64)
12917 m_jit.load64(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset)), tempGPR);
12918 jsValueResult(tempGPR, node);
12919#else
12920 m_jit.load32(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset) + TagOffset), temp2GPR);
12921 m_jit.load32(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset) + PayloadOffset), tempGPR);
12922 jsValueResult(temp2GPR, tempGPR, node);
12923#endif
12924 return;
12925 }
12926 }
12927
12928#if USE(JSVALUE64)
12929 m_jit.load64(MacroAssembler::Address(tempGPR, Structure::prototypeOffset()), tempGPR);
12930 auto hasMonoProto = m_jit.branchIfNotEmpty(tempGPR);
12931 m_jit.load64(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset)), tempGPR);
12932 hasMonoProto.link(&m_jit);
12933 jsValueResult(tempGPR, node);
12934#else
12935 m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + TagOffset), temp2GPR);
12936 m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + PayloadOffset), tempGPR);
12937 auto hasMonoProto = m_jit.branchIfNotEmpty(temp2GPR);
12938 m_jit.load32(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset) + TagOffset), temp2GPR);
12939 m_jit.load32(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset) + PayloadOffset), tempGPR);
12940 hasMonoProto.link(&m_jit);
12941 jsValueResult(temp2GPR, tempGPR, node);
12942#endif
12943 return;
12944 }
12945 case ObjectUse: {
12946 SpeculateCellOperand value(this, node->child1());
12947 JSValueRegsTemporary result(this);
12948
12949 GPRReg valueGPR = value.gpr();
12950 JSValueRegs resultRegs = result.regs();
12951
12952 speculateObject(node->child1(), valueGPR);
12953
12954 flushRegisters();
12955 callOperation(operationGetPrototypeOfObject, resultRegs, valueGPR);
12956 m_jit.exceptionCheck();
12957 jsValueResult(resultRegs, node);
12958 return;
12959 }
12960 default: {
12961 JSValueOperand value(this, node->child1());
12962 JSValueRegsTemporary result(this);
12963
12964 JSValueRegs valueRegs = value.jsValueRegs();
12965 JSValueRegs resultRegs = result.regs();
12966
12967 flushRegisters();
12968 callOperation(operationGetPrototypeOf, resultRegs, valueRegs);
12969 m_jit.exceptionCheck();
12970 jsValueResult(resultRegs, node);
12971 return;
12972 }
12973 }
12974}
12975
12976void SpeculativeJIT::compileIdentity(Node* node)
12977{
12978 speculate(node, node->child1());
12979 switch (node->child1().useKind()) {
12980#if USE(JSVALUE64)
12981 case DoubleRepAnyIntUse:
12982#endif
12983 case DoubleRepUse:
12984 case DoubleRepRealUse: {
12985 SpeculateDoubleOperand op(this, node->child1());
12986 FPRTemporary scratch(this, op);
12987 m_jit.moveDouble(op.fpr(), scratch.fpr());
12988 doubleResult(scratch.fpr(), node);
12989 break;
12990 }
12991#if USE(JSVALUE64)
12992 case Int52RepUse: {
12993 SpeculateInt52Operand op(this, node->child1());
12994 GPRTemporary result(this, Reuse, op);
12995 m_jit.move(op.gpr(), result.gpr());
12996 int52Result(result.gpr(), node);
12997 break;
12998 }
12999#endif
13000 default: {
13001 JSValueOperand op(this, node->child1(), ManualOperandSpeculation);
13002 JSValueRegsTemporary result(this, Reuse, op);
13003 JSValueRegs opRegs = op.jsValueRegs();
13004 JSValueRegs resultRegs = result.regs();
13005 m_jit.moveValueRegs(opRegs, resultRegs);
13006 jsValueResult(resultRegs, node);
13007 break;
13008 }
13009 }
13010}
13011
13012void SpeculativeJIT::compileMiscStrictEq(Node* node)
13013{
13014 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
13015 JSValueOperand op2(this, node->child2(), ManualOperandSpeculation);
13016 GPRTemporary result(this);
13017
13018 if (node->child1().useKind() == MiscUse)
13019 speculateMisc(node->child1(), op1.jsValueRegs());
13020 if (node->child2().useKind() == MiscUse)
13021 speculateMisc(node->child2(), op2.jsValueRegs());
13022
13023#if USE(JSVALUE64)
13024 m_jit.compare64(JITCompiler::Equal, op1.gpr(), op2.gpr(), result.gpr());
13025#else
13026 m_jit.move(TrustedImm32(0), result.gpr());
13027 JITCompiler::Jump notEqual = m_jit.branch32(JITCompiler::NotEqual, op1.tagGPR(), op2.tagGPR());
13028 m_jit.compare32(JITCompiler::Equal, op1.payloadGPR(), op2.payloadGPR(), result.gpr());
13029 notEqual.link(&m_jit);
13030#endif
13031 unblessedBooleanResult(result.gpr(), node);
13032}
13033
13034void SpeculativeJIT::emitInitializeButterfly(GPRReg storageGPR, GPRReg sizeGPR, JSValueRegs emptyValueRegs, GPRReg scratchGPR)
13035{
13036 m_jit.zeroExtend32ToPtr(sizeGPR, scratchGPR);
13037 MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratchGPR);
13038 MacroAssembler::Label loop = m_jit.label();
13039 m_jit.sub32(TrustedImm32(1), scratchGPR);
13040 m_jit.storeValue(emptyValueRegs, MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight));
13041 m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
13042 done.link(&m_jit);
13043}
13044
13045void SpeculativeJIT::compileAllocateNewArrayWithSize(JSGlobalObject* globalObject, GPRReg resultGPR, GPRReg sizeGPR, IndexingType indexingType, bool shouldConvertLargeSizeToArrayStorage)
13046{
13047 GPRTemporary storage(this);
13048 GPRTemporary scratch(this);
13049 GPRTemporary scratch2(this);
13050
13051 GPRReg storageGPR = storage.gpr();
13052 GPRReg scratchGPR = scratch.gpr();
13053 GPRReg scratch2GPR = scratch2.gpr();
13054
13055 m_jit.move(TrustedImmPtr(nullptr), storageGPR);
13056
13057 MacroAssembler::JumpList slowCases;
13058 if (shouldConvertLargeSizeToArrayStorage)
13059 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)));
13060#if !ASSERT_DISABLED
13061 else {
13062 MacroAssembler::Jump lengthIsWithinLimits;
13063 lengthIsWithinLimits = m_jit.branch32(MacroAssembler::Below, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH));
13064 m_jit.abortWithReason(UncheckedOverflow);
13065 lengthIsWithinLimits.link(&m_jit);
13066 }
13067#endif
13068
13069 // We can use resultGPR as a scratch right now.
13070 emitAllocateButterfly(storageGPR, sizeGPR, scratchGPR, scratch2GPR, resultGPR, slowCases);
13071
13072#if USE(JSVALUE64)
13073 JSValueRegs emptyValueRegs(scratchGPR);
13074 if (hasDouble(indexingType))
13075 m_jit.move(TrustedImm64(bitwise_cast<int64_t>(PNaN)), emptyValueRegs.gpr());
13076 else
13077 m_jit.move(TrustedImm64(JSValue::encode(JSValue())), emptyValueRegs.gpr());
13078#else
13079 JSValueRegs emptyValueRegs(scratchGPR, scratch2GPR);
13080 if (hasDouble(indexingType))
13081 m_jit.moveValue(JSValue(JSValue::EncodeAsDouble, PNaN), emptyValueRegs);
13082 else
13083 m_jit.moveValue(JSValue(), emptyValueRegs);
13084#endif
13085 emitInitializeButterfly(storageGPR, sizeGPR, emptyValueRegs, resultGPR);
13086
13087 RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType));
13088
13089 emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
13090
13091 m_jit.mutatorFence(*m_jit.vm());
13092
13093 addSlowPathGenerator(std::make_unique<CallArrayAllocatorWithVariableSizeSlowPathGenerator>(
13094 slowCases, this, operationNewArrayWithSize, resultGPR,
13095 structure,
13096 shouldConvertLargeSizeToArrayStorage ? m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)) : structure,
13097 sizeGPR, storageGPR));
13098}
13099
13100void SpeculativeJIT::compileHasIndexedProperty(Node* node)
13101{
13102 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
13103 SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 1));
13104 GPRTemporary result(this);
13105
13106 GPRReg baseGPR = base.gpr();
13107 GPRReg indexGPR = index.gpr();
13108 GPRReg resultGPR = result.gpr();
13109
13110 MacroAssembler::JumpList slowCases;
13111 ArrayMode mode = node->arrayMode();
13112 switch (mode.type()) {
13113 case Array::Int32:
13114 case Array::Contiguous: {
13115 ASSERT(!!m_graph.varArgChild(node, 2));
13116 StorageOperand storage(this, m_graph.varArgChild(node, 2));
13117 GPRTemporary scratch(this);
13118
13119 GPRReg storageGPR = storage.gpr();
13120 GPRReg scratchGPR = scratch.gpr();
13121
13122 MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
13123 if (mode.isInBounds())
13124 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, outOfBounds);
13125 else
13126 slowCases.append(outOfBounds);
13127
13128#if USE(JSVALUE64)
13129 m_jit.load64(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchGPR);
13130 slowCases.append(m_jit.branchIfEmpty(scratchGPR));
13131#else
13132 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR);
13133 slowCases.append(m_jit.branchIfEmpty(scratchGPR));
13134#endif
13135 m_jit.move(TrustedImm32(1), resultGPR);
13136 break;
13137 }
13138 case Array::Double: {
13139 ASSERT(!!m_graph.varArgChild(node, 2));
13140 StorageOperand storage(this, m_graph.varArgChild(node, 2));
13141 FPRTemporary scratch(this);
13142 FPRReg scratchFPR = scratch.fpr();
13143 GPRReg storageGPR = storage.gpr();
13144
13145 MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
13146 if (mode.isInBounds())
13147 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, outOfBounds);
13148 else
13149 slowCases.append(outOfBounds);
13150
13151 m_jit.loadDouble(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchFPR);
13152 slowCases.append(m_jit.branchIfNaN(scratchFPR));
13153 m_jit.move(TrustedImm32(1), resultGPR);
13154 break;
13155 }
13156 case Array::ArrayStorage: {
13157 ASSERT(!!m_graph.varArgChild(node, 2));
13158 StorageOperand storage(this, m_graph.varArgChild(node, 2));
13159 GPRTemporary scratch(this);
13160
13161 GPRReg storageGPR = storage.gpr();
13162 GPRReg scratchGPR = scratch.gpr();
13163
13164 MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
13165 if (mode.isInBounds())
13166 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, outOfBounds);
13167 else
13168 slowCases.append(outOfBounds);
13169
13170#if USE(JSVALUE64)
13171 m_jit.load64(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()), scratchGPR);
13172 slowCases.append(m_jit.branchIfEmpty(scratchGPR));
13173#else
13174 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR);
13175 slowCases.append(m_jit.branchIfEmpty(scratchGPR));
13176#endif
13177 m_jit.move(TrustedImm32(1), resultGPR);
13178 break;
13179 }
13180 default: {
13181 slowCases.append(m_jit.jump());
13182 break;
13183 }
13184 }
13185
13186 addSlowPathGenerator(slowPathCall(slowCases, this, operationHasIndexedPropertyByInt, resultGPR, baseGPR, indexGPR, static_cast<int32_t>(node->internalMethodType())));
13187
13188 unblessedBooleanResult(resultGPR, node);
13189}
13190
13191void SpeculativeJIT::compileGetDirectPname(Node* node)
13192{
13193 Edge& baseEdge = m_jit.graph().varArgChild(node, 0);
13194 Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
13195 Edge& indexEdge = m_jit.graph().varArgChild(node, 2);
13196
13197 SpeculateCellOperand base(this, baseEdge);
13198 SpeculateCellOperand property(this, propertyEdge);
13199 GPRReg baseGPR = base.gpr();
13200 GPRReg propertyGPR = property.gpr();
13201
13202#if CPU(X86)
13203 // Not enough registers on X86 for this code, so always use the slow path.
13204 speculate(node, indexEdge);
13205 flushRegisters();
13206 JSValueRegsFlushedCallResult result(this);
13207 JSValueRegs resultRegs = result.regs();
13208 callOperation(operationGetByValCell, resultRegs, baseGPR, CCallHelpers::CellValue(propertyGPR));
13209 m_jit.exceptionCheck();
13210 jsValueResult(resultRegs, node);
13211#else
13212 Edge& enumeratorEdge = m_jit.graph().varArgChild(node, 3);
13213 SpeculateStrictInt32Operand index(this, indexEdge);
13214 SpeculateCellOperand enumerator(this, enumeratorEdge);
13215 GPRTemporary scratch(this);
13216 JSValueRegsTemporary result(this);
13217
13218 GPRReg indexGPR = index.gpr();
13219 GPRReg enumeratorGPR = enumerator.gpr();
13220 GPRReg scratchGPR = scratch.gpr();
13221 JSValueRegs resultRegs = result.regs();
13222
13223 MacroAssembler::JumpList slowPath;
13224
13225 // Check the structure
13226 m_jit.load32(MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), scratchGPR);
13227 slowPath.append(
13228 m_jit.branch32(
13229 MacroAssembler::NotEqual,
13230 scratchGPR,
13231 MacroAssembler::Address(
13232 enumeratorGPR, JSPropertyNameEnumerator::cachedStructureIDOffset())));
13233
13234 // Compute the offset
13235 // If index is less than the enumerator's cached inline storage, then it's an inline access
13236 MacroAssembler::Jump outOfLineAccess = m_jit.branch32(MacroAssembler::AboveOrEqual,
13237 indexGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()));
13238
13239 m_jit.loadValue(MacroAssembler::BaseIndex(baseGPR, indexGPR, MacroAssembler::TimesEight, JSObject::offsetOfInlineStorage()), resultRegs);
13240
13241 MacroAssembler::Jump done = m_jit.jump();
13242
13243 // Otherwise it's out of line
13244 outOfLineAccess.link(&m_jit);
13245 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), resultRegs.payloadGPR());
13246 m_jit.move(indexGPR, scratchGPR);
13247 m_jit.sub32(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), scratchGPR);
13248 m_jit.neg32(scratchGPR);
13249 m_jit.signExtend32ToPtr(scratchGPR, scratchGPR);
13250 int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
13251 m_jit.loadValue(MacroAssembler::BaseIndex(resultRegs.payloadGPR(), scratchGPR, MacroAssembler::TimesEight, offsetOfFirstProperty), resultRegs);
13252
13253 done.link(&m_jit);
13254
13255 addSlowPathGenerator(slowPathCall(slowPath, this, operationGetByValCell, resultRegs, baseGPR, CCallHelpers::CellValue(propertyGPR)));
13256
13257 jsValueResult(resultRegs, node);
13258#endif
13259}
13260
13261void SpeculativeJIT::compileExtractCatchLocal(Node* node)
13262{
13263 JSValueRegsTemporary result(this);
13264 JSValueRegs resultRegs = result.regs();
13265
13266 JSValue* ptr = &reinterpret_cast<JSValue*>(m_jit.jitCode()->common.catchOSREntryBuffer->dataBuffer())[node->catchOSREntryIndex()];
13267 m_jit.loadValue(ptr, resultRegs);
13268 jsValueResult(resultRegs, node);
13269}
13270
13271void SpeculativeJIT::compileClearCatchLocals(Node* node)
13272{
13273 ScratchBuffer* scratchBuffer = m_jit.jitCode()->common.catchOSREntryBuffer;
13274 ASSERT(scratchBuffer);
13275 GPRTemporary scratch(this);
13276 GPRReg scratchGPR = scratch.gpr();
13277 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratchGPR);
13278 m_jit.storePtr(TrustedImmPtr(nullptr), scratchGPR);
13279 noResult(node);
13280}
13281
13282void SpeculativeJIT::compileProfileType(Node* node)
13283{
13284 JSValueOperand value(this, node->child1());
13285 GPRTemporary scratch1(this);
13286 GPRTemporary scratch2(this);
13287 GPRTemporary scratch3(this);
13288
13289 JSValueRegs valueRegs = value.jsValueRegs();
13290 GPRReg scratch1GPR = scratch1.gpr();
13291 GPRReg scratch2GPR = scratch2.gpr();
13292 GPRReg scratch3GPR = scratch3.gpr();
13293
13294 MacroAssembler::JumpList jumpToEnd;
13295
13296 jumpToEnd.append(m_jit.branchIfEmpty(valueRegs));
13297
13298 TypeLocation* cachedTypeLocation = node->typeLocation();
13299 // Compile in a predictive type check, if possible, to see if we can skip writing to the log.
13300 // These typechecks are inlined to match those of the 64-bit JSValue type checks.
13301 if (cachedTypeLocation->m_lastSeenType == TypeUndefined)
13302 jumpToEnd.append(m_jit.branchIfUndefined(valueRegs));
13303 else if (cachedTypeLocation->m_lastSeenType == TypeNull)
13304 jumpToEnd.append(m_jit.branchIfNull(valueRegs));
13305 else if (cachedTypeLocation->m_lastSeenType == TypeBoolean)
13306 jumpToEnd.append(m_jit.branchIfBoolean(valueRegs, scratch1GPR));
13307 else if (cachedTypeLocation->m_lastSeenType == TypeAnyInt)
13308 jumpToEnd.append(m_jit.branchIfInt32(valueRegs));
13309 else if (cachedTypeLocation->m_lastSeenType == TypeNumber)
13310 jumpToEnd.append(m_jit.branchIfNumber(valueRegs, scratch1GPR));
13311 else if (cachedTypeLocation->m_lastSeenType == TypeString) {
13312 MacroAssembler::Jump isNotCell = m_jit.branchIfNotCell(valueRegs);
13313 jumpToEnd.append(m_jit.branchIfString(valueRegs.payloadGPR()));
13314 isNotCell.link(&m_jit);
13315 }
13316
13317 // Load the TypeProfilerLog into Scratch2.
13318 TypeProfilerLog* cachedTypeProfilerLog = m_jit.vm()->typeProfilerLog();
13319 m_jit.move(TrustedImmPtr(cachedTypeProfilerLog), scratch2GPR);
13320
13321 // Load the next LogEntry into Scratch1.
13322 m_jit.loadPtr(MacroAssembler::Address(scratch2GPR, TypeProfilerLog::currentLogEntryOffset()), scratch1GPR);
13323
13324 // Store the JSValue onto the log entry.
13325 m_jit.storeValue(valueRegs, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::valueOffset()));
13326
13327 // Store the structureID of the cell if valueRegs is a cell, otherwise, store 0 on the log entry.
13328 MacroAssembler::Jump isNotCell = m_jit.branchIfNotCell(valueRegs);
13329 m_jit.load32(MacroAssembler::Address(valueRegs.payloadGPR(), JSCell::structureIDOffset()), scratch3GPR);
13330 m_jit.store32(scratch3GPR, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::structureIDOffset()));
13331 MacroAssembler::Jump skipIsCell = m_jit.jump();
13332 isNotCell.link(&m_jit);
13333 m_jit.store32(TrustedImm32(0), MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::structureIDOffset()));
13334 skipIsCell.link(&m_jit);
13335
13336 // Store the typeLocation on the log entry.
13337 m_jit.move(TrustedImmPtr(cachedTypeLocation), scratch3GPR);
13338 m_jit.storePtr(scratch3GPR, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::locationOffset()));
13339
13340 // Increment the current log entry.
13341 m_jit.addPtr(TrustedImm32(sizeof(TypeProfilerLog::LogEntry)), scratch1GPR);
13342 m_jit.storePtr(scratch1GPR, MacroAssembler::Address(scratch2GPR, TypeProfilerLog::currentLogEntryOffset()));
13343 MacroAssembler::Jump clearLog = m_jit.branchPtr(MacroAssembler::Equal, scratch1GPR, TrustedImmPtr(cachedTypeProfilerLog->logEndPtr()));
13344 addSlowPathGenerator(
13345 slowPathCall(clearLog, this, operationProcessTypeProfilerLogDFG, NoResult));
13346
13347 jumpToEnd.link(&m_jit);
13348
13349 noResult(node);
13350}
13351
13352void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, JSValueRegs valueRegs, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
13353{
13354 RegisterSet usedRegisters = this->usedRegisters();
13355 if (spillMode == DontSpill) {
13356 // We've already flushed registers to the stack, we don't need to spill these.
13357 usedRegisters.set(baseGPR, false);
13358 usedRegisters.set(valueRegs, false);
13359 }
13360 CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
13361 JITPutByIdGenerator gen(
13362 m_jit.codeBlock(), codeOrigin, callSite, usedRegisters,
13363 JSValueRegs::payloadOnly(baseGPR), valueRegs,
13364 scratchGPR, m_jit.ecmaModeFor(codeOrigin), putKind);
13365
13366 gen.generateFastPath(m_jit);
13367
13368 JITCompiler::JumpList slowCases;
13369 if (slowPathTarget.isSet())
13370 slowCases.append(slowPathTarget);
13371 slowCases.append(gen.slowPathJump());
13372
13373 auto slowPath = slowPathCall(
13374 slowCases, this, gen.slowPathFunction(), NoResult, gen.stubInfo(), valueRegs,
13375 CCallHelpers::CellValue(baseGPR), identifierUID(identifierNumber));
13376
13377 m_jit.addPutById(gen, slowPath.get());
13378 addSlowPathGenerator(WTFMove(slowPath));
13379}
13380
13381void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node* node, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
13382{
13383 ASSERT(node->isBinaryUseKind(UntypedUse));
13384 JSValueOperand arg1(this, node->child1());
13385 JSValueOperand arg2(this, node->child2());
13386
13387 JSValueRegs arg1Regs = arg1.jsValueRegs();
13388 JSValueRegs arg2Regs = arg2.jsValueRegs();
13389
13390 JITCompiler::JumpList slowPath;
13391
13392 if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) {
13393 GPRFlushedCallResult result(this);
13394 GPRReg resultGPR = result.gpr();
13395
13396 arg1.use();
13397 arg2.use();
13398
13399 flushRegisters();
13400 callOperation(helperFunction, resultGPR, arg1Regs, arg2Regs);
13401 m_jit.exceptionCheck();
13402
13403 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
13404 return;
13405 }
13406
13407 GPRTemporary result(this, Reuse, arg1, TagWord);
13408 GPRReg resultGPR = result.gpr();
13409
13410 arg1.use();
13411 arg2.use();
13412
13413 if (!isKnownInteger(node->child1().node()))
13414 slowPath.append(m_jit.branchIfNotInt32(arg1Regs));
13415 if (!isKnownInteger(node->child2().node()))
13416 slowPath.append(m_jit.branchIfNotInt32(arg2Regs));
13417
13418 m_jit.compare32(cond, arg1Regs.payloadGPR(), arg2Regs.payloadGPR(), resultGPR);
13419
13420 if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node()))
13421 addSlowPathGenerator(slowPathCall(slowPath, this, helperFunction, resultGPR, arg1Regs, arg2Regs));
13422
13423 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
13424}
13425
13426void SpeculativeJIT::nonSpeculativePeepholeBranch(Node* node, Node* branchNode, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
13427{
13428 BasicBlock* taken = branchNode->branchData()->taken.block;
13429 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
13430
13431 JITCompiler::ResultCondition callResultCondition = JITCompiler::NonZero;
13432
13433 // The branch instruction will branch to the taken block.
13434 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
13435 if (taken == nextBlock()) {
13436 cond = JITCompiler::invert(cond);
13437 callResultCondition = JITCompiler::Zero;
13438 BasicBlock* tmp = taken;
13439 taken = notTaken;
13440 notTaken = tmp;
13441 }
13442
13443 JSValueOperand arg1(this, node->child1());
13444 JSValueOperand arg2(this, node->child2());
13445 JSValueRegs arg1Regs = arg1.jsValueRegs();
13446 JSValueRegs arg2Regs = arg2.jsValueRegs();
13447
13448 JITCompiler::JumpList slowPath;
13449
13450 if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) {
13451 GPRFlushedCallResult result(this);
13452 GPRReg resultGPR = result.gpr();
13453
13454 arg1.use();
13455 arg2.use();
13456
13457 flushRegisters();
13458 callOperation(helperFunction, resultGPR, arg1Regs, arg2Regs);
13459 m_jit.exceptionCheck();
13460
13461 branchTest32(callResultCondition, resultGPR, taken);
13462 } else {
13463 GPRTemporary result(this, Reuse, arg2, TagWord);
13464 GPRReg resultGPR = result.gpr();
13465
13466 arg1.use();
13467 arg2.use();
13468
13469 if (!isKnownInteger(node->child1().node()))
13470 slowPath.append(m_jit.branchIfNotInt32(arg1Regs));
13471 if (!isKnownInteger(node->child2().node()))
13472 slowPath.append(m_jit.branchIfNotInt32(arg2Regs));
13473
13474 branch32(cond, arg1Regs.payloadGPR(), arg2Regs.payloadGPR(), taken);
13475
13476 if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node())) {
13477 jump(notTaken, ForceJump);
13478
13479 slowPath.link(&m_jit);
13480
13481 silentSpillAllRegisters(resultGPR);
13482 callOperation(helperFunction, resultGPR, arg1Regs, arg2Regs);
13483 silentFillAllRegisters();
13484 m_jit.exceptionCheck();
13485
13486 branchTest32(callResultCondition, resultGPR, taken);
13487 }
13488 }
13489
13490 jump(notTaken);
13491
13492 m_indexInBlock = m_block->size() - 1;
13493 m_currentNode = branchNode;
13494}
13495
13496void SpeculativeJIT::compileBigIntEquality(Node* node)
13497{
13498 // FIXME: [ESNext][BigInt] Create specialized version of strict equals for BigIntUse
13499 // https://bugs.webkit.org/show_bug.cgi?id=182895
13500 SpeculateCellOperand left(this, node->child1());
13501 SpeculateCellOperand right(this, node->child2());
13502 GPRTemporary result(this, Reuse, left);
13503 GPRReg leftGPR = left.gpr();
13504 GPRReg rightGPR = right.gpr();
13505 GPRReg resultGPR = result.gpr();
13506
13507 left.use();
13508 right.use();
13509
13510 speculateBigInt(node->child1(), leftGPR);
13511 speculateBigInt(node->child2(), rightGPR);
13512
13513 JITCompiler::Jump notEqualCase = m_jit.branchPtr(JITCompiler::NotEqual, leftGPR, rightGPR);
13514
13515 m_jit.move(JITCompiler::TrustedImm32(1), resultGPR);
13516
13517 JITCompiler::Jump done = m_jit.jump();
13518
13519 notEqualCase.link(&m_jit);
13520
13521 silentSpillAllRegisters(resultGPR);
13522 callOperation(operationCompareStrictEqCell, resultGPR, leftGPR, rightGPR);
13523 silentFillAllRegisters();
13524
13525 done.link(&m_jit);
13526
13527 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
13528}
13529
13530void SpeculativeJIT::compileMakeRope(Node* node)
13531{
13532 ASSERT(node->child1().useKind() == KnownStringUse);
13533 ASSERT(node->child2().useKind() == KnownStringUse);
13534 ASSERT(!node->child3() || node->child3().useKind() == KnownStringUse);
13535
13536 SpeculateCellOperand op1(this, node->child1());
13537 SpeculateCellOperand op2(this, node->child2());
13538 SpeculateCellOperand op3(this, node->child3());
13539 GPRReg opGPRs[3];
13540 unsigned numOpGPRs;
13541 opGPRs[0] = op1.gpr();
13542 opGPRs[1] = op2.gpr();
13543 if (node->child3()) {
13544 opGPRs[2] = op3.gpr();
13545 numOpGPRs = 3;
13546 } else {
13547 opGPRs[2] = InvalidGPRReg;
13548 numOpGPRs = 2;
13549 }
13550
13551#if CPU(ADDRESS64)
13552 Edge edges[3] = {
13553 node->child1(),
13554 node->child2(),
13555 node->child3()
13556 };
13557
13558 GPRTemporary result(this);
13559 GPRTemporary allocator(this);
13560 GPRTemporary scratch(this);
13561 GPRTemporary scratch2(this);
13562 GPRReg resultGPR = result.gpr();
13563 GPRReg allocatorGPR = allocator.gpr();
13564 GPRReg scratchGPR = scratch.gpr();
13565 GPRReg scratch2GPR = scratch2.gpr();
13566
13567 CCallHelpers::JumpList slowPath;
13568 Allocator allocatorValue = allocatorForNonVirtualConcurrently<JSRopeString>(*m_jit.vm(), sizeof(JSRopeString), AllocatorForMode::AllocatorIfExists);
13569 emitAllocateJSCell(resultGPR, JITAllocator::constant(allocatorValue), allocatorGPR, TrustedImmPtr(m_jit.graph().registerStructure(m_jit.vm()->stringStructure.get())), scratchGPR, slowPath);
13570
13571 // This puts nullptr for the first fiber. It makes visitChildren safe even if this JSRopeString is discarded due to the speculation failure in the following path.
13572 m_jit.storePtr(TrustedImmPtr(JSString::isRopeInPointer), CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber0()));
13573
13574 {
13575 if (JSString* string = edges[0]->dynamicCastConstant<JSString*>(*m_jit.vm())) {
13576 m_jit.move(TrustedImm32(string->is8Bit() ? StringImpl::flagIs8Bit() : 0), scratchGPR);
13577 m_jit.move(TrustedImm32(string->length()), allocatorGPR);
13578 } else {
13579 bool needsRopeCase = canBeRope(edges[0]);
13580 m_jit.loadPtr(CCallHelpers::Address(opGPRs[0], JSString::offsetOfValue()), scratch2GPR);
13581 CCallHelpers::Jump isRope;
13582 if (needsRopeCase)
13583 isRope = m_jit.branchIfRopeStringImpl(scratch2GPR);
13584
13585 m_jit.load32(CCallHelpers::Address(scratch2GPR, StringImpl::flagsOffset()), scratchGPR);
13586 m_jit.load32(CCallHelpers::Address(scratch2GPR, StringImpl::lengthMemoryOffset()), allocatorGPR);
13587
13588 if (needsRopeCase) {
13589 auto done = m_jit.jump();
13590
13591 isRope.link(&m_jit);
13592 m_jit.load32(CCallHelpers::Address(opGPRs[0], JSRopeString::offsetOfFlags()), scratchGPR);
13593 m_jit.load32(CCallHelpers::Address(opGPRs[0], JSRopeString::offsetOfLength()), allocatorGPR);
13594 done.link(&m_jit);
13595 }
13596 }
13597
13598 if (!ASSERT_DISABLED) {
13599 CCallHelpers::Jump ok = m_jit.branch32(
13600 CCallHelpers::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
13601 m_jit.abortWithReason(DFGNegativeStringLength);
13602 ok.link(&m_jit);
13603 }
13604 }
13605
13606 for (unsigned i = 1; i < numOpGPRs; ++i) {
13607 if (JSString* string = edges[i]->dynamicCastConstant<JSString*>(*m_jit.vm())) {
13608 m_jit.and32(TrustedImm32(string->is8Bit() ? StringImpl::flagIs8Bit() : 0), scratchGPR);
13609 speculationCheck(
13610 Uncountable, JSValueSource(), nullptr,
13611 m_jit.branchAdd32(
13612 CCallHelpers::Overflow,
13613 TrustedImm32(string->length()), allocatorGPR));
13614 } else {
13615 bool needsRopeCase = canBeRope(edges[i]);
13616 m_jit.loadPtr(CCallHelpers::Address(opGPRs[i], JSString::offsetOfValue()), scratch2GPR);
13617 CCallHelpers::Jump isRope;
13618 if (needsRopeCase)
13619 isRope = m_jit.branchIfRopeStringImpl(scratch2GPR);
13620
13621 m_jit.and32(CCallHelpers::Address(scratch2GPR, StringImpl::flagsOffset()), scratchGPR);
13622 speculationCheck(
13623 Uncountable, JSValueSource(), nullptr,
13624 m_jit.branchAdd32(
13625 CCallHelpers::Overflow,
13626 CCallHelpers::Address(scratch2GPR, StringImpl::lengthMemoryOffset()), allocatorGPR));
13627 if (needsRopeCase) {
13628 auto done = m_jit.jump();
13629
13630 isRope.link(&m_jit);
13631 m_jit.and32(CCallHelpers::Address(opGPRs[i], JSRopeString::offsetOfFlags()), scratchGPR);
13632 m_jit.load32(CCallHelpers::Address(opGPRs[i], JSRopeString::offsetOfLength()), scratch2GPR);
13633 speculationCheck(
13634 Uncountable, JSValueSource(), nullptr,
13635 m_jit.branchAdd32(
13636 CCallHelpers::Overflow, scratch2GPR, allocatorGPR));
13637 done.link(&m_jit);
13638 }
13639 }
13640 }
13641
13642 if (!ASSERT_DISABLED) {
13643 CCallHelpers::Jump ok = m_jit.branch32(
13644 CCallHelpers::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
13645 m_jit.abortWithReason(DFGNegativeStringLength);
13646 ok.link(&m_jit);
13647 }
13648
13649 static_assert(StringImpl::flagIs8Bit() == JSRopeString::is8BitInPointer, "");
13650 m_jit.and32(TrustedImm32(StringImpl::flagIs8Bit()), scratchGPR);
13651 m_jit.orPtr(opGPRs[0], scratchGPR);
13652 m_jit.orPtr(TrustedImmPtr(JSString::isRopeInPointer), scratchGPR);
13653 m_jit.storePtr(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber0()));
13654
13655 m_jit.move(opGPRs[1], scratchGPR);
13656 m_jit.lshiftPtr(TrustedImm32(32), scratchGPR);
13657 m_jit.orPtr(allocatorGPR, scratchGPR);
13658 m_jit.storePtr(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber1()));
13659
13660 if (numOpGPRs == 2) {
13661 m_jit.move(opGPRs[1], scratchGPR);
13662 m_jit.rshiftPtr(TrustedImm32(32), scratchGPR);
13663 m_jit.storePtr(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2()));
13664 } else {
13665 m_jit.move(opGPRs[1], scratchGPR);
13666 m_jit.rshiftPtr(TrustedImm32(32), scratchGPR);
13667 m_jit.move(opGPRs[2], scratch2GPR);
13668 m_jit.lshiftPtr(TrustedImm32(16), scratch2GPR);
13669 m_jit.orPtr(scratch2GPR, scratchGPR);
13670 m_jit.storePtr(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2()));
13671 }
13672
13673 auto isNonEmptyString = m_jit.branchTest32(CCallHelpers::NonZero, allocatorGPR);
13674
13675 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(&m_jit.graph().m_vm)), resultGPR);
13676
13677 isNonEmptyString.link(&m_jit);
13678 m_jit.mutatorFence(*m_jit.vm());
13679
13680 switch (numOpGPRs) {
13681 case 2:
13682 addSlowPathGenerator(slowPathCall(
13683 slowPath, this, operationMakeRope2, resultGPR, opGPRs[0], opGPRs[1]));
13684 break;
13685 case 3:
13686 addSlowPathGenerator(slowPathCall(
13687 slowPath, this, operationMakeRope3, resultGPR, opGPRs[0], opGPRs[1], opGPRs[2]));
13688 break;
13689 default:
13690 RELEASE_ASSERT_NOT_REACHED();
13691 break;
13692 }
13693
13694 cellResult(resultGPR, node);
13695#else
13696 flushRegisters();
13697 GPRFlushedCallResult result(this);
13698 GPRReg resultGPR = result.gpr();
13699 switch (numOpGPRs) {
13700 case 2:
13701 callOperation(operationMakeRope2, resultGPR, opGPRs[0], opGPRs[1]);
13702 m_jit.exceptionCheck();
13703 break;
13704 case 3:
13705 callOperation(operationMakeRope3, resultGPR, opGPRs[0], opGPRs[1], opGPRs[2]);
13706 m_jit.exceptionCheck();
13707 break;
13708 default:
13709 RELEASE_ASSERT_NOT_REACHED();
13710 break;
13711 }
13712
13713 cellResult(resultGPR, node);
13714#endif
13715}
13716
13717} } // namespace JSC::DFG
13718
13719#endif
13720