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 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 // 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::compileValuePow(Node* node)
5800{
5801 Edge& leftChild = node->child1();
5802 Edge& rightChild = node->child2();
5803
5804 if (node->binaryUseKind() == BigIntUse) {
5805 SpeculateCellOperand left(this, leftChild);
5806 SpeculateCellOperand right(this, rightChild);
5807 GPRReg leftGPR = left.gpr();
5808 GPRReg rightGPR = right.gpr();
5809
5810 speculateBigInt(leftChild, leftGPR);
5811 speculateBigInt(rightChild, rightGPR);
5812
5813 flushRegisters();
5814 GPRFlushedCallResult result(this);
5815 GPRReg resultGPR = result.gpr();
5816
5817 callOperation(operationPowBigInt, resultGPR, leftGPR, rightGPR);
5818
5819 m_jit.exceptionCheck();
5820 cellResult(resultGPR, node);
5821 return;
5822 }
5823
5824 DFG_ASSERT(m_jit.graph(), node, node->binaryUseKind() == UntypedUse, node->binaryUseKind());
5825
5826 JSValueOperand left(this, leftChild);
5827 JSValueOperand right(this, rightChild);
5828 JSValueRegs leftRegs = left.jsValueRegs();
5829 JSValueRegs rightRegs = right.jsValueRegs();
5830
5831 flushRegisters();
5832 JSValueRegsFlushedCallResult result(this);
5833 JSValueRegs resultRegs = result.regs();
5834 callOperation(operationValuePow, resultRegs, leftRegs, rightRegs);
5835 m_jit.exceptionCheck();
5836
5837 jsValueResult(resultRegs, node);
5838}
5839
5840void SpeculativeJIT::compileArithPow(Node* node)
5841{
5842 if (node->child2().useKind() == Int32Use) {
5843 SpeculateDoubleOperand xOperand(this, node->child1());
5844 SpeculateInt32Operand yOperand(this, node->child2());
5845 FPRReg xOperandfpr = xOperand.fpr();
5846 GPRReg yOperandGpr = yOperand.gpr();
5847 FPRTemporary yOperandfpr(this);
5848
5849 flushRegisters();
5850
5851 FPRResult result(this);
5852 FPRReg resultFpr = result.fpr();
5853
5854 FPRTemporary xOperandCopy(this);
5855 FPRReg xOperandCopyFpr = xOperandCopy.fpr();
5856 m_jit.moveDouble(xOperandfpr, xOperandCopyFpr);
5857
5858 GPRTemporary counter(this);
5859 GPRReg counterGpr = counter.gpr();
5860 m_jit.move(yOperandGpr, counterGpr);
5861
5862 MacroAssembler::Jump skipFallback = compileArithPowIntegerFastPath(m_jit, xOperandCopyFpr, counterGpr, resultFpr);
5863 m_jit.convertInt32ToDouble(yOperandGpr, yOperandfpr.fpr());
5864 callOperation(operationMathPow, resultFpr, xOperandfpr, yOperandfpr.fpr());
5865
5866 skipFallback.link(&m_jit);
5867 doubleResult(resultFpr, node);
5868 return;
5869 }
5870
5871 if (node->child2()->isDoubleConstant()) {
5872 double exponent = node->child2()->asNumber();
5873 static const double infinityConstant = std::numeric_limits<double>::infinity();
5874 static const double minusInfinityConstant = -std::numeric_limits<double>::infinity();
5875 if (exponent == 0.5) {
5876 SpeculateDoubleOperand xOperand(this, node->child1());
5877 FPRTemporary result(this);
5878 FPRReg xOperandFpr = xOperand.fpr();
5879 FPRReg resultFpr = result.fpr();
5880
5881 m_jit.moveZeroToDouble(resultFpr);
5882 MacroAssembler::Jump xIsZeroOrNegativeZero = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr);
5883
5884 m_jit.loadDouble(TrustedImmPtr(&minusInfinityConstant), resultFpr);
5885 MacroAssembler::Jump xIsMinusInfinity = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr);
5886 m_jit.sqrtDouble(xOperandFpr, resultFpr);
5887 MacroAssembler::Jump doneWithSqrt = m_jit.jump();
5888
5889 xIsMinusInfinity.link(&m_jit);
5890 if (isX86())
5891 m_jit.loadDouble(TrustedImmPtr(&infinityConstant), resultFpr);
5892 else
5893 m_jit.absDouble(resultFpr, resultFpr);
5894
5895 xIsZeroOrNegativeZero.link(&m_jit);
5896 doneWithSqrt.link(&m_jit);
5897 doubleResult(resultFpr, node);
5898 return;
5899 }
5900 if (exponent == -0.5) {
5901 SpeculateDoubleOperand xOperand(this, node->child1());
5902 FPRTemporary scratch(this);
5903 FPRTemporary result(this);
5904 FPRReg xOperandFpr = xOperand.fpr();
5905 FPRReg scratchFPR = scratch.fpr();
5906 FPRReg resultFpr = result.fpr();
5907
5908 m_jit.moveZeroToDouble(resultFpr);
5909 MacroAssembler::Jump xIsZeroOrNegativeZero = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr);
5910
5911 m_jit.loadDouble(TrustedImmPtr(&minusInfinityConstant), resultFpr);
5912 MacroAssembler::Jump xIsMinusInfinity = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr);
5913
5914 static const double oneConstant = 1.;
5915 m_jit.loadDouble(TrustedImmPtr(&oneConstant), resultFpr);
5916 m_jit.sqrtDouble(xOperandFpr, scratchFPR);
5917 m_jit.divDouble(resultFpr, scratchFPR, resultFpr);
5918 MacroAssembler::Jump doneWithSqrt = m_jit.jump();
5919
5920 xIsZeroOrNegativeZero.link(&m_jit);
5921 m_jit.loadDouble(TrustedImmPtr(&infinityConstant), resultFpr);
5922 MacroAssembler::Jump doneWithBaseZero = m_jit.jump();
5923
5924 xIsMinusInfinity.link(&m_jit);
5925 m_jit.moveZeroToDouble(resultFpr);
5926
5927 doneWithBaseZero.link(&m_jit);
5928 doneWithSqrt.link(&m_jit);
5929 doubleResult(resultFpr, node);
5930 return;
5931 }
5932 }
5933
5934 SpeculateDoubleOperand xOperand(this, node->child1());
5935 SpeculateDoubleOperand yOperand(this, node->child2());
5936 FPRReg xOperandfpr = xOperand.fpr();
5937 FPRReg yOperandfpr = yOperand.fpr();
5938
5939 flushRegisters();
5940
5941 FPRResult result(this);
5942 FPRReg resultFpr = result.fpr();
5943
5944 FPRTemporary xOperandCopy(this);
5945 FPRReg xOperandCopyFpr = xOperandCopy.fpr();
5946
5947 FPRTemporary scratch(this);
5948 FPRReg scratchFpr = scratch.fpr();
5949
5950 GPRTemporary yOperandInteger(this);
5951 GPRReg yOperandIntegerGpr = yOperandInteger.gpr();
5952 MacroAssembler::JumpList failedExponentConversionToInteger;
5953 m_jit.branchConvertDoubleToInt32(yOperandfpr, yOperandIntegerGpr, failedExponentConversionToInteger, scratchFpr, false);
5954
5955 m_jit.moveDouble(xOperandfpr, xOperandCopyFpr);
5956 MacroAssembler::Jump skipFallback = compileArithPowIntegerFastPath(m_jit, xOperandCopyFpr, yOperandInteger.gpr(), resultFpr);
5957 failedExponentConversionToInteger.link(&m_jit);
5958
5959 callOperation(operationMathPow, resultFpr, xOperandfpr, yOperandfpr);
5960 skipFallback.link(&m_jit);
5961 doubleResult(resultFpr, node);
5962}
5963
5964// Returns true if the compare is fused with a subsequent branch.
5965bool SpeculativeJIT::compare(Node* node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_JITOperation_EJJ operation)
5966{
5967 if (compilePeepHoleBranch(node, condition, doubleCondition, operation))
5968 return true;
5969
5970 if (node->isBinaryUseKind(Int32Use)) {
5971 compileInt32Compare(node, condition);
5972 return false;
5973 }
5974
5975#if USE(JSVALUE64)
5976 if (node->isBinaryUseKind(Int52RepUse)) {
5977 compileInt52Compare(node, condition);
5978 return false;
5979 }
5980#endif // USE(JSVALUE64)
5981
5982 if (node->isBinaryUseKind(DoubleRepUse)) {
5983 compileDoubleCompare(node, doubleCondition);
5984 return false;
5985 }
5986
5987 if (node->isBinaryUseKind(StringUse)) {
5988 if (node->op() == CompareEq)
5989 compileStringEquality(node);
5990 else
5991 compileStringCompare(node, condition);
5992 return false;
5993 }
5994
5995 if (node->isBinaryUseKind(StringIdentUse)) {
5996 if (node->op() == CompareEq)
5997 compileStringIdentEquality(node);
5998 else
5999 compileStringIdentCompare(node, condition);
6000 return false;
6001 }
6002
6003 if (node->op() == CompareEq) {
6004 if (node->isBinaryUseKind(BooleanUse)) {
6005 compileBooleanCompare(node, condition);
6006 return false;
6007 }
6008
6009 if (node->isBinaryUseKind(SymbolUse)) {
6010 compileSymbolEquality(node);
6011 return false;
6012 }
6013
6014 if (node->isBinaryUseKind(ObjectUse)) {
6015 compileObjectEquality(node);
6016 return false;
6017 }
6018
6019 if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse)) {
6020 compileObjectToObjectOrOtherEquality(node->child1(), node->child2());
6021 return false;
6022 }
6023
6024 if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) {
6025 compileObjectToObjectOrOtherEquality(node->child2(), node->child1());
6026 return false;
6027 }
6028
6029 if (!needsTypeCheck(node->child1(), SpecOther)) {
6030 nonSpeculativeNonPeepholeCompareNullOrUndefined(node->child2());
6031 return false;
6032 }
6033
6034 if (!needsTypeCheck(node->child2(), SpecOther)) {
6035 nonSpeculativeNonPeepholeCompareNullOrUndefined(node->child1());
6036 return false;
6037 }
6038 }
6039
6040 nonSpeculativeNonPeepholeCompare(node, condition, operation);
6041 return false;
6042}
6043
6044void SpeculativeJIT::compileCompareUnsigned(Node* node, MacroAssembler::RelationalCondition condition)
6045{
6046 compileInt32Compare(node, condition);
6047}
6048
6049bool SpeculativeJIT::compileStrictEq(Node* node)
6050{
6051 if (node->isBinaryUseKind(BooleanUse)) {
6052 unsigned branchIndexInBlock = detectPeepHoleBranch();
6053 if (branchIndexInBlock != UINT_MAX) {
6054 Node* branchNode = m_block->at(branchIndexInBlock);
6055 compilePeepHoleBooleanBranch(node, branchNode, MacroAssembler::Equal);
6056 use(node->child1());
6057 use(node->child2());
6058 m_indexInBlock = branchIndexInBlock;
6059 m_currentNode = branchNode;
6060 return true;
6061 }
6062 compileBooleanCompare(node, MacroAssembler::Equal);
6063 return false;
6064 }
6065
6066 if (node->isBinaryUseKind(Int32Use)) {
6067 unsigned branchIndexInBlock = detectPeepHoleBranch();
6068 if (branchIndexInBlock != UINT_MAX) {
6069 Node* branchNode = m_block->at(branchIndexInBlock);
6070 compilePeepHoleInt32Branch(node, branchNode, MacroAssembler::Equal);
6071 use(node->child1());
6072 use(node->child2());
6073 m_indexInBlock = branchIndexInBlock;
6074 m_currentNode = branchNode;
6075 return true;
6076 }
6077 compileInt32Compare(node, MacroAssembler::Equal);
6078 return false;
6079 }
6080
6081#if USE(JSVALUE64)
6082 if (node->isBinaryUseKind(Int52RepUse)) {
6083 unsigned branchIndexInBlock = detectPeepHoleBranch();
6084 if (branchIndexInBlock != UINT_MAX) {
6085 Node* branchNode = m_block->at(branchIndexInBlock);
6086 compilePeepHoleInt52Branch(node, branchNode, MacroAssembler::Equal);
6087 use(node->child1());
6088 use(node->child2());
6089 m_indexInBlock = branchIndexInBlock;
6090 m_currentNode = branchNode;
6091 return true;
6092 }
6093 compileInt52Compare(node, MacroAssembler::Equal);
6094 return false;
6095 }
6096#endif // USE(JSVALUE64)
6097
6098 if (node->isBinaryUseKind(DoubleRepUse)) {
6099 unsigned branchIndexInBlock = detectPeepHoleBranch();
6100 if (branchIndexInBlock != UINT_MAX) {
6101 Node* branchNode = m_block->at(branchIndexInBlock);
6102 compilePeepHoleDoubleBranch(node, branchNode, MacroAssembler::DoubleEqual);
6103 use(node->child1());
6104 use(node->child2());
6105 m_indexInBlock = branchIndexInBlock;
6106 m_currentNode = branchNode;
6107 return true;
6108 }
6109 compileDoubleCompare(node, MacroAssembler::DoubleEqual);
6110 return false;
6111 }
6112
6113 if (node->isBinaryUseKind(SymbolUse)) {
6114 unsigned branchIndexInBlock = detectPeepHoleBranch();
6115 if (branchIndexInBlock != UINT_MAX) {
6116 Node* branchNode = m_block->at(branchIndexInBlock);
6117 compilePeepHoleSymbolEquality(node, branchNode);
6118 use(node->child1());
6119 use(node->child2());
6120 m_indexInBlock = branchIndexInBlock;
6121 m_currentNode = branchNode;
6122 return true;
6123 }
6124 compileSymbolEquality(node);
6125 return false;
6126 }
6127
6128 if (node->isBinaryUseKind(BigIntUse)) {
6129 compileBigIntEquality(node);
6130 return false;
6131 }
6132
6133 if (node->isBinaryUseKind(SymbolUse, UntypedUse)) {
6134 compileSymbolUntypedEquality(node, node->child1(), node->child2());
6135 return false;
6136 }
6137
6138 if (node->isBinaryUseKind(UntypedUse, SymbolUse)) {
6139 compileSymbolUntypedEquality(node, node->child2(), node->child1());
6140 return false;
6141 }
6142
6143 if (node->isBinaryUseKind(StringUse)) {
6144 compileStringEquality(node);
6145 return false;
6146 }
6147
6148 if (node->isBinaryUseKind(StringIdentUse)) {
6149 compileStringIdentEquality(node);
6150 return false;
6151 }
6152
6153 if (node->isBinaryUseKind(ObjectUse, UntypedUse)) {
6154 unsigned branchIndexInBlock = detectPeepHoleBranch();
6155 if (branchIndexInBlock != UINT_MAX) {
6156 Node* branchNode = m_block->at(branchIndexInBlock);
6157 compilePeepHoleObjectStrictEquality(node->child1(), node->child2(), branchNode);
6158 use(node->child1());
6159 use(node->child2());
6160 m_indexInBlock = branchIndexInBlock;
6161 m_currentNode = branchNode;
6162 return true;
6163 }
6164 compileObjectStrictEquality(node->child1(), node->child2());
6165 return false;
6166 }
6167
6168 if (node->isBinaryUseKind(UntypedUse, ObjectUse)) {
6169 unsigned branchIndexInBlock = detectPeepHoleBranch();
6170 if (branchIndexInBlock != UINT_MAX) {
6171 Node* branchNode = m_block->at(branchIndexInBlock);
6172 compilePeepHoleObjectStrictEquality(node->child2(), node->child1(), branchNode);
6173 use(node->child1());
6174 use(node->child2());
6175 m_indexInBlock = branchIndexInBlock;
6176 m_currentNode = branchNode;
6177 return true;
6178 }
6179 compileObjectStrictEquality(node->child2(), node->child1());
6180 return false;
6181 }
6182
6183 if (node->isBinaryUseKind(ObjectUse)) {
6184 unsigned branchIndexInBlock = detectPeepHoleBranch();
6185 if (branchIndexInBlock != UINT_MAX) {
6186 Node* branchNode = m_block->at(branchIndexInBlock);
6187 compilePeepHoleObjectEquality(node, branchNode);
6188 use(node->child1());
6189 use(node->child2());
6190 m_indexInBlock = branchIndexInBlock;
6191 m_currentNode = branchNode;
6192 return true;
6193 }
6194 compileObjectEquality(node);
6195 return false;
6196 }
6197
6198 if (node->isBinaryUseKind(MiscUse, UntypedUse)
6199 || node->isBinaryUseKind(UntypedUse, MiscUse)) {
6200 compileMiscStrictEq(node);
6201 return false;
6202 }
6203
6204 if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse)) {
6205 compileStringIdentToNotStringVarEquality(node, node->child1(), node->child2());
6206 return false;
6207 }
6208
6209 if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse)) {
6210 compileStringIdentToNotStringVarEquality(node, node->child2(), node->child1());
6211 return false;
6212 }
6213
6214 if (node->isBinaryUseKind(StringUse, UntypedUse)) {
6215 compileStringToUntypedEquality(node, node->child1(), node->child2());
6216 return false;
6217 }
6218
6219 if (node->isBinaryUseKind(UntypedUse, StringUse)) {
6220 compileStringToUntypedEquality(node, node->child2(), node->child1());
6221 return false;
6222 }
6223
6224 RELEASE_ASSERT(node->isBinaryUseKind(UntypedUse));
6225 return nonSpeculativeStrictEq(node);
6226}
6227
6228void SpeculativeJIT::compileBooleanCompare(Node* node, MacroAssembler::RelationalCondition condition)
6229{
6230 SpeculateBooleanOperand op1(this, node->child1());
6231 SpeculateBooleanOperand op2(this, node->child2());
6232 GPRTemporary result(this);
6233
6234 m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());
6235
6236 unblessedBooleanResult(result.gpr(), node);
6237}
6238
6239void SpeculativeJIT::compileInt32Compare(Node* node, MacroAssembler::RelationalCondition condition)
6240{
6241 if (node->child1()->isInt32Constant()) {
6242 SpeculateInt32Operand op2(this, node->child2());
6243 GPRTemporary result(this, Reuse, op2);
6244 int32_t imm = node->child1()->asInt32();
6245 m_jit.compare32(condition, JITCompiler::Imm32(imm), op2.gpr(), result.gpr());
6246
6247 unblessedBooleanResult(result.gpr(), node);
6248 } else if (node->child2()->isInt32Constant()) {
6249 SpeculateInt32Operand op1(this, node->child1());
6250 GPRTemporary result(this, Reuse, op1);
6251 int32_t imm = node->child2()->asInt32();
6252 m_jit.compare32(condition, op1.gpr(), JITCompiler::Imm32(imm), result.gpr());
6253
6254 unblessedBooleanResult(result.gpr(), node);
6255 } else {
6256 SpeculateInt32Operand op1(this, node->child1());
6257 SpeculateInt32Operand op2(this, node->child2());
6258 GPRTemporary result(this, Reuse, op1, op2);
6259 m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());
6260
6261 unblessedBooleanResult(result.gpr(), node);
6262 }
6263}
6264
6265void SpeculativeJIT::compileDoubleCompare(Node* node, MacroAssembler::DoubleCondition condition)
6266{
6267 SpeculateDoubleOperand op1(this, node->child1());
6268 SpeculateDoubleOperand op2(this, node->child2());
6269 GPRTemporary result(this);
6270
6271 FPRReg op1FPR = op1.fpr();
6272 FPRReg op2FPR = op2.fpr();
6273 GPRReg resultGPR = result.gpr();
6274
6275 m_jit.compareDouble(condition, op1FPR, op2FPR, resultGPR);
6276
6277 unblessedBooleanResult(resultGPR, node);
6278}
6279
6280void SpeculativeJIT::compileObjectEquality(Node* node)
6281{
6282 SpeculateCellOperand op1(this, node->child1());
6283 SpeculateCellOperand op2(this, node->child2());
6284 GPRTemporary result(this, Reuse, op1);
6285
6286 GPRReg op1GPR = op1.gpr();
6287 GPRReg op2GPR = op2.gpr();
6288 GPRReg resultGPR = result.gpr();
6289
6290 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
6291 DFG_TYPE_CHECK(
6292 JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchIfNotObject(op1GPR));
6293 DFG_TYPE_CHECK(
6294 JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchIfNotObject(op2GPR));
6295 } else {
6296 DFG_TYPE_CHECK(
6297 JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchIfNotObject(op1GPR));
6298 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
6299 m_jit.branchTest8(
6300 MacroAssembler::NonZero,
6301 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
6302 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
6303
6304 DFG_TYPE_CHECK(
6305 JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchIfNotObject(op2GPR));
6306 speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
6307 m_jit.branchTest8(
6308 MacroAssembler::NonZero,
6309 MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()),
6310 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
6311 }
6312
6313 m_jit.comparePtr(MacroAssembler::Equal, op1GPR, op2GPR, resultGPR);
6314 unblessedBooleanResult(resultGPR, node);
6315}
6316
6317void SpeculativeJIT::compileSymbolEquality(Node* node)
6318{
6319 SpeculateCellOperand left(this, node->child1());
6320 SpeculateCellOperand right(this, node->child2());
6321 GPRTemporary result(this, Reuse, left, right);
6322
6323 GPRReg leftGPR = left.gpr();
6324 GPRReg rightGPR = right.gpr();
6325 GPRReg resultGPR = result.gpr();
6326
6327 speculateSymbol(node->child1(), leftGPR);
6328 speculateSymbol(node->child2(), rightGPR);
6329
6330 m_jit.comparePtr(JITCompiler::Equal, leftGPR, rightGPR, resultGPR);
6331 unblessedBooleanResult(resultGPR, node);
6332}
6333
6334void SpeculativeJIT::compilePeepHoleSymbolEquality(Node* node, Node* branchNode)
6335{
6336 SpeculateCellOperand left(this, node->child1());
6337 SpeculateCellOperand right(this, node->child2());
6338
6339 GPRReg leftGPR = left.gpr();
6340 GPRReg rightGPR = right.gpr();
6341
6342 speculateSymbol(node->child1(), leftGPR);
6343 speculateSymbol(node->child2(), rightGPR);
6344
6345 BasicBlock* taken = branchNode->branchData()->taken.block;
6346 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
6347
6348 if (taken == nextBlock()) {
6349 branchPtr(JITCompiler::NotEqual, leftGPR, rightGPR, notTaken);
6350 jump(taken);
6351 } else {
6352 branchPtr(JITCompiler::Equal, leftGPR, rightGPR, taken);
6353 jump(notTaken);
6354 }
6355}
6356
6357void SpeculativeJIT::compileStringEquality(
6358 Node* node, GPRReg leftGPR, GPRReg rightGPR, GPRReg lengthGPR, GPRReg leftTempGPR,
6359 GPRReg rightTempGPR, GPRReg leftTemp2GPR, GPRReg rightTemp2GPR,
6360 const JITCompiler::JumpList& fastTrue, const JITCompiler::JumpList& fastFalse)
6361{
6362 JITCompiler::JumpList trueCase;
6363 JITCompiler::JumpList falseCase;
6364 JITCompiler::JumpList slowCase;
6365
6366 trueCase.append(fastTrue);
6367 falseCase.append(fastFalse);
6368
6369 m_jit.loadPtr(MacroAssembler::Address(leftGPR, JSString::offsetOfValue()), leftTempGPR);
6370 m_jit.loadPtr(MacroAssembler::Address(rightGPR, JSString::offsetOfValue()), rightTempGPR);
6371
6372 slowCase.append(m_jit.branchIfRopeStringImpl(leftTempGPR));
6373 slowCase.append(m_jit.branchIfRopeStringImpl(rightTempGPR));
6374
6375 m_jit.load32(MacroAssembler::Address(leftTempGPR, StringImpl::lengthMemoryOffset()), lengthGPR);
6376
6377 falseCase.append(m_jit.branch32(
6378 MacroAssembler::NotEqual,
6379 MacroAssembler::Address(rightTempGPR, StringImpl::lengthMemoryOffset()),
6380 lengthGPR));
6381
6382 trueCase.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR));
6383
6384 slowCase.append(m_jit.branchTest32(
6385 MacroAssembler::Zero,
6386 MacroAssembler::Address(leftTempGPR, StringImpl::flagsOffset()),
6387 TrustedImm32(StringImpl::flagIs8Bit())));
6388 slowCase.append(m_jit.branchTest32(
6389 MacroAssembler::Zero,
6390 MacroAssembler::Address(rightTempGPR, StringImpl::flagsOffset()),
6391 TrustedImm32(StringImpl::flagIs8Bit())));
6392
6393 m_jit.loadPtr(MacroAssembler::Address(leftTempGPR, StringImpl::dataOffset()), leftTempGPR);
6394 m_jit.loadPtr(MacroAssembler::Address(rightTempGPR, StringImpl::dataOffset()), rightTempGPR);
6395
6396 MacroAssembler::Label loop = m_jit.label();
6397
6398 m_jit.sub32(TrustedImm32(1), lengthGPR);
6399
6400 // This isn't going to generate the best code on x86. But that's OK, it's still better
6401 // than not inlining.
6402 m_jit.load8(MacroAssembler::BaseIndex(leftTempGPR, lengthGPR, MacroAssembler::TimesOne), leftTemp2GPR);
6403 m_jit.load8(MacroAssembler::BaseIndex(rightTempGPR, lengthGPR, MacroAssembler::TimesOne), rightTemp2GPR);
6404 falseCase.append(m_jit.branch32(MacroAssembler::NotEqual, leftTemp2GPR, rightTemp2GPR));
6405
6406 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loop, &m_jit);
6407
6408 trueCase.link(&m_jit);
6409 moveTrueTo(leftTempGPR);
6410
6411 JITCompiler::Jump done = m_jit.jump();
6412
6413 falseCase.link(&m_jit);
6414 moveFalseTo(leftTempGPR);
6415
6416 done.link(&m_jit);
6417 addSlowPathGenerator(
6418 slowPathCall(
6419 slowCase, this, operationCompareStringEq, leftTempGPR, leftGPR, rightGPR));
6420
6421 blessedBooleanResult(leftTempGPR, node);
6422}
6423
6424void SpeculativeJIT::compileStringEquality(Node* node)
6425{
6426 SpeculateCellOperand left(this, node->child1());
6427 SpeculateCellOperand right(this, node->child2());
6428 GPRTemporary length(this);
6429 GPRTemporary leftTemp(this);
6430 GPRTemporary rightTemp(this);
6431 GPRTemporary leftTemp2(this, Reuse, left);
6432 GPRTemporary rightTemp2(this, Reuse, right);
6433
6434 GPRReg leftGPR = left.gpr();
6435 GPRReg rightGPR = right.gpr();
6436 GPRReg lengthGPR = length.gpr();
6437 GPRReg leftTempGPR = leftTemp.gpr();
6438 GPRReg rightTempGPR = rightTemp.gpr();
6439 GPRReg leftTemp2GPR = leftTemp2.gpr();
6440 GPRReg rightTemp2GPR = rightTemp2.gpr();
6441
6442 speculateString(node->child1(), leftGPR);
6443
6444 // It's safe to branch around the type check below, since proving that the values are
6445 // equal does indeed prove that the right value is a string.
6446 JITCompiler::Jump fastTrue = m_jit.branchPtr(MacroAssembler::Equal, leftGPR, rightGPR);
6447
6448 speculateString(node->child2(), rightGPR);
6449
6450 compileStringEquality(
6451 node, leftGPR, rightGPR, lengthGPR, leftTempGPR, rightTempGPR, leftTemp2GPR,
6452 rightTemp2GPR, fastTrue, JITCompiler::Jump());
6453}
6454
6455void SpeculativeJIT::compileStringToUntypedEquality(Node* node, Edge stringEdge, Edge untypedEdge)
6456{
6457 SpeculateCellOperand left(this, stringEdge);
6458 JSValueOperand right(this, untypedEdge, ManualOperandSpeculation);
6459 GPRTemporary length(this);
6460 GPRTemporary leftTemp(this);
6461 GPRTemporary rightTemp(this);
6462 GPRTemporary leftTemp2(this, Reuse, left);
6463 GPRTemporary rightTemp2(this);
6464
6465 GPRReg leftGPR = left.gpr();
6466 JSValueRegs rightRegs = right.jsValueRegs();
6467 GPRReg lengthGPR = length.gpr();
6468 GPRReg leftTempGPR = leftTemp.gpr();
6469 GPRReg rightTempGPR = rightTemp.gpr();
6470 GPRReg leftTemp2GPR = leftTemp2.gpr();
6471 GPRReg rightTemp2GPR = rightTemp2.gpr();
6472
6473 speculateString(stringEdge, leftGPR);
6474
6475 JITCompiler::JumpList fastTrue;
6476 JITCompiler::JumpList fastFalse;
6477
6478 fastFalse.append(m_jit.branchIfNotCell(rightRegs));
6479
6480 // It's safe to branch around the type check below, since proving that the values are
6481 // equal does indeed prove that the right value is a string.
6482 fastTrue.append(m_jit.branchPtr(
6483 MacroAssembler::Equal, leftGPR, rightRegs.payloadGPR()));
6484
6485 fastFalse.append(m_jit.branchIfNotString(rightRegs.payloadGPR()));
6486
6487 compileStringEquality(
6488 node, leftGPR, rightRegs.payloadGPR(), lengthGPR, leftTempGPR, rightTempGPR, leftTemp2GPR,
6489 rightTemp2GPR, fastTrue, fastFalse);
6490}
6491
6492void SpeculativeJIT::compileStringIdentEquality(Node* node)
6493{
6494 SpeculateCellOperand left(this, node->child1());
6495 SpeculateCellOperand right(this, node->child2());
6496 GPRTemporary leftTemp(this);
6497 GPRTemporary rightTemp(this);
6498
6499 GPRReg leftGPR = left.gpr();
6500 GPRReg rightGPR = right.gpr();
6501 GPRReg leftTempGPR = leftTemp.gpr();
6502 GPRReg rightTempGPR = rightTemp.gpr();
6503
6504 speculateString(node->child1(), leftGPR);
6505 speculateString(node->child2(), rightGPR);
6506
6507 speculateStringIdentAndLoadStorage(node->child1(), leftGPR, leftTempGPR);
6508 speculateStringIdentAndLoadStorage(node->child2(), rightGPR, rightTempGPR);
6509
6510 m_jit.comparePtr(MacroAssembler::Equal, leftTempGPR, rightTempGPR, leftTempGPR);
6511
6512 unblessedBooleanResult(leftTempGPR, node);
6513}
6514
6515void SpeculativeJIT::compileStringIdentToNotStringVarEquality(
6516 Node* node, Edge stringEdge, Edge notStringVarEdge)
6517{
6518 SpeculateCellOperand left(this, stringEdge);
6519 JSValueOperand right(this, notStringVarEdge, ManualOperandSpeculation);
6520 GPRTemporary leftTemp(this);
6521 GPRTemporary rightTemp(this);
6522 GPRReg leftTempGPR = leftTemp.gpr();
6523 GPRReg rightTempGPR = rightTemp.gpr();
6524 GPRReg leftGPR = left.gpr();
6525 JSValueRegs rightRegs = right.jsValueRegs();
6526
6527 speculateString(stringEdge, leftGPR);
6528 speculateStringIdentAndLoadStorage(stringEdge, leftGPR, leftTempGPR);
6529
6530 moveFalseTo(rightTempGPR);
6531 JITCompiler::JumpList notString;
6532 notString.append(m_jit.branchIfNotCell(rightRegs));
6533 notString.append(m_jit.branchIfNotString(rightRegs.payloadGPR()));
6534
6535 speculateStringIdentAndLoadStorage(notStringVarEdge, rightRegs.payloadGPR(), rightTempGPR);
6536
6537 m_jit.comparePtr(MacroAssembler::Equal, leftTempGPR, rightTempGPR, rightTempGPR);
6538 notString.link(&m_jit);
6539
6540 unblessedBooleanResult(rightTempGPR, node);
6541}
6542
6543void SpeculativeJIT::compileStringCompare(Node* node, MacroAssembler::RelationalCondition condition)
6544{
6545 SpeculateCellOperand left(this, node->child1());
6546 SpeculateCellOperand right(this, node->child2());
6547 GPRReg leftGPR = left.gpr();
6548 GPRReg rightGPR = right.gpr();
6549
6550 speculateString(node->child1(), leftGPR);
6551 speculateString(node->child2(), rightGPR);
6552
6553 C_JITOperation_B_EJssJss compareFunction = nullptr;
6554 if (condition == MacroAssembler::LessThan)
6555 compareFunction = operationCompareStringLess;
6556 else if (condition == MacroAssembler::LessThanOrEqual)
6557 compareFunction = operationCompareStringLessEq;
6558 else if (condition == MacroAssembler::GreaterThan)
6559 compareFunction = operationCompareStringGreater;
6560 else if (condition == MacroAssembler::GreaterThanOrEqual)
6561 compareFunction = operationCompareStringGreaterEq;
6562 else
6563 RELEASE_ASSERT_NOT_REACHED();
6564
6565 GPRFlushedCallResult result(this);
6566 GPRReg resultGPR = result.gpr();
6567
6568 flushRegisters();
6569 callOperation(compareFunction, resultGPR, leftGPR, rightGPR);
6570 m_jit.exceptionCheck();
6571
6572 unblessedBooleanResult(resultGPR, node);
6573}
6574
6575void SpeculativeJIT::compileStringIdentCompare(Node* node, MacroAssembler::RelationalCondition condition)
6576{
6577 SpeculateCellOperand left(this, node->child1());
6578 SpeculateCellOperand right(this, node->child2());
6579 GPRFlushedCallResult result(this);
6580 GPRTemporary leftTemp(this);
6581 GPRTemporary rightTemp(this);
6582
6583 GPRReg leftGPR = left.gpr();
6584 GPRReg rightGPR = right.gpr();
6585 GPRReg resultGPR = result.gpr();
6586 GPRReg leftTempGPR = leftTemp.gpr();
6587 GPRReg rightTempGPR = rightTemp.gpr();
6588
6589 speculateString(node->child1(), leftGPR);
6590 speculateString(node->child2(), rightGPR);
6591
6592 C_JITOperation_TT compareFunction = nullptr;
6593 if (condition == MacroAssembler::LessThan)
6594 compareFunction = operationCompareStringImplLess;
6595 else if (condition == MacroAssembler::LessThanOrEqual)
6596 compareFunction = operationCompareStringImplLessEq;
6597 else if (condition == MacroAssembler::GreaterThan)
6598 compareFunction = operationCompareStringImplGreater;
6599 else if (condition == MacroAssembler::GreaterThanOrEqual)
6600 compareFunction = operationCompareStringImplGreaterEq;
6601 else
6602 RELEASE_ASSERT_NOT_REACHED();
6603
6604 speculateStringIdentAndLoadStorage(node->child1(), leftGPR, leftTempGPR);
6605 speculateStringIdentAndLoadStorage(node->child2(), rightGPR, rightTempGPR);
6606
6607 flushRegisters();
6608 callOperation(compareFunction, resultGPR, leftTempGPR, rightTempGPR);
6609
6610 unblessedBooleanResult(resultGPR, node);
6611}
6612
6613void SpeculativeJIT::compileSameValue(Node* node)
6614{
6615 if (node->isBinaryUseKind(DoubleRepUse)) {
6616 SpeculateDoubleOperand arg1(this, node->child1());
6617 SpeculateDoubleOperand arg2(this, node->child2());
6618 GPRTemporary result(this);
6619 GPRTemporary temp(this);
6620 GPRTemporary temp2(this);
6621
6622 FPRReg arg1FPR = arg1.fpr();
6623 FPRReg arg2FPR = arg2.fpr();
6624 GPRReg resultGPR = result.gpr();
6625 GPRReg tempGPR = temp.gpr();
6626 GPRReg temp2GPR = temp2.gpr();
6627
6628#if USE(JSVALUE64)
6629 m_jit.moveDoubleTo64(arg1FPR, tempGPR);
6630 m_jit.moveDoubleTo64(arg2FPR, temp2GPR);
6631 auto trueCase = m_jit.branch64(CCallHelpers::Equal, tempGPR, temp2GPR);
6632#else
6633 GPRTemporary temp3(this);
6634 GPRReg temp3GPR = temp3.gpr();
6635
6636 m_jit.moveDoubleToInts(arg1FPR, tempGPR, temp2GPR);
6637 m_jit.moveDoubleToInts(arg2FPR, temp3GPR, resultGPR);
6638 auto notEqual = m_jit.branch32(CCallHelpers::NotEqual, tempGPR, temp3GPR);
6639 auto trueCase = m_jit.branch32(CCallHelpers::Equal, temp2GPR, resultGPR);
6640 notEqual.link(&m_jit);
6641#endif
6642
6643 m_jit.compareDouble(CCallHelpers::DoubleNotEqualOrUnordered, arg1FPR, arg1FPR, tempGPR);
6644 m_jit.compareDouble(CCallHelpers::DoubleNotEqualOrUnordered, arg2FPR, arg2FPR, temp2GPR);
6645 m_jit.and32(tempGPR, temp2GPR, resultGPR);
6646 auto done = m_jit.jump();
6647
6648 trueCase.link(&m_jit);
6649 m_jit.move(CCallHelpers::TrustedImm32(1), resultGPR);
6650 done.link(&m_jit);
6651
6652 unblessedBooleanResult(resultGPR, node);
6653 return;
6654 }
6655
6656 ASSERT(node->isBinaryUseKind(UntypedUse));
6657
6658 JSValueOperand arg1(this, node->child1());
6659 JSValueOperand arg2(this, node->child2());
6660 JSValueRegs arg1Regs = arg1.jsValueRegs();
6661 JSValueRegs arg2Regs = arg2.jsValueRegs();
6662
6663 arg1.use();
6664 arg2.use();
6665
6666 flushRegisters();
6667
6668 GPRFlushedCallResult result(this);
6669 GPRReg resultGPR = result.gpr();
6670 callOperation(operationSameValue, resultGPR, arg1Regs, arg2Regs);
6671 m_jit.exceptionCheck();
6672
6673 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
6674}
6675
6676void SpeculativeJIT::compileStringZeroLength(Node* node)
6677{
6678 SpeculateCellOperand str(this, node->child1());
6679 GPRReg strGPR = str.gpr();
6680
6681 // Make sure that this is a string.
6682 speculateString(node->child1(), strGPR);
6683
6684 GPRTemporary eq(this);
6685 GPRReg eqGPR = eq.gpr();
6686
6687 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), eqGPR);
6688 m_jit.comparePtr(CCallHelpers::Equal, strGPR, eqGPR, eqGPR);
6689 unblessedBooleanResult(eqGPR, node);
6690}
6691
6692void SpeculativeJIT::compileLogicalNotStringOrOther(Node* node)
6693{
6694 JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
6695 GPRTemporary temp(this);
6696 JSValueRegs valueRegs = value.jsValueRegs();
6697 GPRReg tempGPR = temp.gpr();
6698
6699 JITCompiler::Jump notCell = m_jit.branchIfNotCell(valueRegs);
6700 GPRReg cellGPR = valueRegs.payloadGPR();
6701 DFG_TYPE_CHECK(
6702 valueRegs, node->child1(), (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cellGPR));
6703
6704 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), tempGPR);
6705 m_jit.comparePtr(CCallHelpers::Equal, cellGPR, tempGPR, tempGPR);
6706 auto done = m_jit.jump();
6707
6708 notCell.link(&m_jit);
6709 DFG_TYPE_CHECK(
6710 valueRegs, node->child1(), SpecCellCheck | SpecOther, m_jit.branchIfNotOther(valueRegs, tempGPR));
6711 m_jit.move(TrustedImm32(1), tempGPR);
6712
6713 done.link(&m_jit);
6714 unblessedBooleanResult(tempGPR, node);
6715
6716}
6717
6718void SpeculativeJIT::emitStringBranch(Edge nodeUse, BasicBlock* taken, BasicBlock* notTaken)
6719{
6720 SpeculateCellOperand str(this, nodeUse);
6721
6722 GPRReg strGPR = str.gpr();
6723
6724 speculateString(nodeUse, strGPR);
6725
6726 branchPtr(CCallHelpers::Equal, strGPR, TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), notTaken);
6727 jump(taken);
6728
6729 noResult(m_currentNode);
6730}
6731
6732void SpeculativeJIT::emitStringOrOtherBranch(Edge nodeUse, BasicBlock* taken, BasicBlock* notTaken)
6733{
6734 JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
6735 GPRTemporary temp(this);
6736 JSValueRegs valueRegs = value.jsValueRegs();
6737 GPRReg tempGPR = temp.gpr();
6738
6739 JITCompiler::Jump notCell = m_jit.branchIfNotCell(valueRegs);
6740 GPRReg cellGPR = valueRegs.payloadGPR();
6741 DFG_TYPE_CHECK(valueRegs, nodeUse, (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cellGPR));
6742
6743 branchPtr(CCallHelpers::Equal, cellGPR, TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), notTaken);
6744 jump(taken, ForceJump);
6745
6746 notCell.link(&m_jit);
6747 DFG_TYPE_CHECK(
6748 valueRegs, nodeUse, SpecCellCheck | SpecOther, m_jit.branchIfNotOther(valueRegs, tempGPR));
6749 jump(notTaken);
6750 noResult(m_currentNode);
6751}
6752
6753void SpeculativeJIT::compileConstantStoragePointer(Node* node)
6754{
6755 GPRTemporary storage(this);
6756 GPRReg storageGPR = storage.gpr();
6757 m_jit.move(TrustedImmPtr(node->storagePointer()), storageGPR);
6758 storageResult(storageGPR, node);
6759}
6760
6761void SpeculativeJIT::cageTypedArrayStorage(GPRReg baseReg, GPRReg storageReg)
6762{
6763#if CPU(ARM64E)
6764 m_jit.untagArrayPtr(MacroAssembler::Address(baseReg, JSArrayBufferView::offsetOfLength()), storageReg);
6765#else
6766 UNUSED_PARAM(baseReg);
6767 UNUSED_PARAM(storageReg);
6768#endif
6769
6770#if GIGACAGE_ENABLED
6771 UNUSED_PARAM(baseReg);
6772 if (!Gigacage::shouldBeEnabled())
6773 return;
6774
6775 if (Gigacage::canPrimitiveGigacageBeDisabled()) {
6776 if (m_jit.vm()->primitiveGigacageEnabled().isStillValid())
6777 m_jit.graph().watchpoints().addLazily(m_jit.vm()->primitiveGigacageEnabled());
6778 else
6779 return;
6780 }
6781
6782 m_jit.cageWithoutUntagging(Gigacage::Primitive, storageReg);
6783#endif
6784}
6785
6786void SpeculativeJIT::compileGetIndexedPropertyStorage(Node* node)
6787{
6788 SpeculateCellOperand base(this, node->child1());
6789 GPRReg baseReg = base.gpr();
6790
6791 GPRTemporary storage(this);
6792 GPRReg storageReg = storage.gpr();
6793
6794 switch (node->arrayMode().type()) {
6795 case Array::String:
6796 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), storageReg);
6797
6798 addSlowPathGenerator(
6799 slowPathCall(
6800 m_jit.branchIfRopeStringImpl(storageReg),
6801 this, operationResolveRope, storageReg, baseReg));
6802
6803 m_jit.loadPtr(MacroAssembler::Address(storageReg, StringImpl::dataOffset()), storageReg);
6804 break;
6805
6806 default: {
6807 auto typedArrayType = node->arrayMode().typedArrayType();
6808 ASSERT_UNUSED(typedArrayType, isTypedView(typedArrayType));
6809
6810 m_jit.loadPtr(JITCompiler::Address(baseReg, JSArrayBufferView::offsetOfVector()), storageReg);
6811 cageTypedArrayStorage(baseReg, storageReg);
6812 break;
6813 }
6814 }
6815
6816 storageResult(storageReg, node);
6817}
6818
6819void SpeculativeJIT::compileGetTypedArrayByteOffset(Node* node)
6820{
6821 SpeculateCellOperand base(this, node->child1());
6822 GPRTemporary vector(this);
6823 GPRTemporary data(this);
6824
6825 GPRReg baseGPR = base.gpr();
6826 GPRReg vectorGPR = vector.gpr();
6827 GPRReg dataGPR = data.gpr();
6828 ASSERT(baseGPR != vectorGPR);
6829 ASSERT(baseGPR != dataGPR);
6830 ASSERT(vectorGPR != dataGPR);
6831
6832 GPRReg arrayBufferGPR = dataGPR;
6833
6834 JITCompiler::Jump emptyByteOffset = m_jit.branch32(
6835 MacroAssembler::NotEqual,
6836 MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfMode()),
6837 TrustedImm32(WastefulTypedArray));
6838
6839 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfVector()), vectorGPR);
6840
6841 // FIXME: This should mask the PAC bits
6842 // https://bugs.webkit.org/show_bug.cgi?id=197701
6843 JITCompiler::Jump nullVector = m_jit.branchTestPtr(JITCompiler::Zero, vectorGPR);
6844
6845 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), dataGPR);
6846 m_jit.cageWithoutUntagging(Gigacage::JSValue, dataGPR);
6847
6848 cageTypedArrayStorage(baseGPR, vectorGPR);
6849
6850 m_jit.loadPtr(MacroAssembler::Address(dataGPR, Butterfly::offsetOfArrayBuffer()), arrayBufferGPR);
6851 // FIXME: This needs caging.
6852 // https://bugs.webkit.org/show_bug.cgi?id=175515
6853 m_jit.loadPtr(MacroAssembler::Address(arrayBufferGPR, ArrayBuffer::offsetOfData()), dataGPR);
6854#if CPU(ARM64E)
6855 m_jit.removeArrayPtrTag(dataGPR);
6856#endif
6857
6858 m_jit.subPtr(dataGPR, vectorGPR);
6859
6860 JITCompiler::Jump done = m_jit.jump();
6861
6862 emptyByteOffset.link(&m_jit);
6863 m_jit.move(TrustedImmPtr(nullptr), vectorGPR);
6864
6865 done.link(&m_jit);
6866 nullVector.link(&m_jit);
6867
6868 int32Result(vectorGPR, node);
6869}
6870
6871void SpeculativeJIT::compileGetByValOnDirectArguments(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
6878 GPRReg baseReg = base.gpr();
6879 GPRReg propertyReg = property.gpr();
6880 JSValueRegs resultRegs = result.regs();
6881 GPRReg scratchReg = scratch.gpr();
6882
6883 if (!m_compileOkay)
6884 return;
6885
6886 ASSERT(ArrayMode(Array::DirectArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.varArgChild(node, 0))));
6887
6888 speculationCheck(
6889 ExoticObjectMode, JSValueSource(), 0,
6890 m_jit.branchTestPtr(
6891 MacroAssembler::NonZero,
6892 MacroAssembler::Address(baseReg, DirectArguments::offsetOfMappedArguments())));
6893
6894 m_jit.load32(CCallHelpers::Address(baseReg, DirectArguments::offsetOfLength()), scratchReg);
6895 auto isOutOfBounds = m_jit.branch32(CCallHelpers::AboveOrEqual, propertyReg, scratchReg);
6896 if (node->arrayMode().isInBounds())
6897 speculationCheck(OutOfBounds, JSValueSource(), 0, isOutOfBounds);
6898
6899 m_jit.loadValue(
6900 MacroAssembler::BaseIndex(
6901 baseReg, propertyReg, MacroAssembler::TimesEight, DirectArguments::storageOffset()),
6902 resultRegs);
6903
6904 if (!node->arrayMode().isInBounds()) {
6905 addSlowPathGenerator(
6906 slowPathCall(
6907 isOutOfBounds, this, operationGetByValObjectInt,
6908 extractResult(resultRegs), baseReg, propertyReg));
6909 }
6910
6911 jsValueResult(resultRegs, node);
6912}
6913
6914void SpeculativeJIT::compileGetByValOnScopedArguments(Node* node)
6915{
6916 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
6917 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
6918 JSValueRegsTemporary result(this);
6919 GPRTemporary scratch(this);
6920 GPRTemporary scratch2(this);
6921 GPRTemporary indexMask(this);
6922
6923 GPRReg baseReg = base.gpr();
6924 GPRReg propertyReg = property.gpr();
6925 JSValueRegs resultRegs = result.regs();
6926 GPRReg scratchReg = scratch.gpr();
6927 GPRReg scratch2Reg = scratch2.gpr();
6928 GPRReg indexMaskReg = indexMask.gpr();
6929
6930 if (!m_compileOkay)
6931 return;
6932
6933 ASSERT(ArrayMode(Array::ScopedArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.varArgChild(node, 0))));
6934
6935 m_jit.loadPtr(
6936 MacroAssembler::Address(baseReg, ScopedArguments::offsetOfStorage()), resultRegs.payloadGPR());
6937 m_jit.load32(
6938 MacroAssembler::Address(resultRegs.payloadGPR(), ScopedArguments::offsetOfTotalLengthInStorage()),
6939 scratchReg);
6940
6941 speculationCheck(
6942 ExoticObjectMode, JSValueSource(), nullptr,
6943 m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, scratchReg));
6944
6945 m_jit.emitPreparePreciseIndexMask32(propertyReg, scratchReg, indexMaskReg);
6946
6947 m_jit.loadPtr(MacroAssembler::Address(baseReg, ScopedArguments::offsetOfTable()), scratchReg);
6948 m_jit.load32(
6949 MacroAssembler::Address(scratchReg, ScopedArgumentsTable::offsetOfLength()), scratch2Reg);
6950
6951 MacroAssembler::Jump overflowArgument = m_jit.branch32(
6952 MacroAssembler::AboveOrEqual, propertyReg, scratch2Reg);
6953
6954 m_jit.loadPtr(MacroAssembler::Address(baseReg, ScopedArguments::offsetOfScope()), scratch2Reg);
6955
6956 m_jit.loadPtr(
6957 MacroAssembler::Address(scratchReg, ScopedArgumentsTable::offsetOfArguments()),
6958 scratchReg);
6959 m_jit.load32(
6960 MacroAssembler::BaseIndex(scratchReg, propertyReg, MacroAssembler::TimesFour),
6961 scratchReg);
6962
6963 speculationCheck(
6964 ExoticObjectMode, JSValueSource(), nullptr,
6965 m_jit.branch32(
6966 MacroAssembler::Equal, scratchReg, TrustedImm32(ScopeOffset::invalidOffset)));
6967
6968 m_jit.loadValue(
6969 MacroAssembler::BaseIndex(
6970 scratch2Reg, propertyReg, MacroAssembler::TimesEight,
6971 JSLexicalEnvironment::offsetOfVariables()),
6972 resultRegs);
6973
6974 MacroAssembler::Jump done = m_jit.jump();
6975 overflowArgument.link(&m_jit);
6976
6977 m_jit.sub32(propertyReg, scratch2Reg);
6978 m_jit.neg32(scratch2Reg);
6979
6980 m_jit.loadValue(
6981 MacroAssembler::BaseIndex(
6982 resultRegs.payloadGPR(), scratch2Reg, MacroAssembler::TimesEight),
6983 resultRegs);
6984 speculationCheck(ExoticObjectMode, JSValueSource(), nullptr, m_jit.branchIfEmpty(resultRegs));
6985
6986 done.link(&m_jit);
6987
6988 m_jit.andPtr(indexMaskReg, resultRegs.payloadGPR());
6989
6990 jsValueResult(resultRegs, node);
6991}
6992
6993void SpeculativeJIT::compileGetScope(Node* node)
6994{
6995 SpeculateCellOperand function(this, node->child1());
6996 GPRTemporary result(this, Reuse, function);
6997 m_jit.loadPtr(JITCompiler::Address(function.gpr(), JSFunction::offsetOfScopeChain()), result.gpr());
6998 cellResult(result.gpr(), node);
6999}
7000
7001void SpeculativeJIT::compileSkipScope(Node* node)
7002{
7003 SpeculateCellOperand scope(this, node->child1());
7004 GPRTemporary result(this, Reuse, scope);
7005 m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSScope::offsetOfNext()), result.gpr());
7006 cellResult(result.gpr(), node);
7007}
7008
7009void SpeculativeJIT::compileGetGlobalObject(Node* node)
7010{
7011 SpeculateCellOperand object(this, node->child1());
7012 GPRTemporary result(this);
7013 GPRTemporary scratch(this);
7014 m_jit.emitLoadStructure(*m_jit.vm(), object.gpr(), result.gpr(), scratch.gpr());
7015 m_jit.loadPtr(JITCompiler::Address(result.gpr(), Structure::globalObjectOffset()), result.gpr());
7016 cellResult(result.gpr(), node);
7017}
7018
7019void SpeculativeJIT::compileGetGlobalThis(Node* node)
7020{
7021 GPRTemporary result(this);
7022 GPRReg resultGPR = result.gpr();
7023 auto* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
7024 m_jit.loadPtr(globalObject->addressOfGlobalThis(), resultGPR);
7025 cellResult(resultGPR, node);
7026}
7027
7028bool SpeculativeJIT::canBeRope(Edge& edge)
7029{
7030 if (m_state.forNode(edge).isType(SpecStringIdent))
7031 return false;
7032 // If this value is LazyValue, it will be converted to JSString, and the result must be non-rope string.
7033 String string = edge->tryGetString(m_graph);
7034 if (!string.isNull())
7035 return false;
7036 return true;
7037}
7038
7039void SpeculativeJIT::compileGetArrayLength(Node* node)
7040{
7041 switch (node->arrayMode().type()) {
7042 case Array::Undecided:
7043 case Array::Int32:
7044 case Array::Double:
7045 case Array::Contiguous: {
7046 StorageOperand storage(this, node->child2());
7047 GPRTemporary result(this, Reuse, storage);
7048 GPRReg storageReg = storage.gpr();
7049 GPRReg resultReg = result.gpr();
7050 m_jit.load32(MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()), resultReg);
7051
7052 int32Result(resultReg, node);
7053 break;
7054 }
7055 case Array::ArrayStorage:
7056 case Array::SlowPutArrayStorage: {
7057 StorageOperand storage(this, node->child2());
7058 GPRTemporary result(this, Reuse, storage);
7059 GPRReg storageReg = storage.gpr();
7060 GPRReg resultReg = result.gpr();
7061 m_jit.load32(MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()), resultReg);
7062
7063 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, resultReg, MacroAssembler::TrustedImm32(0)));
7064
7065 int32Result(resultReg, node);
7066 break;
7067 }
7068 case Array::String: {
7069 SpeculateCellOperand base(this, node->child1());
7070 GPRTemporary result(this, Reuse, base);
7071 GPRTemporary temp(this);
7072 GPRReg baseGPR = base.gpr();
7073 GPRReg resultGPR = result.gpr();
7074 GPRReg tempGPR = temp.gpr();
7075
7076 bool needsRopeCase = canBeRope(node->child1());
7077
7078 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSString::offsetOfValue()), tempGPR);
7079 CCallHelpers::Jump isRope;
7080 if (needsRopeCase)
7081 isRope = m_jit.branchIfRopeStringImpl(tempGPR);
7082 m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), resultGPR);
7083 if (needsRopeCase) {
7084 auto done = m_jit.jump();
7085
7086 isRope.link(&m_jit);
7087 m_jit.load32(CCallHelpers::Address(baseGPR, JSRopeString::offsetOfLength()), resultGPR);
7088
7089 done.link(&m_jit);
7090 }
7091 int32Result(resultGPR, node);
7092 break;
7093 }
7094 case Array::DirectArguments: {
7095 SpeculateCellOperand base(this, node->child1());
7096 GPRTemporary result(this, Reuse, base);
7097
7098 GPRReg baseReg = base.gpr();
7099 GPRReg resultReg = result.gpr();
7100
7101 if (!m_compileOkay)
7102 return;
7103
7104 ASSERT(ArrayMode(Array::DirectArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1())));
7105
7106 speculationCheck(
7107 ExoticObjectMode, JSValueSource(), 0,
7108 m_jit.branchTestPtr(
7109 MacroAssembler::NonZero,
7110 MacroAssembler::Address(baseReg, DirectArguments::offsetOfMappedArguments())));
7111
7112 m_jit.load32(
7113 MacroAssembler::Address(baseReg, DirectArguments::offsetOfLength()), resultReg);
7114
7115 int32Result(resultReg, node);
7116 break;
7117 }
7118 case Array::ScopedArguments: {
7119 SpeculateCellOperand base(this, node->child1());
7120 GPRTemporary result(this);
7121
7122 GPRReg baseReg = base.gpr();
7123 GPRReg resultReg = result.gpr();
7124
7125 if (!m_compileOkay)
7126 return;
7127
7128 ASSERT(ArrayMode(Array::ScopedArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1())));
7129
7130 m_jit.loadPtr(
7131 MacroAssembler::Address(baseReg, ScopedArguments::offsetOfStorage()), resultReg);
7132
7133 speculationCheck(
7134 ExoticObjectMode, JSValueSource(), 0,
7135 m_jit.branchTest8(
7136 MacroAssembler::NonZero,
7137 MacroAssembler::Address(resultReg, ScopedArguments::offsetOfOverrodeThingsInStorage())));
7138
7139 m_jit.load32(
7140 MacroAssembler::Address(resultReg, ScopedArguments::offsetOfTotalLengthInStorage()), resultReg);
7141
7142 int32Result(resultReg, node);
7143 break;
7144 }
7145 default: {
7146 ASSERT(node->arrayMode().isSomeTypedArrayView());
7147 SpeculateCellOperand base(this, node->child1());
7148 GPRTemporary result(this, Reuse, base);
7149 GPRReg baseGPR = base.gpr();
7150 GPRReg resultGPR = result.gpr();
7151 m_jit.load32(MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfLength()), resultGPR);
7152 int32Result(resultGPR, node);
7153 break;
7154 } }
7155}
7156
7157void SpeculativeJIT::compileCheckStringIdent(Node* node)
7158{
7159 SpeculateCellOperand string(this, node->child1());
7160 GPRTemporary storage(this);
7161
7162 GPRReg stringGPR = string.gpr();
7163 GPRReg storageGPR = storage.gpr();
7164
7165 speculateString(node->child1(), stringGPR);
7166 speculateStringIdentAndLoadStorage(node->child1(), stringGPR, storageGPR);
7167
7168 UniquedStringImpl* uid = node->uidOperand();
7169 speculationCheck(
7170 BadIdent, JSValueSource(), nullptr,
7171 m_jit.branchPtr(JITCompiler::NotEqual, storageGPR, TrustedImmPtr(uid)));
7172 noResult(node);
7173}
7174
7175template <typename ClassType>
7176void SpeculativeJIT::compileNewFunctionCommon(GPRReg resultGPR, RegisteredStructure structure, GPRReg scratch1GPR, GPRReg scratch2GPR, GPRReg scopeGPR, MacroAssembler::JumpList& slowPath, size_t size, FunctionExecutable* executable)
7177{
7178 auto butterfly = TrustedImmPtr(nullptr);
7179 emitAllocateJSObjectWithKnownSize<ClassType>(resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR, slowPath, size);
7180
7181 m_jit.storePtr(scopeGPR, JITCompiler::Address(resultGPR, JSFunction::offsetOfScopeChain()));
7182 m_jit.storePtr(TrustedImmPtr::weakPointer(m_jit.graph(), executable), JITCompiler::Address(resultGPR, JSFunction::offsetOfExecutable()));
7183 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, JSFunction::offsetOfRareData()));
7184
7185 if (executable->isAnonymousBuiltinFunction()) {
7186 VM& vm = *m_jit.vm();
7187 m_jit.mutatorFence(vm);
7188 GPRTemporary allocator(this);
7189 Allocator allocatorValue = allocatorForNonVirtualConcurrently<FunctionRareData>(vm, sizeof(FunctionRareData), AllocatorForMode::AllocatorIfExists);
7190 emitAllocateJSCell(scratch1GPR, JITAllocator::constant(allocatorValue), allocator.gpr(), TrustedImmPtr(m_jit.graph().registerStructure(vm.functionRareDataStructure.get())), scratch2GPR, slowPath);
7191
7192 ptrdiff_t objectAllocationProfileOffset = FunctionRareData::offsetOfObjectAllocationProfile();
7193 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, objectAllocationProfileOffset + ObjectAllocationProfileWithPrototype::offsetOfAllocator()));
7194 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, objectAllocationProfileOffset + ObjectAllocationProfileWithPrototype::offsetOfStructure()));
7195 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, objectAllocationProfileOffset + ObjectAllocationProfileWithPrototype::offsetOfPrototype()));
7196 m_jit.storePtr(TrustedImmPtr(0x1), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfObjectAllocationProfileWatchpoint()));
7197 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfInternalFunctionAllocationProfile() + InternalFunctionAllocationProfile::offsetOfStructure()));
7198 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfBoundFunctionStructure()));
7199 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfAllocationProfileClearingWatchpoint()));
7200 m_jit.store8(TrustedImm32(0), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfHasReifiedLength()));
7201 m_jit.store8(TrustedImm32(1), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfHasReifiedName()));
7202 m_jit.mutatorFence(vm);
7203 m_jit.storePtr(scratch1GPR, JITCompiler::Address(resultGPR, JSFunction::offsetOfRareData()));
7204 } else
7205 m_jit.mutatorFence(*m_jit.vm());
7206
7207}
7208
7209void SpeculativeJIT::compileNewFunction(Node* node)
7210{
7211 NodeType nodeType = node->op();
7212 ASSERT(nodeType == NewFunction || nodeType == NewGeneratorFunction || nodeType == NewAsyncFunction || nodeType == NewAsyncGeneratorFunction);
7213
7214 SpeculateCellOperand scope(this, node->child1());
7215 GPRReg scopeGPR = scope.gpr();
7216
7217 FunctionExecutable* executable = node->castOperand<FunctionExecutable*>();
7218
7219 if (executable->singleton().isStillValid()) {
7220 GPRFlushedCallResult result(this);
7221 GPRReg resultGPR = result.gpr();
7222
7223 flushRegisters();
7224
7225 if (nodeType == NewGeneratorFunction)
7226 callOperation(operationNewGeneratorFunction, resultGPR, scopeGPR, executable);
7227 else if (nodeType == NewAsyncFunction)
7228 callOperation(operationNewAsyncFunction, resultGPR, scopeGPR, executable);
7229 else if (nodeType == NewAsyncGeneratorFunction)
7230 callOperation(operationNewAsyncGeneratorFunction, resultGPR, scopeGPR, executable);
7231 else
7232 callOperation(operationNewFunction, resultGPR, scopeGPR, executable);
7233 m_jit.exceptionCheck();
7234 cellResult(resultGPR, node);
7235 return;
7236 }
7237
7238 RegisteredStructure structure = m_jit.graph().registerStructure(
7239 [&] () {
7240 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
7241 switch (nodeType) {
7242 case NewGeneratorFunction:
7243 return globalObject->generatorFunctionStructure();
7244 case NewAsyncFunction:
7245 return globalObject->asyncFunctionStructure();
7246 case NewAsyncGeneratorFunction:
7247 return globalObject->asyncGeneratorFunctionStructure();
7248 case NewFunction:
7249 return JSFunction::selectStructureForNewFuncExp(globalObject, node->castOperand<FunctionExecutable*>());
7250 default:
7251 RELEASE_ASSERT_NOT_REACHED();
7252 }
7253 }());
7254
7255 GPRTemporary result(this);
7256 GPRTemporary scratch1(this);
7257 GPRTemporary scratch2(this);
7258
7259 GPRReg resultGPR = result.gpr();
7260 GPRReg scratch1GPR = scratch1.gpr();
7261 GPRReg scratch2GPR = scratch2.gpr();
7262
7263 JITCompiler::JumpList slowPath;
7264
7265 if (nodeType == NewFunction) {
7266 compileNewFunctionCommon<JSFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSFunction::allocationSize(0), executable);
7267
7268 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable));
7269 }
7270
7271 if (nodeType == NewGeneratorFunction) {
7272 compileNewFunctionCommon<JSGeneratorFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSGeneratorFunction::allocationSize(0), executable);
7273
7274 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewGeneratorFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable));
7275 }
7276
7277 if (nodeType == NewAsyncFunction) {
7278 compileNewFunctionCommon<JSAsyncFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSAsyncFunction::allocationSize(0), executable);
7279
7280 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewAsyncFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable));
7281 }
7282
7283 if (nodeType == NewAsyncGeneratorFunction) {
7284 compileNewFunctionCommon<JSAsyncGeneratorFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSAsyncGeneratorFunction::allocationSize(0), executable);
7285
7286 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewAsyncGeneratorFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable));
7287 }
7288
7289 cellResult(resultGPR, node);
7290}
7291
7292void SpeculativeJIT::compileSetFunctionName(Node* node)
7293{
7294 SpeculateCellOperand func(this, node->child1());
7295 GPRReg funcGPR = func.gpr();
7296 JSValueOperand nameValue(this, node->child2());
7297 JSValueRegs nameValueRegs = nameValue.jsValueRegs();
7298
7299 flushRegisters();
7300 callOperation(operationSetFunctionName, funcGPR, nameValueRegs);
7301 m_jit.exceptionCheck();
7302
7303 noResult(node);
7304}
7305
7306void SpeculativeJIT::compileLoadVarargs(Node* node)
7307{
7308 LoadVarargsData* data = node->loadVarargsData();
7309
7310 JSValueRegs argumentsRegs;
7311 {
7312 JSValueOperand arguments(this, node->child1());
7313 argumentsRegs = arguments.jsValueRegs();
7314 flushRegisters();
7315 }
7316
7317 callOperation(operationSizeOfVarargs, GPRInfo::returnValueGPR, argumentsRegs, data->offset);
7318 m_jit.exceptionCheck();
7319
7320 lock(GPRInfo::returnValueGPR);
7321 {
7322 JSValueOperand arguments(this, node->child1());
7323 argumentsRegs = arguments.jsValueRegs();
7324 flushRegisters();
7325 }
7326 unlock(GPRInfo::returnValueGPR);
7327
7328 // FIXME: There is a chance that we will call an effectful length property twice. This is safe
7329 // from the standpoint of the VM's integrity, but it's subtly wrong from a spec compliance
7330 // standpoint. The best solution would be one where we can exit *into* the op_call_varargs right
7331 // past the sizing.
7332 // https://bugs.webkit.org/show_bug.cgi?id=141448
7333
7334 GPRReg argCountIncludingThisGPR =
7335 JITCompiler::selectScratchGPR(GPRInfo::returnValueGPR, argumentsRegs);
7336
7337 m_jit.add32(TrustedImm32(1), GPRInfo::returnValueGPR, argCountIncludingThisGPR);
7338
7339 speculationCheck(
7340 VarargsOverflow, JSValueSource(), Edge(), m_jit.branch32(
7341 MacroAssembler::Above,
7342 GPRInfo::returnValueGPR,
7343 argCountIncludingThisGPR));
7344
7345 speculationCheck(
7346 VarargsOverflow, JSValueSource(), Edge(), m_jit.branch32(
7347 MacroAssembler::Above,
7348 argCountIncludingThisGPR,
7349 TrustedImm32(data->limit)));
7350
7351 m_jit.store32(argCountIncludingThisGPR, JITCompiler::payloadFor(data->machineCount));
7352
7353 callOperation(operationLoadVarargs, data->machineStart.offset(), argumentsRegs, data->offset, GPRInfo::returnValueGPR, data->mandatoryMinimum);
7354 m_jit.exceptionCheck();
7355
7356 noResult(node);
7357}
7358
7359void SpeculativeJIT::compileForwardVarargs(Node* node)
7360{
7361 LoadVarargsData* data = node->loadVarargsData();
7362 InlineCallFrame* inlineCallFrame;
7363 if (node->child1())
7364 inlineCallFrame = node->child1()->origin.semantic.inlineCallFrame();
7365 else
7366 inlineCallFrame = node->origin.semantic.inlineCallFrame();
7367
7368 GPRTemporary length(this);
7369 JSValueRegsTemporary temp(this);
7370 GPRReg lengthGPR = length.gpr();
7371 JSValueRegs tempRegs = temp.regs();
7372
7373 emitGetLength(inlineCallFrame, lengthGPR, /* includeThis = */ true);
7374 if (data->offset)
7375 m_jit.sub32(TrustedImm32(data->offset), lengthGPR);
7376
7377 speculationCheck(
7378 VarargsOverflow, JSValueSource(), Edge(), m_jit.branch32(
7379 MacroAssembler::Above,
7380 lengthGPR, TrustedImm32(data->limit)));
7381
7382 m_jit.store32(lengthGPR, JITCompiler::payloadFor(data->machineCount));
7383
7384 VirtualRegister sourceStart = JITCompiler::argumentsStart(inlineCallFrame) + data->offset;
7385 VirtualRegister targetStart = data->machineStart;
7386
7387 m_jit.sub32(TrustedImm32(1), lengthGPR);
7388
7389 // First have a loop that fills in the undefined slots in case of an arity check failure.
7390 m_jit.move(TrustedImm32(data->mandatoryMinimum), tempRegs.payloadGPR());
7391 JITCompiler::Jump done = m_jit.branch32(JITCompiler::BelowOrEqual, tempRegs.payloadGPR(), lengthGPR);
7392
7393 JITCompiler::Label loop = m_jit.label();
7394 m_jit.sub32(TrustedImm32(1), tempRegs.payloadGPR());
7395 m_jit.storeTrustedValue(
7396 jsUndefined(),
7397 JITCompiler::BaseIndex(
7398 GPRInfo::callFrameRegister, tempRegs.payloadGPR(), JITCompiler::TimesEight,
7399 targetStart.offset() * sizeof(EncodedJSValue)));
7400 m_jit.branch32(JITCompiler::Above, tempRegs.payloadGPR(), lengthGPR).linkTo(loop, &m_jit);
7401 done.link(&m_jit);
7402
7403 // And then fill in the actual argument values.
7404 done = m_jit.branchTest32(JITCompiler::Zero, lengthGPR);
7405
7406 loop = m_jit.label();
7407 m_jit.sub32(TrustedImm32(1), lengthGPR);
7408 m_jit.loadValue(
7409 JITCompiler::BaseIndex(
7410 GPRInfo::callFrameRegister, lengthGPR, JITCompiler::TimesEight,
7411 sourceStart.offset() * sizeof(EncodedJSValue)),
7412 tempRegs);
7413 m_jit.storeValue(
7414 tempRegs,
7415 JITCompiler::BaseIndex(
7416 GPRInfo::callFrameRegister, lengthGPR, JITCompiler::TimesEight,
7417 targetStart.offset() * sizeof(EncodedJSValue)));
7418 m_jit.branchTest32(JITCompiler::NonZero, lengthGPR).linkTo(loop, &m_jit);
7419
7420 done.link(&m_jit);
7421
7422 noResult(node);
7423}
7424
7425void SpeculativeJIT::compileCreateActivation(Node* node)
7426{
7427 SymbolTable* table = node->castOperand<SymbolTable*>();
7428 RegisteredStructure structure = m_jit.graph().registerStructure(m_jit.graph().globalObjectFor(
7429 node->origin.semantic)->activationStructure());
7430
7431 SpeculateCellOperand scope(this, node->child1());
7432 GPRReg scopeGPR = scope.gpr();
7433 JSValue initializationValue = node->initializationValueForActivation();
7434 ASSERT(initializationValue == jsUndefined() || initializationValue == jsTDZValue());
7435
7436 if (table->singleton().isStillValid()) {
7437 GPRFlushedCallResult result(this);
7438 GPRReg resultGPR = result.gpr();
7439
7440#if USE(JSVALUE32_64)
7441 JSValueRegsTemporary initialization(this);
7442 JSValueRegs initializationRegs = initialization.regs();
7443 m_jit.moveTrustedValue(initializationValue, initializationRegs);
7444#endif
7445
7446 flushRegisters();
7447
7448#if USE(JSVALUE64)
7449 callOperation(operationCreateActivationDirect,
7450 resultGPR, structure, scopeGPR, table, TrustedImm64(JSValue::encode(initializationValue)));
7451#else
7452 callOperation(operationCreateActivationDirect,
7453 resultGPR, structure, scopeGPR, table, initializationRegs);
7454#endif
7455 m_jit.exceptionCheck();
7456 cellResult(resultGPR, node);
7457 return;
7458 }
7459
7460 GPRTemporary result(this);
7461 GPRTemporary scratch1(this);
7462 GPRTemporary scratch2(this);
7463 GPRReg resultGPR = result.gpr();
7464 GPRReg scratch1GPR = scratch1.gpr();
7465 GPRReg scratch2GPR = scratch2.gpr();
7466
7467#if USE(JSVALUE32_64)
7468 JSValueRegsTemporary initialization(this);
7469 JSValueRegs initializationRegs = initialization.regs();
7470 m_jit.moveTrustedValue(initializationValue, initializationRegs);
7471#endif
7472
7473 JITCompiler::JumpList slowPath;
7474 auto butterfly = TrustedImmPtr(nullptr);
7475 emitAllocateJSObjectWithKnownSize<JSLexicalEnvironment>(
7476 resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR,
7477 slowPath, JSLexicalEnvironment::allocationSize(table));
7478
7479 // Don't need a memory barriers since we just fast-created the activation, so the
7480 // activation must be young.
7481 m_jit.storePtr(scopeGPR, JITCompiler::Address(resultGPR, JSScope::offsetOfNext()));
7482 m_jit.storePtr(
7483 TrustedImmPtr(node->cellOperand()),
7484 JITCompiler::Address(resultGPR, JSLexicalEnvironment::offsetOfSymbolTable()));
7485
7486 // Must initialize all members to undefined or the TDZ empty value.
7487 for (unsigned i = 0; i < table->scopeSize(); ++i) {
7488 m_jit.storeTrustedValue(
7489 initializationValue,
7490 JITCompiler::Address(
7491 resultGPR, JSLexicalEnvironment::offsetOfVariable(ScopeOffset(i))));
7492 }
7493
7494 m_jit.mutatorFence(*m_jit.vm());
7495
7496#if USE(JSVALUE64)
7497 addSlowPathGenerator(
7498 slowPathCall(
7499 slowPath, this, operationCreateActivationDirect, resultGPR, structure, scopeGPR, table, TrustedImm64(JSValue::encode(initializationValue))));
7500#else
7501 addSlowPathGenerator(
7502 slowPathCall(
7503 slowPath, this, operationCreateActivationDirect, resultGPR, structure, scopeGPR, table, initializationRegs));
7504#endif
7505
7506 cellResult(resultGPR, node);
7507}
7508
7509void SpeculativeJIT::compileCreateDirectArguments(Node* node)
7510{
7511 // FIXME: A more effective way of dealing with the argument count and callee is to have
7512 // them be explicit arguments to this node.
7513 // https://bugs.webkit.org/show_bug.cgi?id=142207
7514
7515 GPRTemporary result(this);
7516 GPRTemporary scratch1(this);
7517 GPRTemporary scratch2(this);
7518 GPRTemporary length;
7519 GPRReg resultGPR = result.gpr();
7520 GPRReg scratch1GPR = scratch1.gpr();
7521 GPRReg scratch2GPR = scratch2.gpr();
7522 GPRReg lengthGPR = InvalidGPRReg;
7523 JSValueRegs valueRegs = JSValueRegs::withTwoAvailableRegs(scratch1GPR, scratch2GPR);
7524
7525 unsigned minCapacity = m_jit.graph().baselineCodeBlockFor(node->origin.semantic)->numParameters() - 1;
7526
7527 unsigned knownLength;
7528 bool lengthIsKnown; // if false, lengthGPR will have the length.
7529 auto* inlineCallFrame = node->origin.semantic.inlineCallFrame();
7530 if (inlineCallFrame
7531 && !inlineCallFrame->isVarargs()) {
7532 knownLength = inlineCallFrame->argumentCountIncludingThis - 1;
7533 lengthIsKnown = true;
7534 } else {
7535 knownLength = UINT_MAX;
7536 lengthIsKnown = false;
7537
7538 GPRTemporary realLength(this);
7539 length.adopt(realLength);
7540 lengthGPR = length.gpr();
7541
7542 VirtualRegister argumentCountRegister = m_jit.argumentCount(node->origin.semantic);
7543 m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), lengthGPR);
7544 m_jit.sub32(TrustedImm32(1), lengthGPR);
7545 }
7546
7547 RegisteredStructure structure =
7548 m_jit.graph().registerStructure(m_jit.graph().globalObjectFor(node->origin.semantic)->directArgumentsStructure());
7549
7550 // Use a different strategy for allocating the object depending on whether we know its
7551 // size statically.
7552 JITCompiler::JumpList slowPath;
7553 if (lengthIsKnown) {
7554 auto butterfly = TrustedImmPtr(nullptr);
7555 emitAllocateJSObjectWithKnownSize<DirectArguments>(
7556 resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR,
7557 slowPath, DirectArguments::allocationSize(std::max(knownLength, minCapacity)));
7558
7559 m_jit.store32(
7560 TrustedImm32(knownLength),
7561 JITCompiler::Address(resultGPR, DirectArguments::offsetOfLength()));
7562 } else {
7563 JITCompiler::Jump tooFewArguments;
7564 if (minCapacity) {
7565 tooFewArguments =
7566 m_jit.branch32(JITCompiler::Below, lengthGPR, TrustedImm32(minCapacity));
7567 }
7568 m_jit.lshift32(lengthGPR, TrustedImm32(3), scratch1GPR);
7569 m_jit.add32(TrustedImm32(DirectArguments::storageOffset()), scratch1GPR);
7570 if (minCapacity) {
7571 JITCompiler::Jump done = m_jit.jump();
7572 tooFewArguments.link(&m_jit);
7573 m_jit.move(TrustedImm32(DirectArguments::allocationSize(minCapacity)), scratch1GPR);
7574 done.link(&m_jit);
7575 }
7576
7577 emitAllocateVariableSizedJSObject<DirectArguments>(
7578 resultGPR, TrustedImmPtr(structure), scratch1GPR, scratch1GPR, scratch2GPR,
7579 slowPath);
7580
7581 m_jit.store32(
7582 lengthGPR, JITCompiler::Address(resultGPR, DirectArguments::offsetOfLength()));
7583 }
7584
7585 m_jit.store32(
7586 TrustedImm32(minCapacity),
7587 JITCompiler::Address(resultGPR, DirectArguments::offsetOfMinCapacity()));
7588
7589 m_jit.storePtr(
7590 TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, DirectArguments::offsetOfMappedArguments()));
7591
7592 m_jit.storePtr(
7593 TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, DirectArguments::offsetOfModifiedArgumentsDescriptor()));
7594
7595 if (lengthIsKnown) {
7596 addSlowPathGenerator(
7597 slowPathCall(
7598 slowPath, this, operationCreateDirectArguments, resultGPR, structure,
7599 knownLength, minCapacity));
7600 } else {
7601 auto generator = std::make_unique<CallCreateDirectArgumentsSlowPathGenerator>(
7602 slowPath, this, resultGPR, structure, lengthGPR, minCapacity);
7603 addSlowPathGenerator(WTFMove(generator));
7604 }
7605
7606 if (inlineCallFrame) {
7607 if (inlineCallFrame->isClosureCall) {
7608 m_jit.loadPtr(
7609 JITCompiler::addressFor(
7610 inlineCallFrame->calleeRecovery.virtualRegister()),
7611 scratch1GPR);
7612 } else {
7613 m_jit.move(
7614 TrustedImmPtr::weakPointer(
7615 m_jit.graph(), inlineCallFrame->calleeRecovery.constant().asCell()),
7616 scratch1GPR);
7617 }
7618 } else
7619 m_jit.loadPtr(JITCompiler::addressFor(CallFrameSlot::callee), scratch1GPR);
7620
7621 // Don't need a memory barriers since we just fast-created the activation, so the
7622 // activation must be young.
7623 m_jit.storePtr(
7624 scratch1GPR, JITCompiler::Address(resultGPR, DirectArguments::offsetOfCallee()));
7625
7626 VirtualRegister start = m_jit.argumentsStart(node->origin.semantic);
7627 if (lengthIsKnown) {
7628 for (unsigned i = 0; i < std::max(knownLength, minCapacity); ++i) {
7629 m_jit.loadValue(JITCompiler::addressFor(start + i), valueRegs);
7630 m_jit.storeValue(
7631 valueRegs, JITCompiler::Address(resultGPR, DirectArguments::offsetOfSlot(i)));
7632 }
7633 } else {
7634 JITCompiler::Jump done;
7635 if (minCapacity) {
7636 JITCompiler::Jump startLoop = m_jit.branch32(
7637 JITCompiler::AboveOrEqual, lengthGPR, TrustedImm32(minCapacity));
7638 m_jit.move(TrustedImm32(minCapacity), lengthGPR);
7639 startLoop.link(&m_jit);
7640 } else
7641 done = m_jit.branchTest32(MacroAssembler::Zero, lengthGPR);
7642 JITCompiler::Label loop = m_jit.label();
7643 m_jit.sub32(TrustedImm32(1), lengthGPR);
7644 m_jit.loadValue(
7645 JITCompiler::BaseIndex(
7646 GPRInfo::callFrameRegister, lengthGPR, JITCompiler::TimesEight,
7647 start.offset() * static_cast<int>(sizeof(Register))),
7648 valueRegs);
7649 m_jit.storeValue(
7650 valueRegs,
7651 JITCompiler::BaseIndex(
7652 resultGPR, lengthGPR, JITCompiler::TimesEight,
7653 DirectArguments::storageOffset()));
7654 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loop, &m_jit);
7655 if (done.isSet())
7656 done.link(&m_jit);
7657 }
7658
7659 m_jit.mutatorFence(*m_jit.vm());
7660
7661 cellResult(resultGPR, node);
7662}
7663
7664void SpeculativeJIT::compileGetFromArguments(Node* node)
7665{
7666 SpeculateCellOperand arguments(this, node->child1());
7667 JSValueRegsTemporary result(this);
7668
7669 GPRReg argumentsGPR = arguments.gpr();
7670 JSValueRegs resultRegs = result.regs();
7671
7672 m_jit.loadValue(JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfSlot(node->capturedArgumentsOffset().offset())), resultRegs);
7673 jsValueResult(resultRegs, node);
7674}
7675
7676void SpeculativeJIT::compilePutToArguments(Node* node)
7677{
7678 SpeculateCellOperand arguments(this, node->child1());
7679 JSValueOperand value(this, node->child2());
7680
7681 GPRReg argumentsGPR = arguments.gpr();
7682 JSValueRegs valueRegs = value.jsValueRegs();
7683
7684 m_jit.storeValue(valueRegs, JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfSlot(node->capturedArgumentsOffset().offset())));
7685 noResult(node);
7686}
7687
7688void SpeculativeJIT::compileGetArgument(Node* node)
7689{
7690 GPRTemporary argumentCount(this);
7691 JSValueRegsTemporary result(this);
7692 GPRReg argumentCountGPR = argumentCount.gpr();
7693 JSValueRegs resultRegs = result.regs();
7694 m_jit.load32(CCallHelpers::payloadFor(m_jit.argumentCount(node->origin.semantic)), argumentCountGPR);
7695 auto argumentOutOfBounds = m_jit.branch32(CCallHelpers::LessThanOrEqual, argumentCountGPR, CCallHelpers::TrustedImm32(node->argumentIndex()));
7696 m_jit.loadValue(CCallHelpers::addressFor(CCallHelpers::argumentsStart(node->origin.semantic) + node->argumentIndex() - 1), resultRegs);
7697 auto done = m_jit.jump();
7698
7699 argumentOutOfBounds.link(&m_jit);
7700 m_jit.moveValue(jsUndefined(), resultRegs);
7701
7702 done.link(&m_jit);
7703 jsValueResult(resultRegs, node);
7704}
7705
7706void SpeculativeJIT::compileCreateScopedArguments(Node* node)
7707{
7708 SpeculateCellOperand scope(this, node->child1());
7709 GPRReg scopeGPR = scope.gpr();
7710
7711 GPRFlushedCallResult result(this);
7712 GPRReg resultGPR = result.gpr();
7713 flushRegisters();
7714
7715 // We set up the arguments ourselves, because we have the whole register file and we can
7716 // set them up directly into the argument registers. This also means that we don't have to
7717 // invent a four-argument-register shuffle.
7718
7719 // Arguments: 0:exec, 1:structure, 2:start, 3:length, 4:callee, 5:scope
7720
7721 // Do the scopeGPR first, since it might alias an argument register.
7722 m_jit.setupArgument(5, [&] (GPRReg destGPR) { m_jit.move(scopeGPR, destGPR); });
7723
7724 // These other things could be done in any order.
7725 m_jit.setupArgument(4, [&] (GPRReg destGPR) { emitGetCallee(node->origin.semantic, destGPR); });
7726 m_jit.setupArgument(3, [&] (GPRReg destGPR) { emitGetLength(node->origin.semantic, destGPR); });
7727 m_jit.setupArgument(2, [&] (GPRReg destGPR) { emitGetArgumentStart(node->origin.semantic, destGPR); });
7728 m_jit.setupArgument(
7729 1, [&] (GPRReg destGPR) {
7730 m_jit.move(
7731 TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.globalObjectFor(node->origin.semantic)->scopedArgumentsStructure()),
7732 destGPR);
7733 });
7734 m_jit.setupArgument(0, [&] (GPRReg destGPR) { m_jit.move(GPRInfo::callFrameRegister, destGPR); });
7735
7736 appendCallSetResult(operationCreateScopedArguments, resultGPR);
7737 m_jit.exceptionCheck();
7738
7739 cellResult(resultGPR, node);
7740}
7741
7742void SpeculativeJIT::compileCreateClonedArguments(Node* node)
7743{
7744 GPRFlushedCallResult result(this);
7745 GPRReg resultGPR = result.gpr();
7746 flushRegisters();
7747
7748 // We set up the arguments ourselves, because we have the whole register file and we can
7749 // set them up directly into the argument registers.
7750
7751 // Arguments: 0:exec, 1:structure, 2:start, 3:length, 4:callee
7752 m_jit.setupArgument(4, [&] (GPRReg destGPR) { emitGetCallee(node->origin.semantic, destGPR); });
7753 m_jit.setupArgument(3, [&] (GPRReg destGPR) { emitGetLength(node->origin.semantic, destGPR); });
7754 m_jit.setupArgument(2, [&] (GPRReg destGPR) { emitGetArgumentStart(node->origin.semantic, destGPR); });
7755 m_jit.setupArgument(
7756 1, [&] (GPRReg destGPR) {
7757 m_jit.move(
7758 TrustedImmPtr::weakPointer(
7759 m_jit.graph(), m_jit.globalObjectFor(node->origin.semantic)->clonedArgumentsStructure()),
7760 destGPR);
7761 });
7762 m_jit.setupArgument(0, [&] (GPRReg destGPR) { m_jit.move(GPRInfo::callFrameRegister, destGPR); });
7763
7764 appendCallSetResult(operationCreateClonedArguments, resultGPR);
7765 m_jit.exceptionCheck();
7766
7767 cellResult(resultGPR, node);
7768}
7769
7770void SpeculativeJIT::compileCreateRest(Node* node)
7771{
7772 ASSERT(node->op() == CreateRest);
7773
7774#if !CPU(X86)
7775 if (m_jit.graph().isWatchingHavingABadTimeWatchpoint(node)) {
7776 SpeculateStrictInt32Operand arrayLength(this, node->child1());
7777 GPRTemporary arrayResult(this);
7778
7779 GPRReg arrayLengthGPR = arrayLength.gpr();
7780 GPRReg arrayResultGPR = arrayResult.gpr();
7781
7782 // We can tell compileAllocateNewArrayWithSize() that it does not need to check
7783 // for large arrays and use ArrayStorage structure because arrayLength here will
7784 // always be bounded by stack size. Realistically, we won't be able to push enough
7785 // arguments to have arrayLength exceed MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH.
7786 bool shouldAllowForArrayStorageStructureForLargeArrays = false;
7787 ASSERT(m_jit.graph().globalObjectFor(node->origin.semantic)->restParameterStructure()->indexingMode() == ArrayWithContiguous || m_jit.graph().globalObjectFor(node->origin.semantic)->isHavingABadTime());
7788 compileAllocateNewArrayWithSize(m_jit.graph().globalObjectFor(node->origin.semantic), arrayResultGPR, arrayLengthGPR, ArrayWithContiguous, shouldAllowForArrayStorageStructureForLargeArrays);
7789
7790 GPRTemporary argumentsStart(this);
7791 GPRReg argumentsStartGPR = argumentsStart.gpr();
7792
7793 emitGetArgumentStart(node->origin.semantic, argumentsStartGPR);
7794
7795 GPRTemporary butterfly(this);
7796 GPRTemporary currentLength(this);
7797 JSValueRegsTemporary value(this);
7798
7799 JSValueRegs valueRegs = value.regs();
7800 GPRReg currentLengthGPR = currentLength.gpr();
7801 GPRReg butterflyGPR = butterfly.gpr();
7802
7803 m_jit.loadPtr(MacroAssembler::Address(arrayResultGPR, JSObject::butterflyOffset()), butterflyGPR);
7804
7805 CCallHelpers::Jump skipLoop = m_jit.branch32(MacroAssembler::Equal, arrayLengthGPR, TrustedImm32(0));
7806 m_jit.zeroExtend32ToPtr(arrayLengthGPR, currentLengthGPR);
7807 m_jit.addPtr(Imm32(sizeof(Register) * node->numberOfArgumentsToSkip()), argumentsStartGPR);
7808
7809 auto loop = m_jit.label();
7810 m_jit.sub32(TrustedImm32(1), currentLengthGPR);
7811 m_jit.loadValue(JITCompiler::BaseIndex(argumentsStartGPR, currentLengthGPR, MacroAssembler::TimesEight), valueRegs);
7812 m_jit.storeValue(valueRegs, MacroAssembler::BaseIndex(butterflyGPR, currentLengthGPR, MacroAssembler::TimesEight));
7813 m_jit.branch32(MacroAssembler::NotEqual, currentLengthGPR, TrustedImm32(0)).linkTo(loop, &m_jit);
7814
7815 skipLoop.link(&m_jit);
7816 cellResult(arrayResultGPR, node);
7817 return;
7818 }
7819#endif // !CPU(X86)
7820
7821 SpeculateStrictInt32Operand arrayLength(this, node->child1());
7822 GPRTemporary argumentsStart(this);
7823 GPRTemporary numberOfArgumentsToSkip(this);
7824
7825 GPRReg arrayLengthGPR = arrayLength.gpr();
7826 GPRReg argumentsStartGPR = argumentsStart.gpr();
7827
7828 emitGetArgumentStart(node->origin.semantic, argumentsStartGPR);
7829
7830 flushRegisters();
7831
7832 GPRFlushedCallResult result(this);
7833 GPRReg resultGPR = result.gpr();
7834 callOperation(operationCreateRest, resultGPR, argumentsStartGPR, Imm32(node->numberOfArgumentsToSkip()), arrayLengthGPR);
7835 m_jit.exceptionCheck();
7836
7837 cellResult(resultGPR, node);
7838}
7839
7840void SpeculativeJIT::compileSpread(Node* node)
7841{
7842 ASSERT(node->op() == Spread);
7843
7844 SpeculateCellOperand operand(this, node->child1());
7845 GPRReg argument = operand.gpr();
7846
7847 if (node->child1().useKind() == ArrayUse)
7848 speculateArray(node->child1(), argument);
7849
7850 if (m_jit.graph().canDoFastSpread(node, m_state.forNode(node->child1()))) {
7851#if USE(JSVALUE64)
7852 GPRTemporary result(this);
7853 GPRTemporary scratch1(this);
7854 GPRTemporary scratch2(this);
7855 GPRTemporary length(this);
7856 FPRTemporary doubleRegister(this);
7857
7858 GPRReg resultGPR = result.gpr();
7859 GPRReg scratch1GPR = scratch1.gpr();
7860 GPRReg scratch2GPR = scratch2.gpr();
7861 GPRReg lengthGPR = length.gpr();
7862 FPRReg doubleFPR = doubleRegister.fpr();
7863
7864 MacroAssembler::JumpList slowPath;
7865
7866 m_jit.load8(MacroAssembler::Address(argument, JSCell::indexingTypeAndMiscOffset()), scratch1GPR);
7867 m_jit.and32(TrustedImm32(IndexingShapeMask), scratch1GPR);
7868 m_jit.sub32(TrustedImm32(Int32Shape), scratch1GPR);
7869
7870 slowPath.append(m_jit.branch32(MacroAssembler::Above, scratch1GPR, TrustedImm32(ContiguousShape - Int32Shape)));
7871
7872 m_jit.loadPtr(MacroAssembler::Address(argument, JSObject::butterflyOffset()), lengthGPR);
7873 m_jit.load32(MacroAssembler::Address(lengthGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
7874 static_assert(sizeof(JSValue) == 8 && 1 << 3 == 8, "This is strongly assumed in the code below.");
7875 m_jit.move(lengthGPR, scratch1GPR);
7876 m_jit.lshift32(TrustedImm32(3), scratch1GPR);
7877 m_jit.add32(TrustedImm32(JSFixedArray::offsetOfData()), scratch1GPR);
7878
7879 m_jit.emitAllocateVariableSizedCell<JSFixedArray>(*m_jit.vm(), resultGPR, TrustedImmPtr(m_jit.graph().registerStructure(m_jit.graph().m_vm.fixedArrayStructure.get())), scratch1GPR, scratch1GPR, scratch2GPR, slowPath);
7880 m_jit.store32(lengthGPR, MacroAssembler::Address(resultGPR, JSFixedArray::offsetOfSize()));
7881
7882 m_jit.loadPtr(MacroAssembler::Address(argument, JSObject::butterflyOffset()), scratch1GPR);
7883
7884 MacroAssembler::JumpList done;
7885
7886 m_jit.load8(MacroAssembler::Address(argument, JSCell::indexingTypeAndMiscOffset()), scratch2GPR);
7887 m_jit.and32(TrustedImm32(IndexingShapeMask), scratch2GPR);
7888 auto isDoubleArray = m_jit.branch32(MacroAssembler::Equal, scratch2GPR, TrustedImm32(DoubleShape));
7889
7890 {
7891 done.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR));
7892 auto loopStart = m_jit.label();
7893 m_jit.sub32(TrustedImm32(1), lengthGPR);
7894 m_jit.load64(MacroAssembler::BaseIndex(scratch1GPR, lengthGPR, MacroAssembler::TimesEight), scratch2GPR);
7895 auto notEmpty = m_jit.branchIfNotEmpty(scratch2GPR);
7896 m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), scratch2GPR);
7897 notEmpty.link(&m_jit);
7898 m_jit.store64(scratch2GPR, MacroAssembler::BaseIndex(resultGPR, lengthGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()));
7899 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loopStart, &m_jit);
7900 done.append(m_jit.jump());
7901 }
7902
7903 isDoubleArray.link(&m_jit);
7904 {
7905 done.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR));
7906 auto loopStart = m_jit.label();
7907 m_jit.sub32(TrustedImm32(1), lengthGPR);
7908 m_jit.loadDouble(MacroAssembler::BaseIndex(scratch1GPR, lengthGPR, MacroAssembler::TimesEight), doubleFPR);
7909 auto notEmpty = m_jit.branchIfNotNaN(doubleFPR);
7910 m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), scratch2GPR);
7911 auto doStore = m_jit.jump();
7912 notEmpty.link(&m_jit);
7913 m_jit.boxDouble(doubleFPR, scratch2GPR);
7914 doStore.link(&m_jit);
7915 m_jit.store64(scratch2GPR, MacroAssembler::BaseIndex(resultGPR, lengthGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()));
7916 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loopStart, &m_jit);
7917 done.append(m_jit.jump());
7918 }
7919
7920 m_jit.mutatorFence(*m_jit.vm());
7921
7922 slowPath.link(&m_jit);
7923 addSlowPathGenerator(slowPathCall(m_jit.jump(), this, operationSpreadFastArray, resultGPR, argument));
7924
7925 done.link(&m_jit);
7926 cellResult(resultGPR, node);
7927#else
7928 flushRegisters();
7929
7930 GPRFlushedCallResult result(this);
7931 GPRReg resultGPR = result.gpr();
7932 callOperation(operationSpreadFastArray, resultGPR, argument);
7933 m_jit.exceptionCheck();
7934 cellResult(resultGPR, node);
7935#endif // USE(JSVALUE64)
7936 } else {
7937 flushRegisters();
7938
7939 GPRFlushedCallResult result(this);
7940 GPRReg resultGPR = result.gpr();
7941 callOperation(operationSpreadGeneric, resultGPR, argument);
7942 m_jit.exceptionCheck();
7943 cellResult(resultGPR, node);
7944 }
7945}
7946
7947void SpeculativeJIT::compileNewArray(Node* node)
7948{
7949 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
7950 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(node->indexingType())) {
7951 RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
7952 DFG_ASSERT(m_jit.graph(), node, structure->indexingType() == node->indexingType(), structure->indexingType(), node->indexingType());
7953 ASSERT(
7954 hasUndecided(structure->indexingType())
7955 || hasInt32(structure->indexingType())
7956 || hasDouble(structure->indexingType())
7957 || hasContiguous(structure->indexingType()));
7958
7959 unsigned numElements = node->numChildren();
7960 unsigned vectorLengthHint = node->vectorLengthHint();
7961 ASSERT(vectorLengthHint >= numElements);
7962
7963 GPRTemporary result(this);
7964 GPRTemporary storage(this);
7965
7966 GPRReg resultGPR = result.gpr();
7967 GPRReg storageGPR = storage.gpr();
7968
7969 emitAllocateRawObject(resultGPR, structure, storageGPR, numElements, vectorLengthHint);
7970
7971 // At this point, one way or another, resultGPR and storageGPR have pointers to
7972 // the JSArray and the Butterfly, respectively.
7973
7974 ASSERT(!hasUndecided(structure->indexingType()) || !node->numChildren());
7975
7976 for (unsigned operandIdx = 0; operandIdx < node->numChildren(); ++operandIdx) {
7977 Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + operandIdx];
7978 switch (node->indexingType()) {
7979 case ALL_BLANK_INDEXING_TYPES:
7980 case ALL_UNDECIDED_INDEXING_TYPES:
7981 CRASH();
7982 break;
7983 case ALL_DOUBLE_INDEXING_TYPES: {
7984 SpeculateDoubleOperand operand(this, use);
7985 FPRReg opFPR = operand.fpr();
7986 DFG_TYPE_CHECK(
7987 JSValueRegs(), use, SpecDoubleReal,
7988 m_jit.branchIfNaN(opFPR));
7989 m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx));
7990 break;
7991 }
7992 case ALL_INT32_INDEXING_TYPES:
7993 case ALL_CONTIGUOUS_INDEXING_TYPES: {
7994 JSValueOperand operand(this, use, ManualOperandSpeculation);
7995 JSValueRegs operandRegs = operand.jsValueRegs();
7996 if (hasInt32(node->indexingType())) {
7997 DFG_TYPE_CHECK(
7998 operandRegs, use, SpecInt32Only,
7999 m_jit.branchIfNotInt32(operandRegs));
8000 }
8001 m_jit.storeValue(operandRegs, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx));
8002 break;
8003 }
8004 default:
8005 CRASH();
8006 break;
8007 }
8008 }
8009
8010 // Yuck, we should *really* have a way of also returning the storageGPR. But
8011 // that's the least of what's wrong with this code. We really shouldn't be
8012 // allocating the array after having computed - and probably spilled to the
8013 // stack - all of the things that will go into the array. The solution to that
8014 // bigger problem will also likely fix the redundancy in reloading the storage
8015 // pointer that we currently have.
8016
8017 cellResult(resultGPR, node);
8018 return;
8019 }
8020
8021 if (!node->numChildren()) {
8022 flushRegisters();
8023 GPRFlushedCallResult result(this);
8024 callOperation(operationNewEmptyArray, result.gpr(), m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())));
8025 m_jit.exceptionCheck();
8026 cellResult(result.gpr(), node);
8027 return;
8028 }
8029
8030 size_t scratchSize = sizeof(EncodedJSValue) * node->numChildren();
8031 ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
8032 EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : nullptr;
8033
8034 for (unsigned operandIdx = 0; operandIdx < node->numChildren(); ++operandIdx) {
8035 // Need to perform the speculations that this node promises to perform. If we're
8036 // emitting code here and the indexing type is not array storage then there is
8037 // probably something hilarious going on and we're already failing at all the
8038 // things, but at least we're going to be sound.
8039 Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + operandIdx];
8040 switch (node->indexingType()) {
8041 case ALL_BLANK_INDEXING_TYPES:
8042 case ALL_UNDECIDED_INDEXING_TYPES:
8043 CRASH();
8044 break;
8045 case ALL_DOUBLE_INDEXING_TYPES: {
8046 SpeculateDoubleOperand operand(this, use);
8047 FPRReg opFPR = operand.fpr();
8048 DFG_TYPE_CHECK(
8049 JSValueRegs(), use, SpecDoubleReal,
8050 m_jit.branchIfNaN(opFPR));
8051#if USE(JSVALUE64)
8052 JSValueRegsTemporary scratch(this);
8053 JSValueRegs scratchRegs = scratch.regs();
8054 m_jit.boxDouble(opFPR, scratchRegs);
8055 m_jit.storeValue(scratchRegs, buffer + operandIdx);
8056#else
8057 m_jit.storeDouble(opFPR, TrustedImmPtr(buffer + operandIdx));
8058#endif
8059 operand.use();
8060 break;
8061 }
8062 case ALL_INT32_INDEXING_TYPES:
8063 case ALL_CONTIGUOUS_INDEXING_TYPES:
8064 case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
8065 JSValueOperand operand(this, use, ManualOperandSpeculation);
8066 JSValueRegs operandRegs = operand.jsValueRegs();
8067 if (hasInt32(node->indexingType())) {
8068 DFG_TYPE_CHECK(
8069 operandRegs, use, SpecInt32Only,
8070 m_jit.branchIfNotInt32(operandRegs));
8071 }
8072 m_jit.storeValue(operandRegs, buffer + operandIdx);
8073 operand.use();
8074 break;
8075 }
8076 default:
8077 CRASH();
8078 break;
8079 }
8080 }
8081
8082 flushRegisters();
8083
8084 if (scratchSize) {
8085 GPRTemporary scratch(this);
8086
8087 // Tell GC mark phase how much of the scratch buffer is active during call.
8088 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratch.gpr());
8089 m_jit.storePtr(TrustedImmPtr(scratchSize), scratch.gpr());
8090 }
8091
8092 GPRFlushedCallResult result(this);
8093
8094 callOperation(
8095 operationNewArray, result.gpr(), m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())),
8096 static_cast<void*>(buffer), size_t(node->numChildren()));
8097 m_jit.exceptionCheck();
8098
8099 if (scratchSize) {
8100 GPRTemporary scratch(this);
8101
8102 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratch.gpr());
8103 m_jit.storePtr(TrustedImmPtr(nullptr), scratch.gpr());
8104 }
8105
8106 cellResult(result.gpr(), node, UseChildrenCalledExplicitly);
8107}
8108
8109void SpeculativeJIT::compileNewArrayWithSpread(Node* node)
8110{
8111 ASSERT(node->op() == NewArrayWithSpread);
8112
8113#if USE(JSVALUE64)
8114 if (m_jit.graph().isWatchingHavingABadTimeWatchpoint(node)) {
8115 GPRTemporary result(this);
8116 GPRReg resultGPR = result.gpr();
8117
8118 BitVector* bitVector = node->bitVector();
8119 {
8120 unsigned startLength = 0;
8121 for (unsigned i = 0; i < node->numChildren(); ++i) {
8122 if (!bitVector->get(i))
8123 ++startLength;
8124 }
8125
8126 GPRTemporary length(this);
8127 GPRReg lengthGPR = length.gpr();
8128 m_jit.move(TrustedImm32(startLength), lengthGPR);
8129
8130 for (unsigned i = 0; i < node->numChildren(); ++i) {
8131 if (bitVector->get(i)) {
8132 Edge use = m_jit.graph().varArgChild(node, i);
8133 SpeculateCellOperand fixedArray(this, use);
8134 GPRReg fixedArrayGPR = fixedArray.gpr();
8135 speculationCheck(Overflow, JSValueRegs(), nullptr, m_jit.branchAdd32(MacroAssembler::Overflow, MacroAssembler::Address(fixedArrayGPR, JSFixedArray::offsetOfSize()), lengthGPR));
8136 }
8137 }
8138
8139 speculationCheck(Overflow, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::AboveOrEqual, lengthGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)));
8140
8141 // We can tell compileAllocateNewArrayWithSize() that it does not need to
8142 // check for large arrays and use ArrayStorage structure because we already
8143 // ensured above that the spread array length will definitely fit in a
8144 // non-ArrayStorage shaped array.
8145 bool shouldAllowForArrayStorageStructureForLargeArrays = false;
8146 ASSERT(m_jit.graph().globalObjectFor(node->origin.semantic)->restParameterStructure()->indexingType() == ArrayWithContiguous || m_jit.graph().globalObjectFor(node->origin.semantic)->isHavingABadTime());
8147 compileAllocateNewArrayWithSize(m_jit.graph().globalObjectFor(node->origin.semantic), resultGPR, lengthGPR, ArrayWithContiguous, shouldAllowForArrayStorageStructureForLargeArrays);
8148 }
8149
8150 GPRTemporary index(this);
8151 GPRReg indexGPR = index.gpr();
8152
8153 GPRTemporary storage(this);
8154 GPRReg storageGPR = storage.gpr();
8155
8156 m_jit.move(TrustedImm32(0), indexGPR);
8157 m_jit.loadPtr(MacroAssembler::Address(resultGPR, JSObject::butterflyOffset()), storageGPR);
8158
8159 for (unsigned i = 0; i < node->numChildren(); ++i) {
8160 Edge use = m_jit.graph().varArgChild(node, i);
8161 if (bitVector->get(i)) {
8162 SpeculateCellOperand fixedArray(this, use);
8163 GPRReg fixedArrayGPR = fixedArray.gpr();
8164
8165 GPRTemporary fixedIndex(this);
8166 GPRReg fixedIndexGPR = fixedIndex.gpr();
8167
8168 GPRTemporary item(this);
8169 GPRReg itemGPR = item.gpr();
8170
8171 GPRTemporary fixedLength(this);
8172 GPRReg fixedLengthGPR = fixedLength.gpr();
8173
8174 m_jit.load32(MacroAssembler::Address(fixedArrayGPR, JSFixedArray::offsetOfSize()), fixedLengthGPR);
8175 m_jit.move(TrustedImm32(0), fixedIndexGPR);
8176 auto done = m_jit.branchPtr(MacroAssembler::AboveOrEqual, fixedIndexGPR, fixedLengthGPR);
8177 auto loopStart = m_jit.label();
8178 m_jit.load64(
8179 MacroAssembler::BaseIndex(fixedArrayGPR, fixedIndexGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()),
8180 itemGPR);
8181
8182 m_jit.store64(itemGPR, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight));
8183 m_jit.addPtr(TrustedImm32(1), fixedIndexGPR);
8184 m_jit.addPtr(TrustedImm32(1), indexGPR);
8185 m_jit.branchPtr(MacroAssembler::Below, fixedIndexGPR, fixedLengthGPR).linkTo(loopStart, &m_jit);
8186
8187 done.link(&m_jit);
8188 } else {
8189 JSValueOperand item(this, use);
8190 GPRReg itemGPR = item.gpr();
8191 m_jit.store64(itemGPR, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight));
8192 m_jit.addPtr(TrustedImm32(1), indexGPR);
8193 }
8194 }
8195
8196 cellResult(resultGPR, node);
8197 return;
8198 }
8199#endif // USE(JSVALUE64)
8200
8201 ASSERT(node->numChildren());
8202 size_t scratchSize = sizeof(EncodedJSValue) * node->numChildren();
8203 ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
8204 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
8205
8206 BitVector* bitVector = node->bitVector();
8207 for (unsigned i = 0; i < node->numChildren(); ++i) {
8208 Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + i];
8209 if (bitVector->get(i)) {
8210 SpeculateCellOperand fixedArray(this, use);
8211 GPRReg arrayGPR = fixedArray.gpr();
8212#if USE(JSVALUE64)
8213 m_jit.store64(arrayGPR, &buffer[i]);
8214#else
8215 char* pointer = static_cast<char*>(static_cast<void*>(&buffer[i]));
8216 m_jit.store32(arrayGPR, pointer + PayloadOffset);
8217 m_jit.store32(TrustedImm32(JSValue::CellTag), pointer + TagOffset);
8218#endif
8219 } else {
8220 JSValueOperand input(this, use);
8221 JSValueRegs inputRegs = input.jsValueRegs();
8222 m_jit.storeValue(inputRegs, &buffer[i]);
8223 }
8224 }
8225
8226 {
8227 GPRTemporary scratch(this);
8228 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratch.gpr());
8229 m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(scratch.gpr()));
8230 }
8231
8232 flushRegisters();
8233
8234 GPRFlushedCallResult result(this);
8235 GPRReg resultGPR = result.gpr();
8236
8237 callOperation(operationNewArrayWithSpreadSlow, resultGPR, buffer, node->numChildren());
8238 m_jit.exceptionCheck();
8239 {
8240 GPRTemporary scratch(this);
8241 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratch.gpr());
8242 m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(scratch.gpr()));
8243 }
8244
8245 cellResult(resultGPR, node);
8246}
8247
8248void SpeculativeJIT::compileGetRestLength(Node* node)
8249{
8250 ASSERT(node->op() == GetRestLength);
8251
8252 GPRTemporary result(this);
8253 GPRReg resultGPR = result.gpr();
8254
8255 emitGetLength(node->origin.semantic, resultGPR);
8256 CCallHelpers::Jump hasNonZeroLength = m_jit.branch32(MacroAssembler::Above, resultGPR, Imm32(node->numberOfArgumentsToSkip()));
8257 m_jit.move(TrustedImm32(0), resultGPR);
8258 CCallHelpers::Jump done = m_jit.jump();
8259 hasNonZeroLength.link(&m_jit);
8260 if (node->numberOfArgumentsToSkip())
8261 m_jit.sub32(TrustedImm32(node->numberOfArgumentsToSkip()), resultGPR);
8262 done.link(&m_jit);
8263 int32Result(resultGPR, node);
8264}
8265
8266void SpeculativeJIT::emitPopulateSliceIndex(Edge& target, Optional<GPRReg> indexGPR, GPRReg lengthGPR, GPRReg resultGPR)
8267{
8268 if (target->isInt32Constant()) {
8269 int32_t value = target->asInt32();
8270 if (value == 0) {
8271 m_jit.move(TrustedImm32(0), resultGPR);
8272 return;
8273 }
8274
8275 MacroAssembler::JumpList done;
8276 if (value > 0) {
8277 m_jit.move(TrustedImm32(value), resultGPR);
8278 done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, resultGPR, lengthGPR));
8279 m_jit.move(lengthGPR, resultGPR);
8280 } else {
8281 ASSERT(value != 0);
8282 m_jit.move(lengthGPR, resultGPR);
8283 done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, TrustedImm32(value), resultGPR));
8284 m_jit.move(TrustedImm32(0), resultGPR);
8285 }
8286 done.link(&m_jit);
8287 return;
8288 }
8289
8290 Optional<SpeculateInt32Operand> index;
8291 if (!indexGPR) {
8292 index.emplace(this, target);
8293 indexGPR = index->gpr();
8294 }
8295 MacroAssembler::JumpList done;
8296
8297 auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR.value(), TrustedImm32(0));
8298 m_jit.move(lengthGPR, resultGPR);
8299 done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR.value(), resultGPR));
8300 m_jit.move(TrustedImm32(0), resultGPR);
8301 done.append(m_jit.jump());
8302
8303 isPositive.link(&m_jit);
8304 m_jit.move(indexGPR.value(), resultGPR);
8305 done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, resultGPR, lengthGPR));
8306 m_jit.move(lengthGPR, resultGPR);
8307
8308 done.link(&m_jit);
8309}
8310
8311void SpeculativeJIT::compileArraySlice(Node* node)
8312{
8313 ASSERT(node->op() == ArraySlice);
8314
8315 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
8316
8317 GPRTemporary temp(this);
8318 StorageOperand storage(this, m_jit.graph().varArgChild(node, node->numChildren() - 1));
8319 GPRTemporary result(this);
8320
8321 GPRReg storageGPR = storage.gpr();
8322 GPRReg resultGPR = result.gpr();
8323 GPRReg tempGPR = temp.gpr();
8324
8325 if (node->numChildren() == 2)
8326 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempGPR);
8327 else {
8328 ASSERT(node->numChildren() == 3 || node->numChildren() == 4);
8329 GPRTemporary tempLength(this);
8330 GPRReg lengthGPR = tempLength.gpr();
8331 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
8332
8333 if (node->numChildren() == 4)
8334 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, lengthGPR, tempGPR);
8335 else
8336 m_jit.move(lengthGPR, tempGPR);
8337
8338 if (m_jit.graph().varArgChild(node, 1)->isInt32Constant() && m_jit.graph().varArgChild(node, 1)->asInt32() == 0) {
8339 // Do nothing for array.slice(0, end) or array.slice(0) cases.
8340 // `tempGPR` already points to the size of a newly created array.
8341 } else {
8342 GPRTemporary tempStartIndex(this);
8343 GPRReg startGPR = tempStartIndex.gpr();
8344 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), WTF::nullopt, lengthGPR, startGPR);
8345
8346 auto tooBig = m_jit.branch32(MacroAssembler::Above, startGPR, tempGPR);
8347 m_jit.sub32(startGPR, tempGPR); // the size of the array we'll make.
8348 auto done = m_jit.jump();
8349
8350 tooBig.link(&m_jit);
8351 m_jit.move(TrustedImm32(0), tempGPR);
8352 done.link(&m_jit);
8353 }
8354 }
8355
8356 GPRTemporary temp3(this);
8357 GPRReg tempValue = temp3.gpr();
8358
8359 {
8360 // We need to keep the source array alive at least until after we're done
8361 // with anything that can GC (e.g. allocating the result array below).
8362 SpeculateCellOperand cell(this, m_jit.graph().varArgChild(node, 0));
8363
8364 m_jit.load8(MacroAssembler::Address(cell.gpr(), JSCell::indexingTypeAndMiscOffset()), tempValue);
8365 // We can ignore the writability of the cell since we won't write to the source.
8366 m_jit.and32(TrustedImm32(AllWritableArrayTypesAndHistory), tempValue);
8367
8368 JSValueRegsTemporary emptyValue(this);
8369 JSValueRegs emptyValueRegs = emptyValue.regs();
8370
8371 GPRTemporary storage(this);
8372 GPRReg storageResultGPR = storage.gpr();
8373
8374 GPRReg sizeGPR = tempGPR;
8375
8376 CCallHelpers::JumpList done;
8377
8378 auto emitMoveEmptyValue = [&] (JSValue v) {
8379 m_jit.moveValue(v, emptyValueRegs);
8380 };
8381
8382 auto isContiguous = m_jit.branch32(MacroAssembler::Equal, tempValue, TrustedImm32(ArrayWithContiguous));
8383 auto isInt32 = m_jit.branch32(MacroAssembler::Equal, tempValue, TrustedImm32(ArrayWithInt32));
8384 // When we emit an ArraySlice, we dominate the use of the array by a CheckStructure
8385 // to ensure the incoming array is one to be one of the original array structures
8386 // with one of the following indexing shapes: Int32, Contiguous, Double. Therefore,
8387 // we're a double array here.
8388 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithDouble))), tempValue);
8389 emitMoveEmptyValue(jsNaN());
8390 done.append(m_jit.jump());
8391
8392 isContiguous.link(&m_jit);
8393 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous))), tempValue);
8394 emitMoveEmptyValue(JSValue());
8395 done.append(m_jit.jump());
8396
8397 isInt32.link(&m_jit);
8398 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithInt32))), tempValue);
8399 emitMoveEmptyValue(JSValue());
8400
8401 done.link(&m_jit);
8402
8403 MacroAssembler::JumpList slowCases;
8404 m_jit.move(TrustedImmPtr(nullptr), storageResultGPR);
8405 // Enable the fast case on 64-bit platforms, where a sufficient amount of GP registers should be available.
8406 // Other platforms could support the same approach with custom code, but that is not currently worth the extra code maintenance.
8407 if (is64Bit()) {
8408 GPRTemporary scratch(this);
8409 GPRTemporary scratch2(this);
8410 GPRReg scratchGPR = scratch.gpr();
8411 GPRReg scratch2GPR = scratch2.gpr();
8412
8413 emitAllocateButterfly(storageResultGPR, sizeGPR, scratchGPR, scratch2GPR, resultGPR, slowCases);
8414 emitInitializeButterfly(storageResultGPR, sizeGPR, emptyValueRegs, scratchGPR);
8415 emitAllocateJSObject<JSArray>(resultGPR, tempValue, storageResultGPR, scratchGPR, scratch2GPR, slowCases);
8416 m_jit.mutatorFence(*m_jit.vm());
8417 } else {
8418 slowCases.append(m_jit.jump());
8419 }
8420
8421 addSlowPathGenerator(std::make_unique<CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator>(
8422 slowCases, this, operationNewArrayWithSize, resultGPR, tempValue, sizeGPR, storageResultGPR));
8423 }
8424
8425 GPRTemporary temp4(this);
8426 GPRReg loadIndex = temp4.gpr();
8427
8428 if (node->numChildren() == 2) {
8429 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempGPR);
8430 m_jit.move(TrustedImm32(0), loadIndex);
8431 } else {
8432 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempValue);
8433 if (node->numChildren() == 4)
8434 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, tempValue, tempGPR);
8435 else
8436 m_jit.move(tempValue, tempGPR);
8437 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), WTF::nullopt, tempValue, loadIndex);
8438 }
8439
8440 GPRTemporary temp5(this);
8441 GPRReg storeIndex = temp5.gpr();
8442 m_jit.move(TrustedImmPtr(nullptr), storeIndex);
8443
8444 GPRTemporary temp2(this);
8445 GPRReg resultButterfly = temp2.gpr();
8446
8447 m_jit.loadPtr(MacroAssembler::Address(resultGPR, JSObject::butterflyOffset()), resultButterfly);
8448 m_jit.zeroExtend32ToPtr(tempGPR, tempGPR);
8449 m_jit.zeroExtend32ToPtr(loadIndex, loadIndex);
8450 auto done = m_jit.branchPtr(MacroAssembler::AboveOrEqual, loadIndex, tempGPR);
8451
8452 auto loop = m_jit.label();
8453#if USE(JSVALUE64)
8454 m_jit.load64(
8455 MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight), tempValue);
8456 m_jit.store64(
8457 tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight));
8458#else
8459 m_jit.load32(
8460 MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight, PayloadOffset), tempValue);
8461 m_jit.store32(
8462 tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight, PayloadOffset));
8463 m_jit.load32(
8464 MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight, TagOffset), tempValue);
8465 m_jit.store32(
8466 tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight, TagOffset));
8467#endif // USE(JSVALUE64)
8468 m_jit.addPtr(TrustedImm32(1), loadIndex);
8469 m_jit.addPtr(TrustedImm32(1), storeIndex);
8470 m_jit.branchPtr(MacroAssembler::Below, loadIndex, tempGPR).linkTo(loop, &m_jit);
8471
8472 done.link(&m_jit);
8473 cellResult(resultGPR, node);
8474}
8475
8476void SpeculativeJIT::compileArrayIndexOf(Node* node)
8477{
8478 ASSERT(node->op() == ArrayIndexOf);
8479
8480 StorageOperand storage(this, m_jit.graph().varArgChild(node, node->numChildren() == 3 ? 2 : 3));
8481 GPRTemporary index(this);
8482 GPRTemporary tempLength(this);
8483
8484 GPRReg storageGPR = storage.gpr();
8485 GPRReg indexGPR = index.gpr();
8486 GPRReg lengthGPR = tempLength.gpr();
8487
8488 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
8489
8490 if (node->numChildren() == 4)
8491 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, lengthGPR, indexGPR);
8492 else
8493 m_jit.move(TrustedImm32(0), indexGPR);
8494
8495 Edge& searchElementEdge = m_jit.graph().varArgChild(node, 1);
8496 switch (searchElementEdge.useKind()) {
8497 case Int32Use:
8498 case ObjectUse:
8499 case SymbolUse:
8500 case OtherUse: {
8501 auto emitLoop = [&] (auto emitCompare) {
8502#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
8503 m_jit.clearRegisterAllocationOffsets();
8504#endif
8505
8506 m_jit.zeroExtend32ToPtr(lengthGPR, lengthGPR);
8507 m_jit.zeroExtend32ToPtr(indexGPR, indexGPR);
8508
8509 auto loop = m_jit.label();
8510 auto notFound = m_jit.branch32(CCallHelpers::Equal, indexGPR, lengthGPR);
8511
8512 auto found = emitCompare();
8513
8514 m_jit.add32(TrustedImm32(1), indexGPR);
8515 m_jit.jump().linkTo(loop, &m_jit);
8516
8517 notFound.link(&m_jit);
8518 m_jit.move(TrustedImm32(-1), indexGPR);
8519 found.link(&m_jit);
8520 int32Result(indexGPR, node);
8521 };
8522
8523 if (searchElementEdge.useKind() == Int32Use) {
8524 ASSERT(node->arrayMode().type() == Array::Int32);
8525#if USE(JSVALUE64)
8526 JSValueOperand searchElement(this, searchElementEdge, ManualOperandSpeculation);
8527 JSValueRegs searchElementRegs = searchElement.jsValueRegs();
8528 speculateInt32(searchElementEdge, searchElementRegs);
8529 GPRReg searchElementGPR = searchElementRegs.payloadGPR();
8530#else
8531 SpeculateInt32Operand searchElement(this, searchElementEdge);
8532 GPRReg searchElementGPR = searchElement.gpr();
8533
8534 GPRTemporary temp(this);
8535 GPRReg tempGPR = temp.gpr();
8536#endif
8537 emitLoop([&] () {
8538#if USE(JSVALUE64)
8539 auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementGPR);
8540#else
8541 auto skip = m_jit.branch32(CCallHelpers::NotEqual, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), TrustedImm32(JSValue::Int32Tag));
8542 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, PayloadOffset), tempGPR);
8543 auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementGPR);
8544 skip.link(&m_jit);
8545#endif
8546 return found;
8547 });
8548 return;
8549 }
8550
8551 if (searchElementEdge.useKind() == OtherUse) {
8552 ASSERT(node->arrayMode().type() == Array::Contiguous);
8553 JSValueOperand searchElement(this, searchElementEdge, ManualOperandSpeculation);
8554 GPRTemporary temp(this);
8555
8556 JSValueRegs searchElementRegs = searchElement.jsValueRegs();
8557 GPRReg tempGPR = temp.gpr();
8558 speculateOther(searchElementEdge, searchElementRegs, tempGPR);
8559
8560 emitLoop([&] () {
8561#if USE(JSVALUE64)
8562 auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementRegs.payloadGPR());
8563#else
8564 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), tempGPR);
8565 auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementRegs.tagGPR());
8566#endif
8567 return found;
8568 });
8569 return;
8570 }
8571
8572 ASSERT(node->arrayMode().type() == Array::Contiguous);
8573 SpeculateCellOperand searchElement(this, searchElementEdge);
8574 GPRReg searchElementGPR = searchElement.gpr();
8575
8576 if (searchElementEdge.useKind() == ObjectUse)
8577 speculateObject(searchElementEdge, searchElementGPR);
8578 else {
8579 ASSERT(searchElementEdge.useKind() == SymbolUse);
8580 speculateSymbol(searchElementEdge, searchElementGPR);
8581 }
8582
8583#if USE(JSVALUE32_64)
8584 GPRTemporary temp(this);
8585 GPRReg tempGPR = temp.gpr();
8586#endif
8587
8588 emitLoop([&] () {
8589#if USE(JSVALUE64)
8590 auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementGPR);
8591#else
8592 auto skip = m_jit.branch32(CCallHelpers::NotEqual, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), TrustedImm32(JSValue::CellTag));
8593 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, PayloadOffset), tempGPR);
8594 auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementGPR);
8595 skip.link(&m_jit);
8596#endif
8597 return found;
8598 });
8599 return;
8600 }
8601
8602 case DoubleRepUse: {
8603 ASSERT(node->arrayMode().type() == Array::Double);
8604 SpeculateDoubleOperand searchElement(this, searchElementEdge);
8605 FPRTemporary tempDouble(this);
8606
8607 FPRReg searchElementFPR = searchElement.fpr();
8608 FPRReg tempFPR = tempDouble.fpr();
8609
8610#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
8611 m_jit.clearRegisterAllocationOffsets();
8612#endif
8613
8614 m_jit.zeroExtend32ToPtr(lengthGPR, lengthGPR);
8615 m_jit.zeroExtend32ToPtr(indexGPR, indexGPR);
8616
8617 auto loop = m_jit.label();
8618 auto notFound = m_jit.branch32(CCallHelpers::Equal, indexGPR, lengthGPR);
8619 m_jit.loadDouble(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), tempFPR);
8620 auto found = m_jit.branchDouble(CCallHelpers::DoubleEqual, tempFPR, searchElementFPR);
8621 m_jit.add32(TrustedImm32(1), indexGPR);
8622 m_jit.jump().linkTo(loop, &m_jit);
8623
8624 notFound.link(&m_jit);
8625 m_jit.move(TrustedImm32(-1), indexGPR);
8626 found.link(&m_jit);
8627 int32Result(indexGPR, node);
8628 return;
8629 }
8630
8631 case StringUse: {
8632 ASSERT(node->arrayMode().type() == Array::Contiguous);
8633 SpeculateCellOperand searchElement(this, searchElementEdge);
8634
8635 GPRReg searchElementGPR = searchElement.gpr();
8636
8637 speculateString(searchElementEdge, searchElementGPR);
8638
8639 flushRegisters();
8640
8641 callOperation(operationArrayIndexOfString, lengthGPR, storageGPR, searchElementGPR, indexGPR);
8642 m_jit.exceptionCheck();
8643
8644 int32Result(lengthGPR, node);
8645 return;
8646 }
8647
8648 case UntypedUse: {
8649 JSValueOperand searchElement(this, searchElementEdge);
8650
8651 JSValueRegs searchElementRegs = searchElement.jsValueRegs();
8652
8653 flushRegisters();
8654 switch (node->arrayMode().type()) {
8655 case Array::Double:
8656 callOperation(operationArrayIndexOfValueDouble, lengthGPR, storageGPR, searchElementRegs, indexGPR);
8657 break;
8658 case Array::Int32:
8659 case Array::Contiguous:
8660 callOperation(operationArrayIndexOfValueInt32OrContiguous, lengthGPR, storageGPR, searchElementRegs, indexGPR);
8661 break;
8662 default:
8663 RELEASE_ASSERT_NOT_REACHED();
8664 break;
8665 }
8666 m_jit.exceptionCheck();
8667
8668 int32Result(lengthGPR, node);
8669 return;
8670 }
8671
8672 default:
8673 RELEASE_ASSERT_NOT_REACHED();
8674 return;
8675 }
8676}
8677
8678void SpeculativeJIT::compileArrayPush(Node* node)
8679{
8680 ASSERT(node->arrayMode().isJSArray());
8681
8682 Edge& storageEdge = m_jit.graph().varArgChild(node, 0);
8683 Edge& arrayEdge = m_jit.graph().varArgChild(node, 1);
8684
8685 SpeculateCellOperand base(this, arrayEdge);
8686 GPRTemporary storageLength(this);
8687
8688 GPRReg baseGPR = base.gpr();
8689 GPRReg storageLengthGPR = storageLength.gpr();
8690
8691 StorageOperand storage(this, storageEdge);
8692 GPRReg storageGPR = storage.gpr();
8693 unsigned elementOffset = 2;
8694 unsigned elementCount = node->numChildren() - elementOffset;
8695
8696#if USE(JSVALUE32_64)
8697 GPRTemporary tag(this);
8698 GPRReg tagGPR = tag.gpr();
8699 JSValueRegs resultRegs { tagGPR, storageLengthGPR };
8700#else
8701 JSValueRegs resultRegs { storageLengthGPR };
8702#endif
8703
8704 auto getStorageBufferAddress = [&] (GPRReg storageGPR, GPRReg indexGPR, int32_t offset, GPRReg bufferGPR) {
8705 static_assert(sizeof(JSValue) == 8 && 1 << 3 == 8, "This is strongly assumed in the code below.");
8706 m_jit.getEffectiveAddress(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, offset), bufferGPR);
8707 };
8708
8709 switch (node->arrayMode().type()) {
8710 case Array::Int32:
8711 case Array::Contiguous: {
8712 if (elementCount == 1) {
8713 Edge& element = m_jit.graph().varArgChild(node, elementOffset);
8714 if (node->arrayMode().type() == Array::Int32) {
8715 ASSERT(element.useKind() == Int32Use);
8716 speculateInt32(element);
8717 }
8718 JSValueOperand value(this, element, ManualOperandSpeculation);
8719 JSValueRegs valueRegs = value.jsValueRegs();
8720
8721 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
8722 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
8723 m_jit.storeValue(valueRegs, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
8724 m_jit.add32(TrustedImm32(1), storageLengthGPR);
8725 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
8726 m_jit.boxInt32(storageLengthGPR, resultRegs);
8727
8728 addSlowPathGenerator(
8729 slowPathCall(slowPath, this, operationArrayPush, resultRegs, valueRegs, baseGPR));
8730
8731 jsValueResult(resultRegs, node);
8732 return;
8733 }
8734
8735 if (node->arrayMode().type() == Array::Int32) {
8736 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8737 Edge element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8738 ASSERT(element.useKind() == Int32Use);
8739 speculateInt32(element);
8740 }
8741 }
8742
8743 GPRTemporary buffer(this);
8744 GPRReg bufferGPR = buffer.gpr();
8745
8746 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
8747 m_jit.move(storageLengthGPR, bufferGPR);
8748 m_jit.add32(TrustedImm32(elementCount), bufferGPR);
8749 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::Above, bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
8750
8751 m_jit.store32(bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
8752 getStorageBufferAddress(storageGPR, storageLengthGPR, 0, bufferGPR);
8753 m_jit.add32(TrustedImm32(elementCount), storageLengthGPR);
8754 m_jit.boxInt32(storageLengthGPR, resultRegs);
8755 auto storageDone = m_jit.jump();
8756
8757 slowPath.link(&m_jit);
8758
8759 size_t scratchSize = sizeof(EncodedJSValue) * elementCount;
8760 ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
8761 m_jit.move(TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())), bufferGPR);
8762 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), storageLengthGPR);
8763 m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(storageLengthGPR));
8764
8765 storageDone.link(&m_jit);
8766 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8767 Edge& element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8768 JSValueOperand value(this, element, ManualOperandSpeculation); // We did type checks above.
8769 JSValueRegs valueRegs = value.jsValueRegs();
8770
8771 m_jit.storeValue(valueRegs, MacroAssembler::Address(bufferGPR, sizeof(EncodedJSValue) * elementIndex));
8772 value.use();
8773 }
8774
8775 MacroAssembler::Jump fastPath = m_jit.branchPtr(MacroAssembler::NotEqual, bufferGPR, TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
8776
8777 addSlowPathGenerator(slowPathCall(m_jit.jump(), this, operationArrayPushMultiple, resultRegs, baseGPR, bufferGPR, TrustedImm32(elementCount)));
8778
8779 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), bufferGPR);
8780 m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(bufferGPR));
8781
8782 base.use();
8783 storage.use();
8784
8785 fastPath.link(&m_jit);
8786 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
8787 return;
8788 }
8789
8790 case Array::Double: {
8791 if (elementCount == 1) {
8792 Edge& element = m_jit.graph().varArgChild(node, elementOffset);
8793 speculate(node, element);
8794 SpeculateDoubleOperand value(this, element);
8795 FPRReg valueFPR = value.fpr();
8796
8797 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
8798 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
8799 m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
8800 m_jit.add32(TrustedImm32(1), storageLengthGPR);
8801 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
8802 m_jit.boxInt32(storageLengthGPR, resultRegs);
8803
8804 addSlowPathGenerator(
8805 slowPathCall(slowPath, this, operationArrayPushDouble, resultRegs, valueFPR, baseGPR));
8806
8807 jsValueResult(resultRegs, node);
8808 return;
8809 }
8810
8811 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8812 Edge element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8813 ASSERT(element.useKind() == DoubleRepRealUse);
8814 speculate(node, element);
8815 }
8816
8817 GPRTemporary buffer(this);
8818 GPRReg bufferGPR = buffer.gpr();
8819
8820 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
8821 m_jit.move(storageLengthGPR, bufferGPR);
8822 m_jit.add32(TrustedImm32(elementCount), bufferGPR);
8823 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::Above, bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
8824
8825 m_jit.store32(bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
8826 getStorageBufferAddress(storageGPR, storageLengthGPR, 0, bufferGPR);
8827 m_jit.add32(TrustedImm32(elementCount), storageLengthGPR);
8828 m_jit.boxInt32(storageLengthGPR, resultRegs);
8829 auto storageDone = m_jit.jump();
8830
8831 slowPath.link(&m_jit);
8832
8833 size_t scratchSize = sizeof(double) * elementCount;
8834 ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
8835 m_jit.move(TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())), bufferGPR);
8836 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), storageLengthGPR);
8837 m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(storageLengthGPR));
8838
8839 storageDone.link(&m_jit);
8840 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8841 Edge& element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8842 SpeculateDoubleOperand value(this, element);
8843 FPRReg valueFPR = value.fpr();
8844
8845 m_jit.storeDouble(valueFPR, MacroAssembler::Address(bufferGPR, sizeof(double) * elementIndex));
8846 value.use();
8847 }
8848
8849 MacroAssembler::Jump fastPath = m_jit.branchPtr(MacroAssembler::NotEqual, bufferGPR, TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
8850
8851 addSlowPathGenerator(slowPathCall(m_jit.jump(), this, operationArrayPushDoubleMultiple, resultRegs, baseGPR, bufferGPR, TrustedImm32(elementCount)));
8852
8853 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), bufferGPR);
8854 m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(bufferGPR));
8855
8856 base.use();
8857 storage.use();
8858
8859 fastPath.link(&m_jit);
8860 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
8861 return;
8862 }
8863
8864 case Array::ArrayStorage: {
8865 // This ensures that the result of ArrayPush is Int32 in AI.
8866 int32_t largestPositiveInt32Length = 0x7fffffff - elementCount;
8867 if (elementCount == 1) {
8868 Edge& element = m_jit.graph().varArgChild(node, elementOffset);
8869 JSValueOperand value(this, element);
8870 JSValueRegs valueRegs = value.jsValueRegs();
8871
8872 m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
8873
8874 // Refuse to handle bizarre lengths.
8875 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(largestPositiveInt32Length)));
8876
8877 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
8878
8879 m_jit.storeValue(valueRegs, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()));
8880
8881 m_jit.add32(TrustedImm32(1), storageLengthGPR);
8882 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
8883 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
8884 m_jit.boxInt32(storageLengthGPR, resultRegs);
8885
8886 addSlowPathGenerator(
8887 slowPathCall(slowPath, this, operationArrayPush, resultRegs, valueRegs, baseGPR));
8888
8889 jsValueResult(resultRegs, node);
8890 return;
8891 }
8892
8893 GPRTemporary buffer(this);
8894 GPRReg bufferGPR = buffer.gpr();
8895
8896 m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
8897
8898 // Refuse to handle bizarre lengths.
8899 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(largestPositiveInt32Length)));
8900
8901 m_jit.move(storageLengthGPR, bufferGPR);
8902 m_jit.add32(TrustedImm32(elementCount), bufferGPR);
8903 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::Above, bufferGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
8904
8905 m_jit.store32(bufferGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
8906 getStorageBufferAddress(storageGPR, storageLengthGPR, ArrayStorage::vectorOffset(), bufferGPR);
8907 m_jit.add32(TrustedImm32(elementCount), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
8908 m_jit.add32(TrustedImm32(elementCount), storageLengthGPR);
8909 m_jit.boxInt32(storageLengthGPR, resultRegs);
8910 auto storageDone = m_jit.jump();
8911
8912 slowPath.link(&m_jit);
8913
8914 size_t scratchSize = sizeof(EncodedJSValue) * elementCount;
8915 ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(scratchSize);
8916 m_jit.move(TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())), bufferGPR);
8917 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), storageLengthGPR);
8918 m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(storageLengthGPR));
8919
8920 storageDone.link(&m_jit);
8921 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8922 Edge& element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8923 JSValueOperand value(this, element);
8924 JSValueRegs valueRegs = value.jsValueRegs();
8925
8926 m_jit.storeValue(valueRegs, MacroAssembler::Address(bufferGPR, sizeof(EncodedJSValue) * elementIndex));
8927 value.use();
8928 }
8929
8930 MacroAssembler::Jump fastPath = m_jit.branchPtr(MacroAssembler::NotEqual, bufferGPR, TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
8931
8932 addSlowPathGenerator(
8933 slowPathCall(m_jit.jump(), this, operationArrayPushMultiple, resultRegs, baseGPR, bufferGPR, TrustedImm32(elementCount)));
8934
8935 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), bufferGPR);
8936 m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(bufferGPR));
8937
8938 base.use();
8939 storage.use();
8940
8941 fastPath.link(&m_jit);
8942 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
8943 return;
8944 }
8945
8946 default:
8947 RELEASE_ASSERT_NOT_REACHED();
8948 }
8949}
8950
8951void SpeculativeJIT::compileNotifyWrite(Node* node)
8952{
8953 WatchpointSet* set = node->watchpointSet();
8954
8955 JITCompiler::Jump slowCase = m_jit.branch8(
8956 JITCompiler::NotEqual,
8957 JITCompiler::AbsoluteAddress(set->addressOfState()),
8958 TrustedImm32(IsInvalidated));
8959
8960 addSlowPathGenerator(
8961 slowPathCall(slowCase, this, operationNotifyWrite, NeedToSpill, ExceptionCheckRequirement::CheckNotNeeded, NoResult, set));
8962
8963 noResult(node);
8964}
8965
8966void SpeculativeJIT::compileIsObject(Node* node)
8967{
8968 JSValueOperand value(this, node->child1());
8969 GPRTemporary result(this, Reuse, value, TagWord);
8970
8971 JSValueRegs valueRegs = value.jsValueRegs();
8972 GPRReg resultGPR = result.gpr();
8973
8974 JITCompiler::Jump isNotCell = m_jit.branchIfNotCell(valueRegs);
8975
8976 m_jit.compare8(JITCompiler::AboveOrEqual,
8977 JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoTypeOffset()),
8978 TrustedImm32(ObjectType),
8979 resultGPR);
8980 JITCompiler::Jump done = m_jit.jump();
8981
8982 isNotCell.link(&m_jit);
8983 m_jit.move(TrustedImm32(0), resultGPR);
8984
8985 done.link(&m_jit);
8986 unblessedBooleanResult(resultGPR, node);
8987}
8988
8989void SpeculativeJIT::compileIsObjectOrNull(Node* node)
8990{
8991 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
8992
8993 JSValueOperand value(this, node->child1());
8994 JSValueRegs valueRegs = value.jsValueRegs();
8995
8996 GPRTemporary result(this);
8997 GPRReg resultGPR = result.gpr();
8998
8999 JITCompiler::Jump isCell = m_jit.branchIfCell(valueRegs);
9000
9001 JITCompiler::Jump isNull = m_jit.branchIfEqual(valueRegs, jsNull());
9002 JITCompiler::Jump isNonNullNonCell = m_jit.jump();
9003
9004 isCell.link(&m_jit);
9005 JITCompiler::Jump isFunction = m_jit.branchIfFunction(valueRegs.payloadGPR());
9006 JITCompiler::Jump notObject = m_jit.branchIfNotObject(valueRegs.payloadGPR());
9007
9008 JITCompiler::Jump slowPath = m_jit.branchTest8(
9009 JITCompiler::NonZero,
9010 JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoFlagsOffset()),
9011 TrustedImm32(MasqueradesAsUndefined | OverridesGetCallData));
9012
9013 isNull.link(&m_jit);
9014 m_jit.move(TrustedImm32(1), resultGPR);
9015 JITCompiler::Jump done = m_jit.jump();
9016
9017 isNonNullNonCell.link(&m_jit);
9018 isFunction.link(&m_jit);
9019 notObject.link(&m_jit);
9020 m_jit.move(TrustedImm32(0), resultGPR);
9021
9022 addSlowPathGenerator(
9023 slowPathCall(
9024 slowPath, this, operationObjectIsObject, resultGPR, globalObject,
9025 valueRegs.payloadGPR()));
9026
9027 done.link(&m_jit);
9028
9029 unblessedBooleanResult(resultGPR, node);
9030}
9031
9032void SpeculativeJIT::compileIsFunction(Node* node)
9033{
9034 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
9035
9036 JSValueOperand value(this, node->child1());
9037 JSValueRegs valueRegs = value.jsValueRegs();
9038
9039 GPRTemporary result(this);
9040 GPRReg resultGPR = result.gpr();
9041
9042 JITCompiler::Jump notCell = m_jit.branchIfNotCell(valueRegs);
9043 JITCompiler::Jump isFunction = m_jit.branchIfFunction(valueRegs.payloadGPR());
9044 JITCompiler::Jump notObject = m_jit.branchIfNotObject(valueRegs.payloadGPR());
9045
9046 JITCompiler::Jump slowPath = m_jit.branchTest8(
9047 JITCompiler::NonZero,
9048 JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoFlagsOffset()),
9049 TrustedImm32(MasqueradesAsUndefined | OverridesGetCallData));
9050
9051 notCell.link(&m_jit);
9052 notObject.link(&m_jit);
9053 m_jit.move(TrustedImm32(0), resultGPR);
9054 JITCompiler::Jump done = m_jit.jump();
9055
9056 isFunction.link(&m_jit);
9057 m_jit.move(TrustedImm32(1), resultGPR);
9058
9059 addSlowPathGenerator(
9060 slowPathCall(
9061 slowPath, this, operationObjectIsFunction, resultGPR, globalObject,
9062 valueRegs.payloadGPR()));
9063
9064 done.link(&m_jit);
9065
9066 unblessedBooleanResult(resultGPR, node);
9067}
9068
9069void SpeculativeJIT::compileTypeOf(Node* node)
9070{
9071 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
9072
9073 JSValueOperand value(this, node->child1());
9074 JSValueRegs valueRegs = value.jsValueRegs();
9075
9076 GPRTemporary result(this);
9077 GPRReg resultGPR = result.gpr();
9078
9079 JITCompiler::JumpList done;
9080 JITCompiler::Jump slowPath;
9081 m_jit.emitTypeOf(
9082 valueRegs, resultGPR,
9083 [&] (TypeofType type, bool fallsThrough) {
9084 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->smallStrings.typeString(type)), resultGPR);
9085 if (!fallsThrough)
9086 done.append(m_jit.jump());
9087 },
9088 [&] (JITCompiler::Jump theSlowPath) {
9089 slowPath = theSlowPath;
9090 });
9091 done.link(&m_jit);
9092
9093 addSlowPathGenerator(
9094 slowPathCall(
9095 slowPath, this, operationTypeOfObject, resultGPR, globalObject,
9096 valueRegs.payloadGPR()));
9097
9098 cellResult(resultGPR, node);
9099}
9100
9101void SpeculativeJIT::emitStructureCheck(Node* node, GPRReg cellGPR, GPRReg tempGPR)
9102{
9103 ASSERT(node->structureSet().size());
9104
9105 if (node->structureSet().size() == 1) {
9106 speculationCheck(
9107 BadCache, JSValueSource::unboxedCell(cellGPR), 0,
9108 m_jit.branchWeakStructure(
9109 JITCompiler::NotEqual,
9110 JITCompiler::Address(cellGPR, JSCell::structureIDOffset()),
9111 node->structureSet()[0]));
9112 } else {
9113 std::unique_ptr<GPRTemporary> structure;
9114 GPRReg structureGPR;
9115
9116 if (tempGPR == InvalidGPRReg) {
9117 structure = std::make_unique<GPRTemporary>(this);
9118 structureGPR = structure->gpr();
9119 } else
9120 structureGPR = tempGPR;
9121
9122 m_jit.load32(JITCompiler::Address(cellGPR, JSCell::structureIDOffset()), structureGPR);
9123
9124 JITCompiler::JumpList done;
9125
9126 for (size_t i = 0; i < node->structureSet().size() - 1; ++i) {
9127 done.append(
9128 m_jit.branchWeakStructure(JITCompiler::Equal, structureGPR, node->structureSet()[i]));
9129 }
9130
9131 speculationCheck(
9132 BadCache, JSValueSource::unboxedCell(cellGPR), 0,
9133 m_jit.branchWeakStructure(
9134 JITCompiler::NotEqual, structureGPR, node->structureSet().last()));
9135
9136 done.link(&m_jit);
9137 }
9138}
9139
9140void SpeculativeJIT::compileCheckCell(Node* node)
9141{
9142 SpeculateCellOperand cell(this, node->child1());
9143 speculationCheck(BadCell, JSValueSource::unboxedCell(cell.gpr()), node->child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, cell.gpr(), node->cellOperand()->cell()));
9144 noResult(node);
9145}
9146
9147void SpeculativeJIT::compileCheckNotEmpty(Node* node)
9148{
9149 JSValueOperand operand(this, node->child1());
9150 JSValueRegs regs = operand.jsValueRegs();
9151 speculationCheck(TDZFailure, JSValueSource(), nullptr, m_jit.branchIfEmpty(regs));
9152 noResult(node);
9153}
9154
9155void SpeculativeJIT::compileCheckStructure(Node* node)
9156{
9157 switch (node->child1().useKind()) {
9158 case CellUse:
9159 case KnownCellUse: {
9160 SpeculateCellOperand cell(this, node->child1());
9161 emitStructureCheck(node, cell.gpr(), InvalidGPRReg);
9162 noResult(node);
9163 return;
9164 }
9165
9166 case CellOrOtherUse: {
9167 JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
9168 GPRTemporary temp(this);
9169
9170 JSValueRegs valueRegs = value.jsValueRegs();
9171 GPRReg tempGPR = temp.gpr();
9172
9173 JITCompiler::Jump cell = m_jit.branchIfCell(valueRegs);
9174 DFG_TYPE_CHECK(
9175 valueRegs, node->child1(), SpecCell | SpecOther,
9176 m_jit.branchIfNotOther(valueRegs, tempGPR));
9177 JITCompiler::Jump done = m_jit.jump();
9178 cell.link(&m_jit);
9179 emitStructureCheck(node, valueRegs.payloadGPR(), tempGPR);
9180 done.link(&m_jit);
9181 noResult(node);
9182 return;
9183 }
9184
9185 default:
9186 DFG_CRASH(m_jit.graph(), node, "Bad use kind");
9187 return;
9188 }
9189}
9190
9191void SpeculativeJIT::compileAllocatePropertyStorage(Node* node)
9192{
9193 ASSERT(!node->transition()->previous->outOfLineCapacity());
9194 ASSERT(initialOutOfLineCapacity == node->transition()->next->outOfLineCapacity());
9195
9196 size_t size = initialOutOfLineCapacity * sizeof(JSValue);
9197
9198 Allocator allocator = m_jit.vm()->jsValueGigacageAuxiliarySpace.allocatorForNonVirtual(size, AllocatorForMode::AllocatorIfExists);
9199
9200 if (!allocator || node->transition()->previous->couldHaveIndexingHeader()) {
9201 SpeculateCellOperand base(this, node->child1());
9202
9203 GPRReg baseGPR = base.gpr();
9204
9205 flushRegisters();
9206
9207 GPRFlushedCallResult result(this);
9208 callOperation(operationAllocateComplexPropertyStorageWithInitialCapacity, result.gpr(), baseGPR);
9209 m_jit.exceptionCheck();
9210
9211 storageResult(result.gpr(), node);
9212 return;
9213 }
9214
9215 GPRTemporary scratch1(this);
9216 GPRTemporary scratch2(this);
9217 GPRTemporary scratch3(this);
9218
9219 GPRReg scratchGPR1 = scratch1.gpr();
9220 GPRReg scratchGPR2 = scratch2.gpr();
9221 GPRReg scratchGPR3 = scratch3.gpr();
9222
9223 JITCompiler::JumpList slowPath;
9224 m_jit.emitAllocate(scratchGPR1, JITAllocator::constant(allocator), scratchGPR2, scratchGPR3, slowPath);
9225 m_jit.addPtr(JITCompiler::TrustedImm32(size + sizeof(IndexingHeader)), scratchGPR1);
9226
9227 addSlowPathGenerator(
9228 slowPathCall(slowPath, this, operationAllocateSimplePropertyStorageWithInitialCapacity, scratchGPR1));
9229
9230 for (ptrdiff_t offset = 0; offset < static_cast<ptrdiff_t>(size); offset += sizeof(void*))
9231 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratchGPR1, -(offset + sizeof(JSValue) + sizeof(void*))));
9232
9233 storageResult(scratchGPR1, node);
9234}
9235
9236void SpeculativeJIT::compileReallocatePropertyStorage(Node* node)
9237{
9238 size_t oldSize = node->transition()->previous->outOfLineCapacity() * sizeof(JSValue);
9239 size_t newSize = oldSize * outOfLineGrowthFactor;
9240 ASSERT(newSize == node->transition()->next->outOfLineCapacity() * sizeof(JSValue));
9241
9242 Allocator allocator = m_jit.vm()->jsValueGigacageAuxiliarySpace.allocatorForNonVirtual(newSize, AllocatorForMode::AllocatorIfExists);
9243
9244 if (!allocator || node->transition()->previous->couldHaveIndexingHeader()) {
9245 SpeculateCellOperand base(this, node->child1());
9246
9247 GPRReg baseGPR = base.gpr();
9248
9249 flushRegisters();
9250
9251 GPRFlushedCallResult result(this);
9252 callOperation(operationAllocateComplexPropertyStorage, result.gpr(), baseGPR, newSize / sizeof(JSValue));
9253 m_jit.exceptionCheck();
9254
9255 storageResult(result.gpr(), node);
9256 return;
9257 }
9258
9259 StorageOperand oldStorage(this, node->child2());
9260 GPRTemporary scratch1(this);
9261 GPRTemporary scratch2(this);
9262 GPRTemporary scratch3(this);
9263
9264 GPRReg oldStorageGPR = oldStorage.gpr();
9265 GPRReg scratchGPR1 = scratch1.gpr();
9266 GPRReg scratchGPR2 = scratch2.gpr();
9267 GPRReg scratchGPR3 = scratch3.gpr();
9268
9269 JITCompiler::JumpList slowPath;
9270 m_jit.emitAllocate(scratchGPR1, JITAllocator::constant(allocator), scratchGPR2, scratchGPR3, slowPath);
9271
9272 m_jit.addPtr(JITCompiler::TrustedImm32(newSize + sizeof(IndexingHeader)), scratchGPR1);
9273
9274 addSlowPathGenerator(
9275 slowPathCall(slowPath, this, operationAllocateSimplePropertyStorage, scratchGPR1, newSize / sizeof(JSValue)));
9276
9277 for (ptrdiff_t offset = oldSize; offset < static_cast<ptrdiff_t>(newSize); offset += sizeof(void*))
9278 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratchGPR1, -(offset + sizeof(JSValue) + sizeof(void*))));
9279
9280 // We have scratchGPR1 = new storage, scratchGPR2 = scratch
9281 for (ptrdiff_t offset = 0; offset < static_cast<ptrdiff_t>(oldSize); offset += sizeof(void*)) {
9282 m_jit.loadPtr(JITCompiler::Address(oldStorageGPR, -(offset + sizeof(JSValue) + sizeof(void*))), scratchGPR2);
9283 m_jit.storePtr(scratchGPR2, JITCompiler::Address(scratchGPR1, -(offset + sizeof(JSValue) + sizeof(void*))));
9284 }
9285
9286 storageResult(scratchGPR1, node);
9287}
9288
9289void SpeculativeJIT::compileNukeStructureAndSetButterfly(Node* node)
9290{
9291 SpeculateCellOperand base(this, node->child1());
9292 StorageOperand storage(this, node->child2());
9293
9294 GPRReg baseGPR = base.gpr();
9295 GPRReg storageGPR = storage.gpr();
9296
9297 m_jit.nukeStructureAndStoreButterfly(*m_jit.vm(), storageGPR, baseGPR);
9298
9299 noResult(node);
9300}
9301
9302void SpeculativeJIT::compileGetButterfly(Node* node)
9303{
9304 SpeculateCellOperand base(this, node->child1());
9305 GPRTemporary result(this, Reuse, base);
9306
9307 GPRReg baseGPR = base.gpr();
9308 GPRReg resultGPR = result.gpr();
9309
9310 m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::butterflyOffset()), resultGPR);
9311
9312 storageResult(resultGPR, node);
9313}
9314
9315static void allocateTemporaryRegistersForSnippet(SpeculativeJIT* jit, Vector<GPRTemporary>& gpHolders, Vector<FPRTemporary>& fpHolders, Vector<GPRReg>& gpScratch, Vector<FPRReg>& fpScratch, Snippet& snippet)
9316{
9317 for (unsigned i = 0; i < snippet.numGPScratchRegisters; ++i) {
9318 GPRTemporary temporary(jit);
9319 gpScratch.append(temporary.gpr());
9320 gpHolders.append(WTFMove(temporary));
9321 }
9322
9323 for (unsigned i = 0; i < snippet.numFPScratchRegisters; ++i) {
9324 FPRTemporary temporary(jit);
9325 fpScratch.append(temporary.fpr());
9326 fpHolders.append(WTFMove(temporary));
9327 }
9328}
9329
9330void SpeculativeJIT::compileCallDOM(Node* node)
9331{
9332 const DOMJIT::Signature* signature = node->signature();
9333
9334 // FIXME: We should have a way to call functions with the vector of registers.
9335 // https://bugs.webkit.org/show_bug.cgi?id=163099
9336 Vector<Variant<SpeculateCellOperand, SpeculateInt32Operand, SpeculateBooleanOperand>, JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS_INCLUDING_THIS> operands;
9337 Vector<GPRReg, JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS_INCLUDING_THIS> regs;
9338
9339 auto appendCell = [&](Edge& edge) {
9340 SpeculateCellOperand operand(this, edge);
9341 regs.append(operand.gpr());
9342 operands.append(WTFMove(operand));
9343 };
9344
9345 auto appendString = [&](Edge& edge) {
9346 SpeculateCellOperand operand(this, edge);
9347 GPRReg gpr = operand.gpr();
9348 regs.append(gpr);
9349 speculateString(edge, gpr);
9350 operands.append(WTFMove(operand));
9351 };
9352
9353 auto appendInt32 = [&](Edge& edge) {
9354 SpeculateInt32Operand operand(this, edge);
9355 regs.append(operand.gpr());
9356 operands.append(WTFMove(operand));
9357 };
9358
9359 auto appendBoolean = [&](Edge& edge) {
9360 SpeculateBooleanOperand operand(this, edge);
9361 regs.append(operand.gpr());
9362 operands.append(WTFMove(operand));
9363 };
9364
9365 unsigned index = 0;
9366 m_jit.graph().doToChildren(node, [&](Edge edge) {
9367 if (!index)
9368 appendCell(edge);
9369 else {
9370 switch (signature->arguments[index - 1]) {
9371 case SpecString:
9372 appendString(edge);
9373 break;
9374 case SpecInt32Only:
9375 appendInt32(edge);
9376 break;
9377 case SpecBoolean:
9378 appendBoolean(edge);
9379 break;
9380 default:
9381 RELEASE_ASSERT_NOT_REACHED();
9382 break;
9383 }
9384 }
9385 ++index;
9386 });
9387
9388 JSValueRegsTemporary result(this);
9389 JSValueRegs resultRegs = result.regs();
9390
9391 flushRegisters();
9392 assertIsTaggedWith(reinterpret_cast<void*>(signature->unsafeFunction), CFunctionPtrTag);
9393 unsigned argumentCountIncludingThis = signature->argumentCount + 1;
9394 switch (argumentCountIncludingThis) {
9395 case 1:
9396 callOperation(reinterpret_cast<J_JITOperation_EP>(signature->unsafeFunction), extractResult(resultRegs), regs[0]);
9397 break;
9398 case 2:
9399 callOperation(reinterpret_cast<J_JITOperation_EPP>(signature->unsafeFunction), extractResult(resultRegs), regs[0], regs[1]);
9400 break;
9401 case 3:
9402 callOperation(reinterpret_cast<J_JITOperation_EPPP>(signature->unsafeFunction), extractResult(resultRegs), regs[0], regs[1], regs[2]);
9403 break;
9404 default:
9405 RELEASE_ASSERT_NOT_REACHED();
9406 break;
9407 }
9408
9409 m_jit.exceptionCheck();
9410 jsValueResult(resultRegs, node);
9411}
9412
9413void SpeculativeJIT::compileCallDOMGetter(Node* node)
9414{
9415 DOMJIT::CallDOMGetterSnippet* snippet = node->callDOMGetterData()->snippet;
9416 if (!snippet) {
9417 FunctionPtr<OperationPtrTag> getter = node->callDOMGetterData()->customAccessorGetter;
9418 SpeculateCellOperand base(this, node->child1());
9419 JSValueRegsTemporary result(this);
9420
9421 JSValueRegs resultRegs = result.regs();
9422 GPRReg baseGPR = base.gpr();
9423
9424 flushRegisters();
9425 m_jit.setupArguments<J_JITOperation_EJI>(CCallHelpers::CellValue(baseGPR), identifierUID(node->callDOMGetterData()->identifierNumber));
9426 m_jit.storePtr(GPRInfo::callFrameRegister, &m_jit.vm()->topCallFrame);
9427 m_jit.emitStoreCodeOrigin(m_currentNode->origin.semantic);
9428 m_jit.appendCall(getter.retagged<CFunctionPtrTag>());
9429 m_jit.setupResults(resultRegs);
9430
9431 m_jit.exceptionCheck();
9432 jsValueResult(resultRegs, node);
9433 return;
9434 }
9435
9436 Vector<GPRReg> gpScratch;
9437 Vector<FPRReg> fpScratch;
9438 Vector<SnippetParams::Value> regs;
9439
9440 JSValueRegsTemporary result(this);
9441 regs.append(result.regs());
9442
9443 Edge& baseEdge = node->child1();
9444 SpeculateCellOperand base(this, baseEdge);
9445 regs.append(SnippetParams::Value(base.gpr(), m_state.forNode(baseEdge).value()));
9446
9447 Optional<SpeculateCellOperand> globalObject;
9448 if (snippet->requireGlobalObject) {
9449 Edge& globalObjectEdge = node->child2();
9450 globalObject.emplace(this, globalObjectEdge);
9451 regs.append(SnippetParams::Value(globalObject->gpr(), m_state.forNode(globalObjectEdge).value()));
9452 }
9453
9454 Vector<GPRTemporary> gpTempraries;
9455 Vector<FPRTemporary> fpTempraries;
9456 allocateTemporaryRegistersForSnippet(this, gpTempraries, fpTempraries, gpScratch, fpScratch, *snippet);
9457 SnippetParams params(this, WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
9458 snippet->generator()->run(m_jit, params);
9459 jsValueResult(result.regs(), node);
9460}
9461
9462void SpeculativeJIT::compileCheckSubClass(Node* node)
9463{
9464 const ClassInfo* classInfo = node->classInfo();
9465 if (!classInfo->checkSubClassSnippet) {
9466 SpeculateCellOperand base(this, node->child1());
9467 GPRTemporary other(this);
9468 GPRTemporary specified(this);
9469
9470 GPRReg baseGPR = base.gpr();
9471 GPRReg otherGPR = other.gpr();
9472 GPRReg specifiedGPR = specified.gpr();
9473
9474 m_jit.emitLoadStructure(*m_jit.vm(), baseGPR, otherGPR, specifiedGPR);
9475 m_jit.loadPtr(CCallHelpers::Address(otherGPR, Structure::classInfoOffset()), otherGPR);
9476 m_jit.move(CCallHelpers::TrustedImmPtr(node->classInfo()), specifiedGPR);
9477
9478 CCallHelpers::Label loop = m_jit.label();
9479 auto done = m_jit.branchPtr(CCallHelpers::Equal, otherGPR, specifiedGPR);
9480 m_jit.loadPtr(CCallHelpers::Address(otherGPR, ClassInfo::offsetOfParentClass()), otherGPR);
9481 m_jit.branchTestPtr(CCallHelpers::NonZero, otherGPR).linkTo(loop, &m_jit);
9482 speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node->child1(), m_jit.jump());
9483 done.link(&m_jit);
9484 noResult(node);
9485 return;
9486 }
9487
9488 Ref<Snippet> snippet = classInfo->checkSubClassSnippet();
9489
9490 Vector<GPRReg> gpScratch;
9491 Vector<FPRReg> fpScratch;
9492 Vector<SnippetParams::Value> regs;
9493
9494 SpeculateCellOperand base(this, node->child1());
9495 GPRReg baseGPR = base.gpr();
9496 regs.append(SnippetParams::Value(baseGPR, m_state.forNode(node->child1()).value()));
9497
9498 Vector<GPRTemporary> gpTempraries;
9499 Vector<FPRTemporary> fpTempraries;
9500 allocateTemporaryRegistersForSnippet(this, gpTempraries, fpTempraries, gpScratch, fpScratch, snippet.get());
9501
9502 SnippetParams params(this, WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
9503 CCallHelpers::JumpList failureCases = snippet->generator()->run(m_jit, params);
9504 speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node->child1(), failureCases);
9505 noResult(node);
9506}
9507
9508GPRReg SpeculativeJIT::temporaryRegisterForPutByVal(GPRTemporary& temporary, ArrayMode arrayMode)
9509{
9510 if (!putByValWillNeedExtraRegister(arrayMode))
9511 return InvalidGPRReg;
9512
9513 GPRTemporary realTemporary(this);
9514 temporary.adopt(realTemporary);
9515 return temporary.gpr();
9516}
9517
9518void SpeculativeJIT::compileToStringOrCallStringConstructorOrStringValueOf(Node* node)
9519{
9520 ASSERT(node->op() != StringValueOf || node->child1().useKind() == UntypedUse);
9521 switch (node->child1().useKind()) {
9522 case NotCellUse: {
9523 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
9524 JSValueRegs op1Regs = op1.jsValueRegs();
9525
9526 GPRFlushedCallResult result(this);
9527 GPRReg resultGPR = result.gpr();
9528
9529 speculateNotCell(node->child1(), op1Regs);
9530
9531 flushRegisters();
9532
9533 if (node->op() == ToString)
9534 callOperation(operationToString, resultGPR, op1Regs);
9535 else {
9536 ASSERT(node->op() == CallStringConstructor);
9537 callOperation(operationCallStringConstructor, resultGPR, op1Regs);
9538 }
9539 m_jit.exceptionCheck();
9540 cellResult(resultGPR, node);
9541 return;
9542 }
9543
9544 case UntypedUse: {
9545 JSValueOperand op1(this, node->child1());
9546 JSValueRegs op1Regs = op1.jsValueRegs();
9547 GPRReg op1PayloadGPR = op1Regs.payloadGPR();
9548
9549 GPRFlushedCallResult result(this);
9550 GPRReg resultGPR = result.gpr();
9551
9552 flushRegisters();
9553
9554 JITCompiler::Jump done;
9555 if (node->child1()->prediction() & SpecString) {
9556 JITCompiler::Jump slowPath1 = m_jit.branchIfNotCell(op1.jsValueRegs());
9557 JITCompiler::Jump slowPath2 = m_jit.branchIfNotString(op1PayloadGPR);
9558 m_jit.move(op1PayloadGPR, resultGPR);
9559 done = m_jit.jump();
9560 slowPath1.link(&m_jit);
9561 slowPath2.link(&m_jit);
9562 }
9563 if (node->op() == ToString)
9564 callOperation(operationToString, resultGPR, op1Regs);
9565 else if (node->op() == StringValueOf)
9566 callOperation(operationStringValueOf, resultGPR, op1Regs);
9567 else {
9568 ASSERT(node->op() == CallStringConstructor);
9569 callOperation(operationCallStringConstructor, resultGPR, op1Regs);
9570 }
9571 m_jit.exceptionCheck();
9572 if (done.isSet())
9573 done.link(&m_jit);
9574 cellResult(resultGPR, node);
9575 return;
9576 }
9577
9578 case Int32Use:
9579 case Int52RepUse:
9580 case DoubleRepUse:
9581 compileNumberToStringWithValidRadixConstant(node, 10);
9582 return;
9583
9584 default:
9585 break;
9586 }
9587
9588 SpeculateCellOperand op1(this, node->child1());
9589 GPRReg op1GPR = op1.gpr();
9590
9591 switch (node->child1().useKind()) {
9592 case StringObjectUse: {
9593 GPRTemporary result(this);
9594 GPRReg resultGPR = result.gpr();
9595
9596 speculateStringObject(node->child1(), op1GPR);
9597
9598 m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR);
9599 cellResult(resultGPR, node);
9600 break;
9601 }
9602
9603 case StringOrStringObjectUse: {
9604 GPRTemporary result(this);
9605 GPRReg resultGPR = result.gpr();
9606
9607 m_jit.load8(JITCompiler::Address(op1GPR, JSCell::typeInfoTypeOffset()), resultGPR);
9608 JITCompiler::Jump isString = m_jit.branch32(JITCompiler::Equal, resultGPR, TrustedImm32(StringType));
9609
9610 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1().node(), m_jit.branch32(JITCompiler::NotEqual, resultGPR, TrustedImm32(StringObjectType)));
9611 m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR);
9612 JITCompiler::Jump done = m_jit.jump();
9613
9614 isString.link(&m_jit);
9615 m_jit.move(op1GPR, resultGPR);
9616 done.link(&m_jit);
9617
9618 m_interpreter.filter(node->child1(), SpecString | SpecStringObject);
9619
9620 cellResult(resultGPR, node);
9621 break;
9622 }
9623
9624 case CellUse: {
9625 GPRFlushedCallResult result(this);
9626 GPRReg resultGPR = result.gpr();
9627
9628 // We flush registers instead of silent spill/fill because in this mode we
9629 // believe that most likely the input is not a string, and we need to take
9630 // slow path.
9631 flushRegisters();
9632 JITCompiler::Jump done;
9633 if (node->child1()->prediction() & SpecString) {
9634 JITCompiler::Jump needCall = m_jit.branchIfNotString(op1GPR);
9635 m_jit.move(op1GPR, resultGPR);
9636 done = m_jit.jump();
9637 needCall.link(&m_jit);
9638 }
9639 if (node->op() == ToString)
9640 callOperation(operationToStringOnCell, resultGPR, op1GPR);
9641 else {
9642 ASSERT(node->op() == CallStringConstructor);
9643 callOperation(operationCallStringConstructorOnCell, resultGPR, op1GPR);
9644 }
9645 m_jit.exceptionCheck();
9646 if (done.isSet())
9647 done.link(&m_jit);
9648 cellResult(resultGPR, node);
9649 break;
9650 }
9651
9652 default:
9653 RELEASE_ASSERT_NOT_REACHED();
9654 }
9655}
9656
9657void SpeculativeJIT::compileNumberToStringWithValidRadixConstant(Node* node)
9658{
9659 compileNumberToStringWithValidRadixConstant(node, node->validRadixConstant());
9660}
9661
9662void SpeculativeJIT::compileNumberToStringWithValidRadixConstant(Node* node, int32_t radix)
9663{
9664 auto callToString = [&] (auto operation, GPRReg resultGPR, auto valueReg) {
9665 flushRegisters();
9666 callOperation(operation, resultGPR, valueReg, TrustedImm32(radix));
9667 m_jit.exceptionCheck();
9668 cellResult(resultGPR, node);
9669 };
9670
9671 switch (node->child1().useKind()) {
9672 case Int32Use: {
9673 SpeculateStrictInt32Operand value(this, node->child1());
9674 GPRFlushedCallResult result(this);
9675 callToString(operationInt32ToStringWithValidRadix, result.gpr(), value.gpr());
9676 break;
9677 }
9678
9679#if USE(JSVALUE64)
9680 case Int52RepUse: {
9681 SpeculateStrictInt52Operand value(this, node->child1());
9682 GPRFlushedCallResult result(this);
9683 callToString(operationInt52ToStringWithValidRadix, result.gpr(), value.gpr());
9684 break;
9685 }
9686#endif
9687
9688 case DoubleRepUse: {
9689 SpeculateDoubleOperand value(this, node->child1());
9690 GPRFlushedCallResult result(this);
9691 callToString(operationDoubleToStringWithValidRadix, result.gpr(), value.fpr());
9692 break;
9693 }
9694
9695 default:
9696 RELEASE_ASSERT_NOT_REACHED();
9697 }
9698}
9699
9700void SpeculativeJIT::compileNumberToStringWithRadix(Node* node)
9701{
9702 bool validRadixIsGuaranteed = false;
9703 if (node->child2()->isInt32Constant()) {
9704 int32_t radix = node->child2()->asInt32();
9705 if (radix >= 2 && radix <= 36)
9706 validRadixIsGuaranteed = true;
9707 }
9708
9709 auto callToString = [&] (auto operation, GPRReg resultGPR, auto valueReg, GPRReg radixGPR) {
9710 flushRegisters();
9711 callOperation(operation, resultGPR, valueReg, radixGPR);
9712 m_jit.exceptionCheck();
9713 cellResult(resultGPR, node);
9714 };
9715
9716 switch (node->child1().useKind()) {
9717 case Int32Use: {
9718 SpeculateStrictInt32Operand value(this, node->child1());
9719 SpeculateStrictInt32Operand radix(this, node->child2());
9720 GPRFlushedCallResult result(this);
9721 callToString(validRadixIsGuaranteed ? operationInt32ToStringWithValidRadix : operationInt32ToString, result.gpr(), value.gpr(), radix.gpr());
9722 break;
9723 }
9724
9725#if USE(JSVALUE64)
9726 case Int52RepUse: {
9727 SpeculateStrictInt52Operand value(this, node->child1());
9728 SpeculateStrictInt32Operand radix(this, node->child2());
9729 GPRFlushedCallResult result(this);
9730 callToString(validRadixIsGuaranteed ? operationInt52ToStringWithValidRadix : operationInt52ToString, result.gpr(), value.gpr(), radix.gpr());
9731 break;
9732 }
9733#endif
9734
9735 case DoubleRepUse: {
9736 SpeculateDoubleOperand value(this, node->child1());
9737 SpeculateStrictInt32Operand radix(this, node->child2());
9738 GPRFlushedCallResult result(this);
9739 callToString(validRadixIsGuaranteed ? operationDoubleToStringWithValidRadix : operationDoubleToString, result.gpr(), value.fpr(), radix.gpr());
9740 break;
9741 }
9742
9743 default:
9744 RELEASE_ASSERT_NOT_REACHED();
9745 }
9746}
9747
9748void SpeculativeJIT::compileNewStringObject(Node* node)
9749{
9750 SpeculateCellOperand operand(this, node->child1());
9751
9752 GPRTemporary result(this);
9753 GPRTemporary scratch1(this);
9754 GPRTemporary scratch2(this);
9755
9756 GPRReg operandGPR = operand.gpr();
9757 GPRReg resultGPR = result.gpr();
9758 GPRReg scratch1GPR = scratch1.gpr();
9759 GPRReg scratch2GPR = scratch2.gpr();
9760
9761 JITCompiler::JumpList slowPath;
9762
9763 auto butterfly = TrustedImmPtr(nullptr);
9764 emitAllocateJSObject<StringObject>(
9765 resultGPR, TrustedImmPtr(node->structure()), butterfly, scratch1GPR, scratch2GPR,
9766 slowPath);
9767
9768 m_jit.storePtr(
9769 TrustedImmPtr(StringObject::info()),
9770 JITCompiler::Address(resultGPR, JSDestructibleObject::classInfoOffset()));
9771#if USE(JSVALUE64)
9772 m_jit.store64(
9773 operandGPR, JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset()));
9774#else
9775 m_jit.store32(
9776 TrustedImm32(JSValue::CellTag),
9777 JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
9778 m_jit.store32(
9779 operandGPR,
9780 JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
9781#endif
9782
9783 m_jit.mutatorFence(*m_jit.vm());
9784
9785 addSlowPathGenerator(slowPathCall(
9786 slowPath, this, operationNewStringObject, resultGPR, operandGPR, node->structure()));
9787
9788 cellResult(resultGPR, node);
9789}
9790
9791void SpeculativeJIT::compileNewSymbol(Node* node)
9792{
9793 if (!node->child1()) {
9794 flushRegisters();
9795 GPRFlushedCallResult result(this);
9796 GPRReg resultGPR = result.gpr();
9797 callOperation(operationNewSymbol, resultGPR);
9798 m_jit.exceptionCheck();
9799 cellResult(resultGPR, node);
9800 return;
9801 }
9802
9803
9804 ASSERT(node->child1().useKind() == KnownStringUse);
9805 SpeculateCellOperand operand(this, node->child1());
9806
9807 GPRReg stringGPR = operand.gpr();
9808
9809 flushRegisters();
9810 GPRFlushedCallResult result(this);
9811 GPRReg resultGPR = result.gpr();
9812 callOperation(operationNewSymbolWithDescription, resultGPR, stringGPR);
9813 m_jit.exceptionCheck();
9814 cellResult(resultGPR, node);
9815}
9816
9817void SpeculativeJIT::compileNewTypedArrayWithSize(Node* node)
9818{
9819 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
9820 auto typedArrayType = node->typedArrayType();
9821 RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->typedArrayStructureConcurrently(typedArrayType));
9822 RELEASE_ASSERT(structure.get());
9823
9824 SpeculateInt32Operand size(this, node->child1());
9825 GPRReg sizeGPR = size.gpr();
9826
9827 GPRTemporary result(this);
9828 GPRTemporary storage(this);
9829 GPRTemporary scratch(this);
9830 GPRTemporary scratch2(this);
9831 GPRReg resultGPR = result.gpr();
9832 GPRReg storageGPR = storage.gpr();
9833 GPRReg scratchGPR = scratch.gpr();
9834 GPRReg scratchGPR2 = scratch2.gpr();
9835
9836 JITCompiler::JumpList slowCases;
9837
9838 m_jit.move(TrustedImmPtr(nullptr), storageGPR);
9839
9840 slowCases.append(m_jit.branch32(
9841 MacroAssembler::Above, sizeGPR, TrustedImm32(JSArrayBufferView::fastSizeLimit)));
9842
9843 m_jit.move(sizeGPR, scratchGPR);
9844 m_jit.lshift32(TrustedImm32(logElementSize(typedArrayType)), scratchGPR);
9845 if (elementSize(typedArrayType) < 8) {
9846 m_jit.add32(TrustedImm32(7), scratchGPR);
9847 m_jit.and32(TrustedImm32(~7), scratchGPR);
9848 }
9849 m_jit.emitAllocateVariableSized(
9850 storageGPR, m_jit.vm()->primitiveGigacageAuxiliarySpace, scratchGPR, scratchGPR,
9851 scratchGPR2, slowCases);
9852
9853 MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, sizeGPR);
9854 m_jit.move(sizeGPR, scratchGPR);
9855 if (elementSize(typedArrayType) != 4) {
9856 if (elementSize(typedArrayType) > 4)
9857 m_jit.lshift32(TrustedImm32(logElementSize(typedArrayType) - 2), scratchGPR);
9858 else {
9859 if (elementSize(typedArrayType) > 1)
9860 m_jit.lshift32(TrustedImm32(logElementSize(typedArrayType)), scratchGPR);
9861 m_jit.add32(TrustedImm32(3), scratchGPR);
9862 m_jit.urshift32(TrustedImm32(2), scratchGPR);
9863 }
9864 }
9865 MacroAssembler::Label loop = m_jit.label();
9866 m_jit.sub32(TrustedImm32(1), scratchGPR);
9867 m_jit.store32(
9868 TrustedImm32(0),
9869 MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesFour));
9870 m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
9871 done.link(&m_jit);
9872#if CPU(ARM64E)
9873 // sizeGPR is still boxed as a number and there is no 32-bit variant of the PAC instructions.
9874 m_jit.zeroExtend32ToPtr(sizeGPR, scratchGPR);
9875 m_jit.tagArrayPtr(scratchGPR, storageGPR);
9876#endif
9877
9878 auto butterfly = TrustedImmPtr(nullptr);
9879 emitAllocateJSObject<JSArrayBufferView>(
9880 resultGPR, TrustedImmPtr(structure), butterfly, scratchGPR, scratchGPR2,
9881 slowCases);
9882
9883 m_jit.storePtr(
9884 storageGPR,
9885 MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfVector()));
9886 m_jit.store32(
9887 sizeGPR,
9888 MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfLength()));
9889 m_jit.store32(
9890 TrustedImm32(FastTypedArray),
9891 MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfMode()));
9892
9893 m_jit.mutatorFence(*m_jit.vm());
9894
9895 addSlowPathGenerator(slowPathCall(
9896 slowCases, this, operationNewTypedArrayWithSizeForType(typedArrayType),
9897 resultGPR, structure, sizeGPR, storageGPR));
9898
9899 cellResult(resultGPR, node);
9900}
9901
9902void SpeculativeJIT::compileNewRegexp(Node* node)
9903{
9904 RegExp* regexp = node->castOperand<RegExp*>();
9905
9906 GPRTemporary result(this);
9907 GPRTemporary scratch1(this);
9908 GPRTemporary scratch2(this);
9909 JSValueOperand lastIndex(this, node->child1());
9910
9911 GPRReg resultGPR = result.gpr();
9912 GPRReg scratch1GPR = scratch1.gpr();
9913 GPRReg scratch2GPR = scratch2.gpr();
9914 JSValueRegs lastIndexRegs = lastIndex.jsValueRegs();
9915
9916 JITCompiler::JumpList slowPath;
9917
9918 auto structure = m_jit.graph().registerStructure(m_jit.graph().globalObjectFor(node->origin.semantic)->regExpStructure());
9919 auto butterfly = TrustedImmPtr(nullptr);
9920 emitAllocateJSObject<RegExpObject>(resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR, slowPath);
9921
9922 m_jit.storePtr(
9923 TrustedImmPtr(node->cellOperand()),
9924 CCallHelpers::Address(resultGPR, RegExpObject::offsetOfRegExpAndLastIndexIsNotWritableFlag()));
9925 m_jit.storeValue(lastIndexRegs, CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndex()));
9926 m_jit.mutatorFence(*m_jit.vm());
9927
9928 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewRegexpWithLastIndex, resultGPR, regexp, lastIndexRegs));
9929
9930 cellResult(resultGPR, node);
9931}
9932
9933void SpeculativeJIT::speculateCellTypeWithoutTypeFiltering(
9934 Edge edge, GPRReg cellGPR, JSType jsType)
9935{
9936 speculationCheck(
9937 BadType, JSValueSource::unboxedCell(cellGPR), edge,
9938 m_jit.branchIfNotType(cellGPR, jsType));
9939}
9940
9941void SpeculativeJIT::speculateCellType(
9942 Edge edge, GPRReg cellGPR, SpeculatedType specType, JSType jsType)
9943{
9944 DFG_TYPE_CHECK(
9945 JSValueSource::unboxedCell(cellGPR), edge, specType,
9946 m_jit.branchIfNotType(cellGPR, jsType));
9947}
9948
9949void SpeculativeJIT::speculateInt32(Edge edge)
9950{
9951 if (!needsTypeCheck(edge, SpecInt32Only))
9952 return;
9953
9954 (SpeculateInt32Operand(this, edge)).gpr();
9955}
9956
9957void SpeculativeJIT::speculateNumber(Edge edge)
9958{
9959 if (!needsTypeCheck(edge, SpecBytecodeNumber))
9960 return;
9961
9962 JSValueOperand value(this, edge, ManualOperandSpeculation);
9963#if USE(JSVALUE64)
9964 GPRReg gpr = value.gpr();
9965 typeCheck(
9966 JSValueRegs(gpr), edge, SpecBytecodeNumber,
9967 m_jit.branchIfNotNumber(gpr));
9968#else
9969 IGNORE_WARNINGS_BEGIN("enum-compare")
9970 static_assert(JSValue::Int32Tag >= JSValue::LowestTag, "Int32Tag is included in >= JSValue::LowestTag range.");
9971 IGNORE_WARNINGS_END
9972 GPRReg tagGPR = value.tagGPR();
9973 DFG_TYPE_CHECK(
9974 value.jsValueRegs(), edge, ~SpecInt32Only,
9975 m_jit.branchIfInt32(tagGPR));
9976 DFG_TYPE_CHECK(
9977 value.jsValueRegs(), edge, SpecBytecodeNumber,
9978 m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag)));
9979#endif
9980}
9981
9982void SpeculativeJIT::speculateRealNumber(Edge edge)
9983{
9984 if (!needsTypeCheck(edge, SpecBytecodeRealNumber))
9985 return;
9986
9987 JSValueOperand op1(this, edge, ManualOperandSpeculation);
9988 FPRTemporary result(this);
9989
9990 JSValueRegs op1Regs = op1.jsValueRegs();
9991 FPRReg resultFPR = result.fpr();
9992
9993#if USE(JSVALUE64)
9994 GPRTemporary temp(this);
9995 GPRReg tempGPR = temp.gpr();
9996 m_jit.unboxDoubleWithoutAssertions(op1Regs.gpr(), tempGPR, resultFPR);
9997#else
9998 FPRTemporary temp(this);
9999 FPRReg tempFPR = temp.fpr();
10000 unboxDouble(op1Regs.tagGPR(), op1Regs.payloadGPR(), resultFPR, tempFPR);
10001#endif
10002
10003 JITCompiler::Jump done = m_jit.branchIfNotNaN(resultFPR);
10004
10005 typeCheck(op1Regs, edge, SpecBytecodeRealNumber, m_jit.branchIfNotInt32(op1Regs));
10006
10007 done.link(&m_jit);
10008}
10009
10010void SpeculativeJIT::speculateDoubleRepReal(Edge edge)
10011{
10012 if (!needsTypeCheck(edge, SpecDoubleReal))
10013 return;
10014
10015 SpeculateDoubleOperand operand(this, edge);
10016 FPRReg fpr = operand.fpr();
10017 typeCheck(
10018 JSValueRegs(), edge, SpecDoubleReal,
10019 m_jit.branchIfNaN(fpr));
10020}
10021
10022void SpeculativeJIT::speculateBoolean(Edge edge)
10023{
10024 if (!needsTypeCheck(edge, SpecBoolean))
10025 return;
10026
10027 (SpeculateBooleanOperand(this, edge)).gpr();
10028}
10029
10030void SpeculativeJIT::speculateCell(Edge edge)
10031{
10032 if (!needsTypeCheck(edge, SpecCellCheck))
10033 return;
10034
10035 (SpeculateCellOperand(this, edge)).gpr();
10036}
10037
10038void SpeculativeJIT::speculateCellOrOther(Edge edge)
10039{
10040 if (!needsTypeCheck(edge, SpecCellCheck | SpecOther))
10041 return;
10042
10043 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10044 GPRTemporary temp(this);
10045 GPRReg tempGPR = temp.gpr();
10046
10047 MacroAssembler::Jump ok = m_jit.branchIfCell(operand.jsValueRegs());
10048 DFG_TYPE_CHECK(
10049 operand.jsValueRegs(), edge, SpecCellCheck | SpecOther,
10050 m_jit.branchIfNotOther(operand.jsValueRegs(), tempGPR));
10051 ok.link(&m_jit);
10052}
10053
10054void SpeculativeJIT::speculateObject(Edge edge, GPRReg cell)
10055{
10056 DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, SpecObject, m_jit.branchIfNotObject(cell));
10057}
10058
10059void SpeculativeJIT::speculateObject(Edge edge)
10060{
10061 if (!needsTypeCheck(edge, SpecObject))
10062 return;
10063
10064 SpeculateCellOperand operand(this, edge);
10065 speculateObject(edge, operand.gpr());
10066}
10067
10068void SpeculativeJIT::speculateFunction(Edge edge, GPRReg cell)
10069{
10070 speculateCellType(edge, cell, SpecFunction, JSFunctionType);
10071}
10072
10073void SpeculativeJIT::speculateFunction(Edge edge)
10074{
10075 if (!needsTypeCheck(edge, SpecFunction))
10076 return;
10077
10078 SpeculateCellOperand operand(this, edge);
10079 speculateFunction(edge, operand.gpr());
10080}
10081
10082void SpeculativeJIT::speculateFinalObject(Edge edge, GPRReg cell)
10083{
10084 speculateCellType(edge, cell, SpecFinalObject, FinalObjectType);
10085}
10086
10087void SpeculativeJIT::speculateFinalObject(Edge edge)
10088{
10089 if (!needsTypeCheck(edge, SpecFinalObject))
10090 return;
10091
10092 SpeculateCellOperand operand(this, edge);
10093 speculateFinalObject(edge, operand.gpr());
10094}
10095
10096void SpeculativeJIT::speculateRegExpObject(Edge edge, GPRReg cell)
10097{
10098 speculateCellType(edge, cell, SpecRegExpObject, RegExpObjectType);
10099}
10100
10101void SpeculativeJIT::speculateRegExpObject(Edge edge)
10102{
10103 if (!needsTypeCheck(edge, SpecRegExpObject))
10104 return;
10105
10106 SpeculateCellOperand operand(this, edge);
10107 speculateRegExpObject(edge, operand.gpr());
10108}
10109
10110void SpeculativeJIT::speculateArray(Edge edge, GPRReg cell)
10111{
10112 speculateCellType(edge, cell, SpecArray, ArrayType);
10113}
10114
10115void SpeculativeJIT::speculateArray(Edge edge)
10116{
10117 if (!needsTypeCheck(edge, SpecArray))
10118 return;
10119
10120 SpeculateCellOperand operand(this, edge);
10121 speculateArray(edge, operand.gpr());
10122}
10123
10124void SpeculativeJIT::speculateProxyObject(Edge edge, GPRReg cell)
10125{
10126 speculateCellType(edge, cell, SpecProxyObject, ProxyObjectType);
10127}
10128
10129void SpeculativeJIT::speculateProxyObject(Edge edge)
10130{
10131 if (!needsTypeCheck(edge, SpecProxyObject))
10132 return;
10133
10134 SpeculateCellOperand operand(this, edge);
10135 speculateProxyObject(edge, operand.gpr());
10136}
10137
10138void SpeculativeJIT::speculateDerivedArray(Edge edge, GPRReg cell)
10139{
10140 speculateCellType(edge, cell, SpecDerivedArray, DerivedArrayType);
10141}
10142
10143void SpeculativeJIT::speculateDerivedArray(Edge edge)
10144{
10145 if (!needsTypeCheck(edge, SpecDerivedArray))
10146 return;
10147
10148 SpeculateCellOperand operand(this, edge);
10149 speculateDerivedArray(edge, operand.gpr());
10150}
10151
10152void SpeculativeJIT::speculateMapObject(Edge edge, GPRReg cell)
10153{
10154 speculateCellType(edge, cell, SpecMapObject, JSMapType);
10155}
10156
10157void SpeculativeJIT::speculateMapObject(Edge edge)
10158{
10159 if (!needsTypeCheck(edge, SpecMapObject))
10160 return;
10161
10162 SpeculateCellOperand operand(this, edge);
10163 speculateMapObject(edge, operand.gpr());
10164}
10165
10166void SpeculativeJIT::speculateSetObject(Edge edge, GPRReg cell)
10167{
10168 speculateCellType(edge, cell, SpecSetObject, JSSetType);
10169}
10170
10171void SpeculativeJIT::speculateSetObject(Edge edge)
10172{
10173 if (!needsTypeCheck(edge, SpecSetObject))
10174 return;
10175
10176 SpeculateCellOperand operand(this, edge);
10177 speculateSetObject(edge, operand.gpr());
10178}
10179
10180void SpeculativeJIT::speculateWeakMapObject(Edge edge, GPRReg cell)
10181{
10182 speculateCellType(edge, cell, SpecWeakMapObject, JSWeakMapType);
10183}
10184
10185void SpeculativeJIT::speculateWeakMapObject(Edge edge)
10186{
10187 if (!needsTypeCheck(edge, SpecWeakMapObject))
10188 return;
10189
10190 SpeculateCellOperand operand(this, edge);
10191 speculateWeakMapObject(edge, operand.gpr());
10192}
10193
10194void SpeculativeJIT::speculateWeakSetObject(Edge edge, GPRReg cell)
10195{
10196 speculateCellType(edge, cell, SpecWeakSetObject, JSWeakSetType);
10197}
10198
10199void SpeculativeJIT::speculateWeakSetObject(Edge edge)
10200{
10201 if (!needsTypeCheck(edge, SpecWeakSetObject))
10202 return;
10203
10204 SpeculateCellOperand operand(this, edge);
10205 speculateWeakSetObject(edge, operand.gpr());
10206}
10207
10208void SpeculativeJIT::speculateDataViewObject(Edge edge, GPRReg cell)
10209{
10210 speculateCellType(edge, cell, SpecDataViewObject, DataViewType);
10211}
10212
10213void SpeculativeJIT::speculateDataViewObject(Edge edge)
10214{
10215 if (!needsTypeCheck(edge, SpecDataViewObject))
10216 return;
10217
10218 SpeculateCellOperand operand(this, edge);
10219 speculateDataViewObject(edge, operand.gpr());
10220}
10221
10222void SpeculativeJIT::speculateObjectOrOther(Edge edge)
10223{
10224 if (!needsTypeCheck(edge, SpecObject | SpecOther))
10225 return;
10226
10227 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10228 GPRTemporary temp(this);
10229 GPRReg tempGPR = temp.gpr();
10230 MacroAssembler::Jump notCell = m_jit.branchIfNotCell(operand.jsValueRegs());
10231 GPRReg gpr = operand.jsValueRegs().payloadGPR();
10232 DFG_TYPE_CHECK(
10233 operand.jsValueRegs(), edge, (~SpecCellCheck) | SpecObject, m_jit.branchIfNotObject(gpr));
10234 MacroAssembler::Jump done = m_jit.jump();
10235 notCell.link(&m_jit);
10236 DFG_TYPE_CHECK(
10237 operand.jsValueRegs(), edge, SpecCellCheck | SpecOther,
10238 m_jit.branchIfNotOther(operand.jsValueRegs(), tempGPR));
10239 done.link(&m_jit);
10240}
10241
10242void SpeculativeJIT::speculateString(Edge edge, GPRReg cell)
10243{
10244 DFG_TYPE_CHECK(
10245 JSValueSource::unboxedCell(cell), edge, SpecString | ~SpecCellCheck, m_jit.branchIfNotString(cell));
10246}
10247
10248void SpeculativeJIT::speculateStringOrOther(Edge edge, JSValueRegs regs, GPRReg scratch)
10249{
10250 JITCompiler::Jump notCell = m_jit.branchIfNotCell(regs);
10251 GPRReg cell = regs.payloadGPR();
10252 DFG_TYPE_CHECK(regs, edge, (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cell));
10253 JITCompiler::Jump done = m_jit.jump();
10254 notCell.link(&m_jit);
10255 DFG_TYPE_CHECK(regs, edge, SpecCellCheck | SpecOther, m_jit.branchIfNotOther(regs, scratch));
10256 done.link(&m_jit);
10257}
10258
10259void SpeculativeJIT::speculateStringOrOther(Edge edge)
10260{
10261 if (!needsTypeCheck(edge, SpecString | SpecOther))
10262 return;
10263
10264 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10265 GPRTemporary temp(this);
10266 JSValueRegs regs = operand.jsValueRegs();
10267 GPRReg tempGPR = temp.gpr();
10268 speculateStringOrOther(edge, regs, tempGPR);
10269}
10270
10271void SpeculativeJIT::speculateStringIdentAndLoadStorage(Edge edge, GPRReg string, GPRReg storage)
10272{
10273 m_jit.loadPtr(MacroAssembler::Address(string, JSString::offsetOfValue()), storage);
10274
10275 if (!needsTypeCheck(edge, SpecStringIdent | ~SpecString))
10276 return;
10277
10278 speculationCheck(
10279 BadType, JSValueSource::unboxedCell(string), edge,
10280 m_jit.branchIfRopeStringImpl(storage));
10281 speculationCheck(
10282 BadType, JSValueSource::unboxedCell(string), edge, m_jit.branchTest32(
10283 MacroAssembler::Zero,
10284 MacroAssembler::Address(storage, StringImpl::flagsOffset()),
10285 MacroAssembler::TrustedImm32(StringImpl::flagIsAtom())));
10286
10287 m_interpreter.filter(edge, SpecStringIdent | ~SpecString);
10288}
10289
10290void SpeculativeJIT::speculateStringIdent(Edge edge, GPRReg string)
10291{
10292 if (!needsTypeCheck(edge, SpecStringIdent))
10293 return;
10294
10295 GPRTemporary temp(this);
10296 speculateStringIdentAndLoadStorage(edge, string, temp.gpr());
10297}
10298
10299void SpeculativeJIT::speculateStringIdent(Edge edge)
10300{
10301 if (!needsTypeCheck(edge, SpecStringIdent))
10302 return;
10303
10304 SpeculateCellOperand operand(this, edge);
10305 GPRReg gpr = operand.gpr();
10306 speculateString(edge, gpr);
10307 speculateStringIdent(edge, gpr);
10308}
10309
10310void SpeculativeJIT::speculateString(Edge edge)
10311{
10312 if (!needsTypeCheck(edge, SpecString))
10313 return;
10314
10315 SpeculateCellOperand operand(this, edge);
10316 speculateString(edge, operand.gpr());
10317}
10318
10319void SpeculativeJIT::speculateStringObject(Edge edge, GPRReg cellGPR)
10320{
10321 DFG_TYPE_CHECK(JSValueSource::unboxedCell(cellGPR), edge, ~SpecCellCheck | SpecStringObject, m_jit.branchIfNotType(cellGPR, StringObjectType));
10322}
10323
10324void SpeculativeJIT::speculateStringObject(Edge edge)
10325{
10326 if (!needsTypeCheck(edge, SpecStringObject))
10327 return;
10328
10329 SpeculateCellOperand operand(this, edge);
10330 GPRReg gpr = operand.gpr();
10331 speculateStringObject(edge, gpr);
10332}
10333
10334void SpeculativeJIT::speculateStringOrStringObject(Edge edge)
10335{
10336 if (!needsTypeCheck(edge, SpecString | SpecStringObject))
10337 return;
10338
10339 SpeculateCellOperand operand(this, edge);
10340 GPRReg gpr = operand.gpr();
10341 if (!needsTypeCheck(edge, SpecString | SpecStringObject))
10342 return;
10343
10344 GPRTemporary typeTemp(this);
10345 GPRReg typeGPR = typeTemp.gpr();
10346
10347 m_jit.load8(JITCompiler::Address(gpr, JSCell::typeInfoTypeOffset()), typeGPR);
10348
10349 JITCompiler::Jump isString = m_jit.branch32(JITCompiler::Equal, typeGPR, TrustedImm32(StringType));
10350 speculationCheck(BadType, JSValueSource::unboxedCell(gpr), edge.node(), m_jit.branch32(JITCompiler::NotEqual, typeGPR, TrustedImm32(StringObjectType)));
10351 isString.link(&m_jit);
10352
10353 m_interpreter.filter(edge, SpecString | SpecStringObject);
10354}
10355
10356void SpeculativeJIT::speculateNotStringVar(Edge edge)
10357{
10358 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10359 GPRTemporary temp(this);
10360 GPRReg tempGPR = temp.gpr();
10361
10362 JITCompiler::Jump notCell = m_jit.branchIfNotCell(operand.jsValueRegs());
10363 GPRReg cell = operand.jsValueRegs().payloadGPR();
10364
10365 JITCompiler::Jump notString = m_jit.branchIfNotString(cell);
10366
10367 speculateStringIdentAndLoadStorage(edge, cell, tempGPR);
10368
10369 notString.link(&m_jit);
10370 notCell.link(&m_jit);
10371}
10372
10373void SpeculativeJIT::speculateNotSymbol(Edge edge)
10374{
10375 if (!needsTypeCheck(edge, ~SpecSymbol))
10376 return;
10377
10378 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10379 auto valueRegs = operand.jsValueRegs();
10380 GPRReg value = valueRegs.payloadGPR();
10381 JITCompiler::Jump notCell;
10382
10383 bool needsCellCheck = needsTypeCheck(edge, SpecCell);
10384 if (needsCellCheck)
10385 notCell = m_jit.branchIfNotCell(valueRegs);
10386
10387 speculationCheck(BadType, JSValueSource::unboxedCell(value), edge.node(), m_jit.branchIfSymbol(value));
10388
10389 if (needsCellCheck)
10390 notCell.link(&m_jit);
10391
10392 m_interpreter.filter(edge, ~SpecSymbol);
10393}
10394
10395void SpeculativeJIT::speculateSymbol(Edge edge, GPRReg cell)
10396{
10397 DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, ~SpecCellCheck | SpecSymbol, m_jit.branchIfNotSymbol(cell));
10398}
10399
10400void SpeculativeJIT::speculateSymbol(Edge edge)
10401{
10402 if (!needsTypeCheck(edge, SpecSymbol))
10403 return;
10404
10405 SpeculateCellOperand operand(this, edge);
10406 speculateSymbol(edge, operand.gpr());
10407}
10408
10409void SpeculativeJIT::speculateBigInt(Edge edge, GPRReg cell)
10410{
10411 DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, ~SpecCellCheck | SpecBigInt, m_jit.branchIfNotBigInt(cell));
10412}
10413
10414void SpeculativeJIT::speculateBigInt(Edge edge)
10415{
10416 if (!needsTypeCheck(edge, SpecBigInt))
10417 return;
10418
10419 SpeculateCellOperand operand(this, edge);
10420 speculateBigInt(edge, operand.gpr());
10421}
10422
10423void SpeculativeJIT::speculateNotCell(Edge edge, JSValueRegs regs)
10424{
10425 DFG_TYPE_CHECK(regs, edge, ~SpecCellCheck, m_jit.branchIfCell(regs));
10426}
10427
10428void SpeculativeJIT::speculateNotCell(Edge edge)
10429{
10430 if (!needsTypeCheck(edge, ~SpecCellCheck))
10431 return;
10432
10433 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10434 speculateNotCell(edge, operand.jsValueRegs());
10435}
10436
10437void SpeculativeJIT::speculateOther(Edge edge, JSValueRegs regs, GPRReg tempGPR)
10438{
10439 DFG_TYPE_CHECK(regs, edge, SpecOther, m_jit.branchIfNotOther(regs, tempGPR));
10440}
10441
10442void SpeculativeJIT::speculateOther(Edge edge, JSValueRegs regs)
10443{
10444 if (!needsTypeCheck(edge, SpecOther))
10445 return;
10446
10447 GPRTemporary temp(this);
10448 GPRReg tempGPR = temp.gpr();
10449 speculateOther(edge, regs, tempGPR);
10450}
10451
10452void SpeculativeJIT::speculateOther(Edge edge)
10453{
10454 if (!needsTypeCheck(edge, SpecOther))
10455 return;
10456
10457 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10458 speculateOther(edge, operand.jsValueRegs());
10459}
10460
10461void SpeculativeJIT::speculateMisc(Edge edge, JSValueRegs regs)
10462{
10463#if USE(JSVALUE64)
10464 DFG_TYPE_CHECK(
10465 regs, edge, SpecMisc,
10466 m_jit.branch64(MacroAssembler::Above, regs.gpr(), MacroAssembler::TrustedImm64(TagBitTypeOther | TagBitBool | TagBitUndefined)));
10467#else
10468 IGNORE_WARNINGS_BEGIN("enum-compare")
10469 static_assert(JSValue::Int32Tag >= JSValue::UndefinedTag, "Int32Tag is included in >= JSValue::UndefinedTag range.");
10470 IGNORE_WARNINGS_END
10471 DFG_TYPE_CHECK(
10472 regs, edge, ~SpecInt32Only,
10473 m_jit.branchIfInt32(regs.tagGPR()));
10474 DFG_TYPE_CHECK(
10475 regs, edge, SpecMisc,
10476 m_jit.branch32(MacroAssembler::Below, regs.tagGPR(), MacroAssembler::TrustedImm32(JSValue::UndefinedTag)));
10477#endif
10478}
10479
10480void SpeculativeJIT::speculateMisc(Edge edge)
10481{
10482 if (!needsTypeCheck(edge, SpecMisc))
10483 return;
10484
10485 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10486 speculateMisc(edge, operand.jsValueRegs());
10487}
10488
10489void SpeculativeJIT::speculate(Node*, Edge edge)
10490{
10491 switch (edge.useKind()) {
10492 case UntypedUse:
10493 break;
10494 case DoubleRepUse:
10495 case Int52RepUse:
10496 case KnownInt32Use:
10497 case KnownCellUse:
10498 case KnownStringUse:
10499 case KnownPrimitiveUse:
10500 case KnownOtherUse:
10501 case KnownBooleanUse:
10502 ASSERT(!m_interpreter.needsTypeCheck(edge));
10503 break;
10504 case Int32Use:
10505 speculateInt32(edge);
10506 break;
10507 case NumberUse:
10508 speculateNumber(edge);
10509 break;
10510 case RealNumberUse:
10511 speculateRealNumber(edge);
10512 break;
10513 case DoubleRepRealUse:
10514 speculateDoubleRepReal(edge);
10515 break;
10516#if USE(JSVALUE64)
10517 case AnyIntUse:
10518 speculateAnyInt(edge);
10519 break;
10520 case DoubleRepAnyIntUse:
10521 speculateDoubleRepAnyInt(edge);
10522 break;
10523#endif
10524 case BooleanUse:
10525 speculateBoolean(edge);
10526 break;
10527 case CellUse:
10528 speculateCell(edge);
10529 break;
10530 case CellOrOtherUse:
10531 speculateCellOrOther(edge);
10532 break;
10533 case ObjectUse:
10534 speculateObject(edge);
10535 break;
10536 case FunctionUse:
10537 speculateFunction(edge);
10538 break;
10539 case ArrayUse:
10540 speculateArray(edge);
10541 break;
10542 case FinalObjectUse:
10543 speculateFinalObject(edge);
10544 break;
10545 case RegExpObjectUse:
10546 speculateRegExpObject(edge);
10547 break;
10548 case ProxyObjectUse:
10549 speculateProxyObject(edge);
10550 break;
10551 case DerivedArrayUse:
10552 speculateDerivedArray(edge);
10553 break;
10554 case MapObjectUse:
10555 speculateMapObject(edge);
10556 break;
10557 case SetObjectUse:
10558 speculateSetObject(edge);
10559 break;
10560 case WeakMapObjectUse:
10561 speculateWeakMapObject(edge);
10562 break;
10563 case WeakSetObjectUse:
10564 speculateWeakSetObject(edge);
10565 break;
10566 case DataViewObjectUse:
10567 speculateDataViewObject(edge);
10568 break;
10569 case ObjectOrOtherUse:
10570 speculateObjectOrOther(edge);
10571 break;
10572 case StringIdentUse:
10573 speculateStringIdent(edge);
10574 break;
10575 case StringUse:
10576 speculateString(edge);
10577 break;
10578 case StringOrOtherUse:
10579 speculateStringOrOther(edge);
10580 break;
10581 case SymbolUse:
10582 speculateSymbol(edge);
10583 break;
10584 case BigIntUse:
10585 speculateBigInt(edge);
10586 break;
10587 case StringObjectUse:
10588 speculateStringObject(edge);
10589 break;
10590 case StringOrStringObjectUse:
10591 speculateStringOrStringObject(edge);
10592 break;
10593 case NotStringVarUse:
10594 speculateNotStringVar(edge);
10595 break;
10596 case NotSymbolUse:
10597 speculateNotSymbol(edge);
10598 break;
10599 case NotCellUse:
10600 speculateNotCell(edge);
10601 break;
10602 case OtherUse:
10603 speculateOther(edge);
10604 break;
10605 case MiscUse:
10606 speculateMisc(edge);
10607 break;
10608 default:
10609 RELEASE_ASSERT_NOT_REACHED();
10610 break;
10611 }
10612}
10613
10614void SpeculativeJIT::emitSwitchIntJump(
10615 SwitchData* data, GPRReg value, GPRReg scratch)
10616{
10617 SimpleJumpTable& table = m_jit.codeBlock()->switchJumpTable(data->switchTableIndex);
10618 table.ensureCTITable();
10619 m_jit.sub32(Imm32(table.min), value);
10620 addBranch(
10621 m_jit.branch32(JITCompiler::AboveOrEqual, value, Imm32(table.ctiOffsets.size())),
10622 data->fallThrough.block);
10623 m_jit.move(TrustedImmPtr(table.ctiOffsets.begin()), scratch);
10624 m_jit.loadPtr(JITCompiler::BaseIndex(scratch, value, JITCompiler::timesPtr()), scratch);
10625
10626 m_jit.jump(scratch, JSSwitchPtrTag);
10627 data->didUseJumpTable = true;
10628}
10629
10630void SpeculativeJIT::emitSwitchImm(Node* node, SwitchData* data)
10631{
10632 switch (node->child1().useKind()) {
10633 case Int32Use: {
10634 SpeculateInt32Operand value(this, node->child1());
10635 GPRTemporary temp(this);
10636 emitSwitchIntJump(data, value.gpr(), temp.gpr());
10637 noResult(node);
10638 break;
10639 }
10640
10641 case UntypedUse: {
10642 JSValueOperand value(this, node->child1());
10643 GPRTemporary temp(this);
10644 JSValueRegs valueRegs = value.jsValueRegs();
10645 GPRReg scratch = temp.gpr();
10646
10647 value.use();
10648
10649 auto notInt32 = m_jit.branchIfNotInt32(valueRegs);
10650 emitSwitchIntJump(data, valueRegs.payloadGPR(), scratch);
10651 notInt32.link(&m_jit);
10652 addBranch(m_jit.branchIfNotNumber(valueRegs, scratch), data->fallThrough.block);
10653 silentSpillAllRegisters(scratch);
10654 callOperation(operationFindSwitchImmTargetForDouble, scratch, valueRegs, data->switchTableIndex);
10655 silentFillAllRegisters();
10656
10657 m_jit.jump(scratch, JSSwitchPtrTag);
10658 noResult(node, UseChildrenCalledExplicitly);
10659 break;
10660 }
10661
10662 default:
10663 RELEASE_ASSERT_NOT_REACHED();
10664 break;
10665 }
10666}
10667
10668void SpeculativeJIT::emitSwitchCharStringJump(
10669 SwitchData* data, GPRReg value, GPRReg scratch)
10670{
10671 m_jit.loadPtr(MacroAssembler::Address(value, JSString::offsetOfValue()), scratch);
10672 auto isRope = m_jit.branchIfRopeStringImpl(scratch);
10673
10674 addBranch(
10675 m_jit.branch32(
10676 MacroAssembler::NotEqual,
10677 MacroAssembler::Address(scratch, StringImpl::lengthMemoryOffset()),
10678 TrustedImm32(1)),
10679 data->fallThrough.block);
10680
10681 addSlowPathGenerator(slowPathCall(isRope, this, operationResolveRope, scratch, value));
10682
10683 m_jit.loadPtr(MacroAssembler::Address(scratch, StringImpl::dataOffset()), value);
10684
10685 JITCompiler::Jump is8Bit = m_jit.branchTest32(
10686 MacroAssembler::NonZero,
10687 MacroAssembler::Address(scratch, StringImpl::flagsOffset()),
10688 TrustedImm32(StringImpl::flagIs8Bit()));
10689
10690 m_jit.load16(MacroAssembler::Address(value), scratch);
10691
10692 JITCompiler::Jump ready = m_jit.jump();
10693
10694 is8Bit.link(&m_jit);
10695 m_jit.load8(MacroAssembler::Address(value), scratch);
10696
10697 ready.link(&m_jit);
10698 emitSwitchIntJump(data, scratch, value);
10699}
10700
10701void SpeculativeJIT::emitSwitchChar(Node* node, SwitchData* data)
10702{
10703 switch (node->child1().useKind()) {
10704 case StringUse: {
10705 SpeculateCellOperand op1(this, node->child1());
10706 GPRTemporary temp(this);
10707
10708 GPRReg op1GPR = op1.gpr();
10709 GPRReg tempGPR = temp.gpr();
10710
10711 op1.use();
10712
10713 speculateString(node->child1(), op1GPR);
10714 emitSwitchCharStringJump(data, op1GPR, tempGPR);
10715 noResult(node, UseChildrenCalledExplicitly);
10716 break;
10717 }
10718
10719 case UntypedUse: {
10720 JSValueOperand op1(this, node->child1());
10721 GPRTemporary temp(this);
10722
10723 JSValueRegs op1Regs = op1.jsValueRegs();
10724 GPRReg tempGPR = temp.gpr();
10725
10726 op1.use();
10727
10728 addBranch(m_jit.branchIfNotCell(op1Regs), data->fallThrough.block);
10729
10730 addBranch(m_jit.branchIfNotString(op1Regs.payloadGPR()), data->fallThrough.block);
10731
10732 emitSwitchCharStringJump(data, op1Regs.payloadGPR(), tempGPR);
10733 noResult(node, UseChildrenCalledExplicitly);
10734 break;
10735 }
10736
10737 default:
10738 RELEASE_ASSERT_NOT_REACHED();
10739 break;
10740 }
10741}
10742
10743namespace {
10744
10745struct CharacterCase {
10746 bool operator<(const CharacterCase& other) const
10747 {
10748 return character < other.character;
10749 }
10750
10751 LChar character;
10752 unsigned begin;
10753 unsigned end;
10754};
10755
10756} // anonymous namespace
10757
10758void SpeculativeJIT::emitBinarySwitchStringRecurse(
10759 SwitchData* data, const Vector<SpeculativeJIT::StringSwitchCase>& cases,
10760 unsigned numChecked, unsigned begin, unsigned end, GPRReg buffer, GPRReg length,
10761 GPRReg temp, unsigned alreadyCheckedLength, bool checkedExactLength)
10762{
10763 static const bool verbose = false;
10764
10765 if (verbose) {
10766 dataLog("We're down to the following cases, alreadyCheckedLength = ", alreadyCheckedLength, ":\n");
10767 for (unsigned i = begin; i < end; ++i) {
10768 dataLog(" ", cases[i].string, "\n");
10769 }
10770 }
10771
10772 if (begin == end) {
10773 jump(data->fallThrough.block, ForceJump);
10774 return;
10775 }
10776
10777 unsigned minLength = cases[begin].string->length();
10778 unsigned commonChars = minLength;
10779 bool allLengthsEqual = true;
10780 for (unsigned i = begin + 1; i < end; ++i) {
10781 unsigned myCommonChars = numChecked;
10782 for (unsigned j = numChecked;
10783 j < std::min(cases[begin].string->length(), cases[i].string->length());
10784 ++j) {
10785 if (cases[begin].string->at(j) != cases[i].string->at(j)) {
10786 if (verbose)
10787 dataLog("string(", cases[i].string, ")[", j, "] != string(", cases[begin].string, ")[", j, "]\n");
10788 break;
10789 }
10790 myCommonChars++;
10791 }
10792 commonChars = std::min(commonChars, myCommonChars);
10793 if (minLength != cases[i].string->length())
10794 allLengthsEqual = false;
10795 minLength = std::min(minLength, cases[i].string->length());
10796 }
10797
10798 if (checkedExactLength) {
10799 RELEASE_ASSERT(alreadyCheckedLength == minLength);
10800 RELEASE_ASSERT(allLengthsEqual);
10801 }
10802
10803 RELEASE_ASSERT(minLength >= commonChars);
10804
10805 if (verbose)
10806 dataLog("length = ", minLength, ", commonChars = ", commonChars, ", allLengthsEqual = ", allLengthsEqual, "\n");
10807
10808 if (!allLengthsEqual && alreadyCheckedLength < minLength)
10809 branch32(MacroAssembler::Below, length, Imm32(minLength), data->fallThrough.block);
10810 if (allLengthsEqual && (alreadyCheckedLength < minLength || !checkedExactLength))
10811 branch32(MacroAssembler::NotEqual, length, Imm32(minLength), data->fallThrough.block);
10812
10813 for (unsigned i = numChecked; i < commonChars; ++i) {
10814 branch8(
10815 MacroAssembler::NotEqual, MacroAssembler::Address(buffer, i),
10816 TrustedImm32(cases[begin].string->at(i)), data->fallThrough.block);
10817 }
10818
10819 if (minLength == commonChars) {
10820 // This is the case where one of the cases is a prefix of all of the other cases.
10821 // We've already checked that the input string is a prefix of all of the cases,
10822 // so we just check length to jump to that case.
10823
10824 if (!ASSERT_DISABLED) {
10825 ASSERT(cases[begin].string->length() == commonChars);
10826 for (unsigned i = begin + 1; i < end; ++i)
10827 ASSERT(cases[i].string->length() > commonChars);
10828 }
10829
10830 if (allLengthsEqual) {
10831 RELEASE_ASSERT(end == begin + 1);
10832 jump(cases[begin].target, ForceJump);
10833 return;
10834 }
10835
10836 branch32(MacroAssembler::Equal, length, Imm32(commonChars), cases[begin].target);
10837
10838 // We've checked if the length is >= minLength, and then we checked if the
10839 // length is == commonChars. We get to this point if it is >= minLength but not
10840 // == commonChars. Hence we know that it now must be > minLength, i.e., that
10841 // it's >= minLength + 1.
10842 emitBinarySwitchStringRecurse(
10843 data, cases, commonChars, begin + 1, end, buffer, length, temp, minLength + 1, false);
10844 return;
10845 }
10846
10847 // At this point we know that the string is longer than commonChars, and we've only
10848 // verified commonChars. Use a binary switch on the next unchecked character, i.e.
10849 // string[commonChars].
10850
10851 RELEASE_ASSERT(end >= begin + 2);
10852
10853 m_jit.load8(MacroAssembler::Address(buffer, commonChars), temp);
10854
10855 Vector<CharacterCase> characterCases;
10856 CharacterCase currentCase;
10857 currentCase.character = cases[begin].string->at(commonChars);
10858 currentCase.begin = begin;
10859 currentCase.end = begin + 1;
10860 for (unsigned i = begin + 1; i < end; ++i) {
10861 if (cases[i].string->at(commonChars) != currentCase.character) {
10862 if (verbose)
10863 dataLog("string(", cases[i].string, ")[", commonChars, "] != string(", cases[begin].string, ")[", commonChars, "]\n");
10864 currentCase.end = i;
10865 characterCases.append(currentCase);
10866 currentCase.character = cases[i].string->at(commonChars);
10867 currentCase.begin = i;
10868 currentCase.end = i + 1;
10869 } else
10870 currentCase.end = i + 1;
10871 }
10872 characterCases.append(currentCase);
10873
10874 Vector<int64_t> characterCaseValues;
10875 for (unsigned i = 0; i < characterCases.size(); ++i)
10876 characterCaseValues.append(characterCases[i].character);
10877
10878 BinarySwitch binarySwitch(temp, characterCaseValues, BinarySwitch::Int32);
10879 while (binarySwitch.advance(m_jit)) {
10880 const CharacterCase& myCase = characterCases[binarySwitch.caseIndex()];
10881 emitBinarySwitchStringRecurse(
10882 data, cases, commonChars + 1, myCase.begin, myCase.end, buffer, length,
10883 temp, minLength, allLengthsEqual);
10884 }
10885
10886 addBranch(binarySwitch.fallThrough(), data->fallThrough.block);
10887}
10888
10889void SpeculativeJIT::emitSwitchStringOnString(SwitchData* data, GPRReg string)
10890{
10891 data->didUseJumpTable = true;
10892
10893 bool canDoBinarySwitch = true;
10894 unsigned totalLength = 0;
10895
10896 for (unsigned i = data->cases.size(); i--;) {
10897 StringImpl* string = data->cases[i].value.stringImpl();
10898 if (!string->is8Bit()) {
10899 canDoBinarySwitch = false;
10900 break;
10901 }
10902 if (string->length() > Options::maximumBinaryStringSwitchCaseLength()) {
10903 canDoBinarySwitch = false;
10904 break;
10905 }
10906 totalLength += string->length();
10907 }
10908
10909 if (!canDoBinarySwitch || totalLength > Options::maximumBinaryStringSwitchTotalLength()) {
10910 flushRegisters();
10911 callOperation(
10912 operationSwitchString, string, static_cast<size_t>(data->switchTableIndex), string);
10913 m_jit.exceptionCheck();
10914 m_jit.jump(string, JSSwitchPtrTag);
10915 return;
10916 }
10917
10918 GPRTemporary length(this);
10919 GPRTemporary temp(this);
10920
10921 GPRReg lengthGPR = length.gpr();
10922 GPRReg tempGPR = temp.gpr();
10923
10924 MacroAssembler::JumpList slowCases;
10925 m_jit.loadPtr(MacroAssembler::Address(string, JSString::offsetOfValue()), tempGPR);
10926 slowCases.append(m_jit.branchIfRopeStringImpl(tempGPR));
10927 m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), lengthGPR);
10928
10929 slowCases.append(m_jit.branchTest32(
10930 MacroAssembler::Zero,
10931 MacroAssembler::Address(tempGPR, StringImpl::flagsOffset()),
10932 TrustedImm32(StringImpl::flagIs8Bit())));
10933
10934 m_jit.loadPtr(MacroAssembler::Address(tempGPR, StringImpl::dataOffset()), string);
10935
10936 Vector<StringSwitchCase> cases;
10937 for (unsigned i = 0; i < data->cases.size(); ++i) {
10938 cases.append(
10939 StringSwitchCase(data->cases[i].value.stringImpl(), data->cases[i].target.block));
10940 }
10941
10942 std::sort(cases.begin(), cases.end());
10943
10944 emitBinarySwitchStringRecurse(
10945 data, cases, 0, 0, cases.size(), string, lengthGPR, tempGPR, 0, false);
10946
10947 slowCases.link(&m_jit);
10948 silentSpillAllRegisters(string);
10949 callOperation(operationSwitchString, string, static_cast<size_t>(data->switchTableIndex), string);
10950 silentFillAllRegisters();
10951 m_jit.exceptionCheck();
10952 m_jit.jump(string, JSSwitchPtrTag);
10953}
10954
10955void SpeculativeJIT::emitSwitchString(Node* node, SwitchData* data)
10956{
10957 switch (node->child1().useKind()) {
10958 case StringIdentUse: {
10959 SpeculateCellOperand op1(this, node->child1());
10960 GPRTemporary temp(this);
10961
10962 GPRReg op1GPR = op1.gpr();
10963 GPRReg tempGPR = temp.gpr();
10964
10965 speculateString(node->child1(), op1GPR);
10966 speculateStringIdentAndLoadStorage(node->child1(), op1GPR, tempGPR);
10967
10968 Vector<int64_t> identifierCaseValues;
10969 for (unsigned i = 0; i < data->cases.size(); ++i) {
10970 identifierCaseValues.append(
10971 static_cast<int64_t>(bitwise_cast<intptr_t>(data->cases[i].value.stringImpl())));
10972 }
10973
10974 BinarySwitch binarySwitch(tempGPR, identifierCaseValues, BinarySwitch::IntPtr);
10975 while (binarySwitch.advance(m_jit))
10976 jump(data->cases[binarySwitch.caseIndex()].target.block, ForceJump);
10977 addBranch(binarySwitch.fallThrough(), data->fallThrough.block);
10978
10979 noResult(node);
10980 break;
10981 }
10982
10983 case StringUse: {
10984 SpeculateCellOperand op1(this, node->child1());
10985
10986 GPRReg op1GPR = op1.gpr();
10987
10988 op1.use();
10989
10990 speculateString(node->child1(), op1GPR);
10991 emitSwitchStringOnString(data, op1GPR);
10992 noResult(node, UseChildrenCalledExplicitly);
10993 break;
10994 }
10995
10996 case UntypedUse: {
10997 JSValueOperand op1(this, node->child1());
10998
10999 JSValueRegs op1Regs = op1.jsValueRegs();
11000
11001 op1.use();
11002
11003 addBranch(m_jit.branchIfNotCell(op1Regs), data->fallThrough.block);
11004
11005 addBranch(m_jit.branchIfNotString(op1Regs.payloadGPR()), data->fallThrough.block);
11006
11007 emitSwitchStringOnString(data, op1Regs.payloadGPR());
11008 noResult(node, UseChildrenCalledExplicitly);
11009 break;
11010 }
11011
11012 default:
11013 RELEASE_ASSERT_NOT_REACHED();
11014 break;
11015 }
11016}
11017
11018void SpeculativeJIT::emitSwitch(Node* node)
11019{
11020 SwitchData* data = node->switchData();
11021 switch (data->kind) {
11022 case SwitchImm: {
11023 emitSwitchImm(node, data);
11024 return;
11025 }
11026 case SwitchChar: {
11027 emitSwitchChar(node, data);
11028 return;
11029 }
11030 case SwitchString: {
11031 emitSwitchString(node, data);
11032 return;
11033 }
11034 case SwitchCell: {
11035 DFG_CRASH(m_jit.graph(), node, "Bad switch kind");
11036 return;
11037 } }
11038 RELEASE_ASSERT_NOT_REACHED();
11039}
11040
11041void SpeculativeJIT::addBranch(const MacroAssembler::JumpList& jump, BasicBlock* destination)
11042{
11043 for (unsigned i = jump.jumps().size(); i--;)
11044 addBranch(jump.jumps()[i], destination);
11045}
11046
11047void SpeculativeJIT::linkBranches()
11048{
11049 for (auto& branch : m_branches)
11050 branch.jump.linkTo(m_jit.blockHeads()[branch.destination->index], &m_jit);
11051}
11052
11053void SpeculativeJIT::compileStoreBarrier(Node* node)
11054{
11055 ASSERT(node->op() == StoreBarrier || node->op() == FencedStoreBarrier);
11056
11057 bool isFenced = node->op() == FencedStoreBarrier;
11058
11059 SpeculateCellOperand base(this, node->child1());
11060 GPRTemporary scratch1(this);
11061
11062 GPRReg baseGPR = base.gpr();
11063 GPRReg scratch1GPR = scratch1.gpr();
11064
11065 JITCompiler::JumpList ok;
11066
11067 if (isFenced) {
11068 ok.append(m_jit.barrierBranch(*m_jit.vm(), baseGPR, scratch1GPR));
11069
11070 JITCompiler::Jump noFence = m_jit.jumpIfMutatorFenceNotNeeded(*m_jit.vm());
11071 m_jit.memoryFence();
11072 ok.append(m_jit.barrierBranchWithoutFence(baseGPR));
11073 noFence.link(&m_jit);
11074 } else
11075 ok.append(m_jit.barrierBranchWithoutFence(baseGPR));
11076
11077 silentSpillAllRegisters(InvalidGPRReg);
11078 callOperation(operationWriteBarrierSlowPath, baseGPR);
11079 silentFillAllRegisters();
11080
11081 ok.link(&m_jit);
11082
11083 noResult(node);
11084}
11085
11086void SpeculativeJIT::compilePutAccessorById(Node* node)
11087{
11088 SpeculateCellOperand base(this, node->child1());
11089 SpeculateCellOperand accessor(this, node->child2());
11090
11091 GPRReg baseGPR = base.gpr();
11092 GPRReg accessorGPR = accessor.gpr();
11093
11094 flushRegisters();
11095 callOperation(node->op() == PutGetterById ? operationPutGetterById : operationPutSetterById, NoResult, baseGPR, identifierUID(node->identifierNumber()), node->accessorAttributes(), accessorGPR);
11096 m_jit.exceptionCheck();
11097
11098 noResult(node);
11099}
11100
11101void SpeculativeJIT::compilePutGetterSetterById(Node* node)
11102{
11103 SpeculateCellOperand base(this, node->child1());
11104 JSValueOperand getter(this, node->child2());
11105 JSValueOperand setter(this, node->child3());
11106
11107#if USE(JSVALUE64)
11108 GPRReg baseGPR = base.gpr();
11109 GPRReg getterGPR = getter.gpr();
11110 GPRReg setterGPR = setter.gpr();
11111
11112 flushRegisters();
11113 callOperation(operationPutGetterSetter, NoResult, baseGPR, identifierUID(node->identifierNumber()), node->accessorAttributes(), getterGPR, setterGPR);
11114#else
11115 // These JSValues may be JSUndefined OR JSFunction*.
11116 // At that time,
11117 // 1. If the JSValue is JSUndefined, its payload becomes nullptr.
11118 // 2. If the JSValue is JSFunction*, its payload becomes JSFunction*.
11119 // So extract payload and pass it to operationPutGetterSetter. This hack is used as the same way in baseline JIT.
11120 GPRReg baseGPR = base.gpr();
11121 JSValueRegs getterRegs = getter.jsValueRegs();
11122 JSValueRegs setterRegs = setter.jsValueRegs();
11123
11124 flushRegisters();
11125 callOperation(operationPutGetterSetter, NoResult, baseGPR, identifierUID(node->identifierNumber()), node->accessorAttributes(), getterRegs.payloadGPR(), setterRegs.payloadGPR());
11126#endif
11127 m_jit.exceptionCheck();
11128
11129 noResult(node);
11130}
11131
11132void SpeculativeJIT::compileResolveScope(Node* node)
11133{
11134 SpeculateCellOperand scope(this, node->child1());
11135 GPRReg scopeGPR = scope.gpr();
11136 GPRFlushedCallResult result(this);
11137 GPRReg resultGPR = result.gpr();
11138 flushRegisters();
11139 callOperation(operationResolveScope, resultGPR, scopeGPR, identifierUID(node->identifierNumber()));
11140 m_jit.exceptionCheck();
11141 cellResult(resultGPR, node);
11142}
11143
11144void SpeculativeJIT::compileResolveScopeForHoistingFuncDeclInEval(Node* node)
11145{
11146 SpeculateCellOperand scope(this, node->child1());
11147 GPRReg scopeGPR = scope.gpr();
11148 flushRegisters();
11149 JSValueRegsFlushedCallResult result(this);
11150 JSValueRegs resultRegs = result.regs();
11151 callOperation(operationResolveScopeForHoistingFuncDeclInEval, resultRegs, scopeGPR, identifierUID(node->identifierNumber()));
11152 m_jit.exceptionCheck();
11153 jsValueResult(resultRegs, node);
11154}
11155
11156void SpeculativeJIT::compileGetGlobalVariable(Node* node)
11157{
11158 JSValueRegsTemporary result(this);
11159 JSValueRegs resultRegs = result.regs();
11160 m_jit.loadValue(node->variablePointer(), resultRegs);
11161 jsValueResult(resultRegs, node);
11162}
11163
11164void SpeculativeJIT::compilePutGlobalVariable(Node* node)
11165{
11166 JSValueOperand value(this, node->child2());
11167 JSValueRegs valueRegs = value.jsValueRegs();
11168 m_jit.storeValue(valueRegs, node->variablePointer());
11169 noResult(node);
11170}
11171
11172void SpeculativeJIT::compileGetDynamicVar(Node* node)
11173{
11174 SpeculateCellOperand scope(this, node->child1());
11175 GPRReg scopeGPR = scope.gpr();
11176 flushRegisters();
11177 JSValueRegsFlushedCallResult result(this);
11178 JSValueRegs resultRegs = result.regs();
11179 callOperation(operationGetDynamicVar, resultRegs, scopeGPR, identifierUID(node->identifierNumber()), node->getPutInfo());
11180 m_jit.exceptionCheck();
11181 jsValueResult(resultRegs, node);
11182}
11183
11184void SpeculativeJIT::compilePutDynamicVar(Node* node)
11185{
11186 SpeculateCellOperand scope(this, node->child1());
11187 JSValueOperand value(this, node->child2());
11188
11189 GPRReg scopeGPR = scope.gpr();
11190 JSValueRegs valueRegs = value.jsValueRegs();
11191
11192 flushRegisters();
11193 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutDynamicVarStrict : operationPutDynamicVarNonStrict, NoResult, scopeGPR, valueRegs, identifierUID(node->identifierNumber()), node->getPutInfo());
11194 m_jit.exceptionCheck();
11195 noResult(node);
11196}
11197
11198void SpeculativeJIT::compileGetClosureVar(Node* node)
11199{
11200 SpeculateCellOperand base(this, node->child1());
11201 JSValueRegsTemporary result(this);
11202
11203 GPRReg baseGPR = base.gpr();
11204 JSValueRegs resultRegs = result.regs();
11205
11206 m_jit.loadValue(JITCompiler::Address(baseGPR, JSLexicalEnvironment::offsetOfVariable(node->scopeOffset())), resultRegs);
11207 jsValueResult(resultRegs, node);
11208}
11209
11210void SpeculativeJIT::compilePutClosureVar(Node* node)
11211{
11212 SpeculateCellOperand base(this, node->child1());
11213 JSValueOperand value(this, node->child2());
11214
11215 GPRReg baseGPR = base.gpr();
11216 JSValueRegs valueRegs = value.jsValueRegs();
11217
11218 m_jit.storeValue(valueRegs, JITCompiler::Address(baseGPR, JSLexicalEnvironment::offsetOfVariable(node->scopeOffset())));
11219 noResult(node);
11220}
11221
11222void SpeculativeJIT::compilePutAccessorByVal(Node* node)
11223{
11224 SpeculateCellOperand base(this, node->child1());
11225 JSValueOperand subscript(this, node->child2());
11226 SpeculateCellOperand accessor(this, node->child3());
11227
11228 auto operation = node->op() == PutGetterByVal ? operationPutGetterByVal : operationPutSetterByVal;
11229
11230 GPRReg baseGPR = base.gpr();
11231 JSValueRegs subscriptRegs = subscript.jsValueRegs();
11232 GPRReg accessorGPR = accessor.gpr();
11233
11234 flushRegisters();
11235 callOperation(operation, NoResult, baseGPR, subscriptRegs, node->accessorAttributes(), accessorGPR);
11236 m_jit.exceptionCheck();
11237
11238 noResult(node);
11239}
11240
11241void SpeculativeJIT::compileGetRegExpObjectLastIndex(Node* node)
11242{
11243 SpeculateCellOperand regExp(this, node->child1());
11244 JSValueRegsTemporary result(this);
11245 GPRReg regExpGPR = regExp.gpr();
11246 JSValueRegs resultRegs = result.regs();
11247 speculateRegExpObject(node->child1(), regExpGPR);
11248 m_jit.loadValue(JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndex()), resultRegs);
11249 jsValueResult(resultRegs, node);
11250}
11251
11252void SpeculativeJIT::compileSetRegExpObjectLastIndex(Node* node)
11253{
11254 SpeculateCellOperand regExp(this, node->child1());
11255 JSValueOperand value(this, node->child2());
11256 GPRReg regExpGPR = regExp.gpr();
11257 JSValueRegs valueRegs = value.jsValueRegs();
11258
11259 if (!node->ignoreLastIndexIsWritable()) {
11260 speculateRegExpObject(node->child1(), regExpGPR);
11261 speculationCheck(
11262 ExoticObjectMode, JSValueRegs(), nullptr,
11263 m_jit.branchTestPtr(
11264 JITCompiler::NonZero,
11265 JITCompiler::Address(regExpGPR, RegExpObject::offsetOfRegExpAndLastIndexIsNotWritableFlag()),
11266 JITCompiler::TrustedImm32(RegExpObject::lastIndexIsNotWritableFlag)));
11267 }
11268
11269 m_jit.storeValue(valueRegs, JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndex()));
11270 noResult(node);
11271}
11272
11273void SpeculativeJIT::compileRegExpExec(Node* node)
11274{
11275 bool sample = false;
11276 if (sample)
11277 m_jit.incrementSuperSamplerCount();
11278
11279 SpeculateCellOperand globalObject(this, node->child1());
11280 GPRReg globalObjectGPR = globalObject.gpr();
11281
11282 if (node->child2().useKind() == RegExpObjectUse) {
11283 if (node->child3().useKind() == StringUse) {
11284 SpeculateCellOperand base(this, node->child2());
11285 SpeculateCellOperand argument(this, node->child3());
11286 GPRReg baseGPR = base.gpr();
11287 GPRReg argumentGPR = argument.gpr();
11288 speculateRegExpObject(node->child2(), baseGPR);
11289 speculateString(node->child3(), argumentGPR);
11290
11291 flushRegisters();
11292 JSValueRegsFlushedCallResult result(this);
11293 JSValueRegs resultRegs = result.regs();
11294 callOperation(operationRegExpExecString, resultRegs, globalObjectGPR, baseGPR, argumentGPR);
11295 m_jit.exceptionCheck();
11296
11297 jsValueResult(resultRegs, node);
11298
11299 if (sample)
11300 m_jit.decrementSuperSamplerCount();
11301 return;
11302 }
11303
11304 SpeculateCellOperand base(this, node->child2());
11305 JSValueOperand argument(this, node->child3());
11306 GPRReg baseGPR = base.gpr();
11307 JSValueRegs argumentRegs = argument.jsValueRegs();
11308 speculateRegExpObject(node->child2(), baseGPR);
11309
11310 flushRegisters();
11311 JSValueRegsFlushedCallResult result(this);
11312 JSValueRegs resultRegs = result.regs();
11313 callOperation(operationRegExpExec, resultRegs, globalObjectGPR, baseGPR, argumentRegs);
11314 m_jit.exceptionCheck();
11315
11316 jsValueResult(resultRegs, node);
11317
11318 if (sample)
11319 m_jit.decrementSuperSamplerCount();
11320 return;
11321 }
11322
11323 JSValueOperand base(this, node->child2());
11324 JSValueOperand argument(this, node->child3());
11325 JSValueRegs baseRegs = base.jsValueRegs();
11326 JSValueRegs argumentRegs = argument.jsValueRegs();
11327
11328 flushRegisters();
11329 JSValueRegsFlushedCallResult result(this);
11330 JSValueRegs resultRegs = result.regs();
11331 callOperation(operationRegExpExecGeneric, resultRegs, globalObjectGPR, baseRegs, argumentRegs);
11332 m_jit.exceptionCheck();
11333
11334 jsValueResult(resultRegs, node);
11335
11336 if (sample)
11337 m_jit.decrementSuperSamplerCount();
11338}
11339
11340void SpeculativeJIT::compileRegExpTest(Node* node)
11341{
11342 SpeculateCellOperand globalObject(this, node->child1());
11343 GPRReg globalObjectGPR = globalObject.gpr();
11344
11345 if (node->child2().useKind() == RegExpObjectUse) {
11346 if (node->child3().useKind() == StringUse) {
11347 SpeculateCellOperand base(this, node->child2());
11348 SpeculateCellOperand argument(this, node->child3());
11349 GPRReg baseGPR = base.gpr();
11350 GPRReg argumentGPR = argument.gpr();
11351 speculateRegExpObject(node->child2(), baseGPR);
11352 speculateString(node->child3(), argumentGPR);
11353
11354 flushRegisters();
11355 GPRFlushedCallResult result(this);
11356 callOperation(operationRegExpTestString, result.gpr(), globalObjectGPR, baseGPR, argumentGPR);
11357 m_jit.exceptionCheck();
11358
11359 unblessedBooleanResult(result.gpr(), node);
11360 return;
11361 }
11362
11363 SpeculateCellOperand base(this, node->child2());
11364 JSValueOperand argument(this, node->child3());
11365 GPRReg baseGPR = base.gpr();
11366 JSValueRegs argumentRegs = argument.jsValueRegs();
11367 speculateRegExpObject(node->child2(), baseGPR);
11368
11369 flushRegisters();
11370 GPRFlushedCallResult result(this);
11371 callOperation(operationRegExpTest, result.gpr(), globalObjectGPR, baseGPR, argumentRegs);
11372 m_jit.exceptionCheck();
11373
11374 unblessedBooleanResult(result.gpr(), node);
11375 return;
11376 }
11377
11378 JSValueOperand base(this, node->child2());
11379 JSValueOperand argument(this, node->child3());
11380 JSValueRegs baseRegs = base.jsValueRegs();
11381 JSValueRegs argumentRegs = argument.jsValueRegs();
11382
11383 flushRegisters();
11384 GPRFlushedCallResult result(this);
11385 callOperation(operationRegExpTestGeneric, result.gpr(), globalObjectGPR, baseRegs, argumentRegs);
11386 m_jit.exceptionCheck();
11387
11388 unblessedBooleanResult(result.gpr(), node);
11389}
11390
11391void SpeculativeJIT::compileStringReplace(Node* node)
11392{
11393 ASSERT(node->op() == StringReplace || node->op() == StringReplaceRegExp);
11394 bool sample = false;
11395 if (sample)
11396 m_jit.incrementSuperSamplerCount();
11397
11398 if (node->child1().useKind() == StringUse
11399 && node->child2().useKind() == RegExpObjectUse
11400 && node->child3().useKind() == StringUse) {
11401 if (JSString* replace = node->child3()->dynamicCastConstant<JSString*>(*m_jit.vm())) {
11402 if (!replace->length()) {
11403 SpeculateCellOperand string(this, node->child1());
11404 SpeculateCellOperand regExp(this, node->child2());
11405 GPRReg stringGPR = string.gpr();
11406 GPRReg regExpGPR = regExp.gpr();
11407 speculateString(node->child1(), stringGPR);
11408 speculateRegExpObject(node->child2(), regExpGPR);
11409
11410 flushRegisters();
11411 GPRFlushedCallResult result(this);
11412 callOperation(operationStringProtoFuncReplaceRegExpEmptyStr, result.gpr(), stringGPR, regExpGPR);
11413 m_jit.exceptionCheck();
11414 cellResult(result.gpr(), node);
11415 if (sample)
11416 m_jit.decrementSuperSamplerCount();
11417 return;
11418 }
11419 }
11420
11421 SpeculateCellOperand string(this, node->child1());
11422 SpeculateCellOperand regExp(this, node->child2());
11423 SpeculateCellOperand replace(this, node->child3());
11424 GPRReg stringGPR = string.gpr();
11425 GPRReg regExpGPR = regExp.gpr();
11426 GPRReg replaceGPR = replace.gpr();
11427 speculateString(node->child1(), stringGPR);
11428 speculateRegExpObject(node->child2(), regExpGPR);
11429 speculateString(node->child3(), replaceGPR);
11430
11431 flushRegisters();
11432 GPRFlushedCallResult result(this);
11433 callOperation(operationStringProtoFuncReplaceRegExpString, result.gpr(), stringGPR, regExpGPR, replaceGPR);
11434 m_jit.exceptionCheck();
11435 cellResult(result.gpr(), node);
11436 if (sample)
11437 m_jit.decrementSuperSamplerCount();
11438 return;
11439 }
11440
11441 // If we fixed up the edge of child2, we inserted a Check(@child2, String).
11442 OperandSpeculationMode child2SpeculationMode = AutomaticOperandSpeculation;
11443 if (node->child2().useKind() == StringUse)
11444 child2SpeculationMode = ManualOperandSpeculation;
11445
11446 JSValueOperand string(this, node->child1());
11447 JSValueOperand search(this, node->child2(), child2SpeculationMode);
11448 JSValueOperand replace(this, node->child3());
11449 JSValueRegs stringRegs = string.jsValueRegs();
11450 JSValueRegs searchRegs = search.jsValueRegs();
11451 JSValueRegs replaceRegs = replace.jsValueRegs();
11452
11453 flushRegisters();
11454 GPRFlushedCallResult result(this);
11455 callOperation(operationStringProtoFuncReplaceGeneric, result.gpr(), stringRegs, searchRegs, replaceRegs);
11456 m_jit.exceptionCheck();
11457 cellResult(result.gpr(), node);
11458 if (sample)
11459 m_jit.decrementSuperSamplerCount();
11460}
11461
11462void SpeculativeJIT::compileRegExpExecNonGlobalOrSticky(Node* node)
11463{
11464 SpeculateCellOperand globalObject(this, node->child1());
11465 SpeculateCellOperand argument(this, node->child2());
11466 GPRReg globalObjectGPR = globalObject.gpr();
11467 GPRReg argumentGPR = argument.gpr();
11468
11469 speculateString(node->child2(), argumentGPR);
11470
11471 flushRegisters();
11472 JSValueRegsFlushedCallResult result(this);
11473 JSValueRegs resultRegs = result.regs();
11474 callOperation(
11475 operationRegExpExecNonGlobalOrSticky, resultRegs,
11476 globalObjectGPR, TrustedImmPtr(node->cellOperand()), argumentGPR);
11477 m_jit.exceptionCheck();
11478
11479 jsValueResult(resultRegs, node);
11480}
11481
11482void SpeculativeJIT::compileRegExpMatchFastGlobal(Node* node)
11483{
11484 SpeculateCellOperand globalObject(this, node->child1());
11485 SpeculateCellOperand argument(this, node->child2());
11486 GPRReg globalObjectGPR = globalObject.gpr();
11487 GPRReg argumentGPR = argument.gpr();
11488
11489 speculateString(node->child2(), argumentGPR);
11490
11491 flushRegisters();
11492 JSValueRegsFlushedCallResult result(this);
11493 JSValueRegs resultRegs = result.regs();
11494 callOperation(
11495 operationRegExpMatchFastGlobalString, resultRegs,
11496 globalObjectGPR, TrustedImmPtr(node->cellOperand()), argumentGPR);
11497 m_jit.exceptionCheck();
11498
11499 jsValueResult(resultRegs, node);
11500}
11501
11502void SpeculativeJIT::compileRegExpMatchFast(Node* node)
11503{
11504 SpeculateCellOperand globalObject(this, node->child1());
11505 SpeculateCellOperand base(this, node->child2());
11506 SpeculateCellOperand argument(this, node->child3());
11507 GPRReg globalObjectGPR = globalObject.gpr();
11508 GPRReg baseGPR = base.gpr();
11509 GPRReg argumentGPR = argument.gpr();
11510 speculateRegExpObject(node->child2(), baseGPR);
11511 speculateString(node->child3(), argumentGPR);
11512
11513 flushRegisters();
11514 JSValueRegsFlushedCallResult result(this);
11515 JSValueRegs resultRegs = result.regs();
11516 callOperation(
11517 operationRegExpMatchFastString, resultRegs,
11518 globalObjectGPR, baseGPR, argumentGPR);
11519 m_jit.exceptionCheck();
11520
11521 jsValueResult(resultRegs, node);
11522}
11523
11524void SpeculativeJIT::compileLazyJSConstant(Node* node)
11525{
11526 JSValueRegsTemporary result(this);
11527 JSValueRegs resultRegs = result.regs();
11528 node->lazyJSValue().emit(m_jit, resultRegs);
11529 jsValueResult(resultRegs, node);
11530}
11531
11532void SpeculativeJIT::compileMaterializeNewObject(Node* node)
11533{
11534 RegisteredStructure structure = node->structureSet().at(0);
11535 ASSERT(m_jit.graph().varArgChild(node, 0)->dynamicCastConstant<Structure*>(*m_jit.vm()) == structure.get());
11536
11537 ObjectMaterializationData& data = node->objectMaterializationData();
11538
11539 IndexingType indexingType = structure->indexingType();
11540 bool hasIndexingHeader = hasIndexedProperties(indexingType);
11541 int32_t publicLength = 0;
11542 int32_t vectorLength = 0;
11543
11544 if (hasIndexingHeader) {
11545 for (unsigned i = data.m_properties.size(); i--;) {
11546 Edge edge = m_jit.graph().varArgChild(node, 1 + i);
11547 switch (data.m_properties[i].kind()) {
11548 case PublicLengthPLoc:
11549 publicLength = edge->asInt32();
11550 break;
11551 case VectorLengthPLoc:
11552 vectorLength = edge->asInt32();
11553 break;
11554 default:
11555 break;
11556 }
11557 }
11558 }
11559
11560 GPRTemporary result(this);
11561 GPRTemporary storage(this);
11562 GPRReg resultGPR = result.gpr();
11563 GPRReg storageGPR = storage.gpr();
11564
11565 emitAllocateRawObject(resultGPR, structure, storageGPR, 0, vectorLength);
11566
11567 m_jit.store32(
11568 JITCompiler::TrustedImm32(publicLength),
11569 JITCompiler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
11570
11571 for (unsigned i = data.m_properties.size(); i--;) {
11572 Edge edge = m_jit.graph().varArgChild(node, 1 + i);
11573 PromotedLocationDescriptor descriptor = data.m_properties[i];
11574 switch (descriptor.kind()) {
11575 case IndexedPropertyPLoc: {
11576 JSValueOperand value(this, edge);
11577 m_jit.storeValue(
11578 value.jsValueRegs(),
11579 JITCompiler::Address(storageGPR, sizeof(EncodedJSValue) * descriptor.info()));
11580 break;
11581 }
11582
11583 case NamedPropertyPLoc: {
11584 StringImpl* uid = m_jit.graph().identifiers()[descriptor.info()];
11585 for (PropertyMapEntry entry : structure->getPropertiesConcurrently()) {
11586 if (uid != entry.key)
11587 continue;
11588
11589 JSValueOperand value(this, edge);
11590 GPRReg baseGPR = isInlineOffset(entry.offset) ? resultGPR : storageGPR;
11591 m_jit.storeValue(
11592 value.jsValueRegs(),
11593 JITCompiler::Address(baseGPR, offsetRelativeToBase(entry.offset)));
11594 }
11595 break;
11596 }
11597
11598 default:
11599 break;
11600 }
11601 }
11602
11603 cellResult(resultGPR, node);
11604}
11605
11606void SpeculativeJIT::compileRecordRegExpCachedResult(Node* node)
11607{
11608 Edge globalObjectEdge = m_jit.graph().varArgChild(node, 0);
11609 Edge regExpEdge = m_jit.graph().varArgChild(node, 1);
11610 Edge stringEdge = m_jit.graph().varArgChild(node, 2);
11611 Edge startEdge = m_jit.graph().varArgChild(node, 3);
11612 Edge endEdge = m_jit.graph().varArgChild(node, 4);
11613
11614 SpeculateCellOperand globalObject(this, globalObjectEdge);
11615 SpeculateCellOperand regExp(this, regExpEdge);
11616 SpeculateCellOperand string(this, stringEdge);
11617 SpeculateInt32Operand start(this, startEdge);
11618 SpeculateInt32Operand end(this, endEdge);
11619
11620 GPRReg globalObjectGPR = globalObject.gpr();
11621 GPRReg regExpGPR = regExp.gpr();
11622 GPRReg stringGPR = string.gpr();
11623 GPRReg startGPR = start.gpr();
11624 GPRReg endGPR = end.gpr();
11625
11626 ptrdiff_t offset = JSGlobalObject::regExpGlobalDataOffset() + RegExpGlobalData::offsetOfCachedResult();
11627
11628 m_jit.storePtr(
11629 regExpGPR,
11630 JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfLastRegExp()));
11631 m_jit.storePtr(
11632 stringGPR,
11633 JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfLastInput()));
11634 m_jit.store32(
11635 startGPR,
11636 JITCompiler::Address(
11637 globalObjectGPR,
11638 offset + RegExpCachedResult::offsetOfResult() + OBJECT_OFFSETOF(MatchResult, start)));
11639 m_jit.store32(
11640 endGPR,
11641 JITCompiler::Address(
11642 globalObjectGPR,
11643 offset + RegExpCachedResult::offsetOfResult() + OBJECT_OFFSETOF(MatchResult, end)));
11644 m_jit.store8(
11645 TrustedImm32(0),
11646 JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfReified()));
11647
11648 noResult(node);
11649}
11650
11651void SpeculativeJIT::compileDefineDataProperty(Node* node)
11652{
11653#if USE(JSVALUE64)
11654 static_assert(GPRInfo::numberOfRegisters >= 5, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
11655#else
11656 static_assert(GPRInfo::numberOfRegisters >= 6, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
11657#endif
11658
11659 SpeculateCellOperand base(this, m_jit.graph().varArgChild(node, 0));
11660 GPRReg baseGPR = base.gpr();
11661
11662 JSValueOperand value(this, m_jit.graph().varArgChild(node, 2));
11663 JSValueRegs valueRegs = value.jsValueRegs();
11664
11665 SpeculateInt32Operand attributes(this, m_jit.graph().varArgChild(node, 3));
11666 GPRReg attributesGPR = attributes.gpr();
11667
11668 Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
11669 switch (propertyEdge.useKind()) {
11670 case StringUse: {
11671 SpeculateCellOperand property(this, propertyEdge);
11672 GPRReg propertyGPR = property.gpr();
11673 speculateString(propertyEdge, propertyGPR);
11674
11675 useChildren(node);
11676
11677 flushRegisters();
11678 callOperation(operationDefineDataPropertyString, NoResult, baseGPR, propertyGPR, valueRegs, attributesGPR);
11679 m_jit.exceptionCheck();
11680 break;
11681 }
11682 case StringIdentUse: {
11683 SpeculateCellOperand property(this, propertyEdge);
11684 GPRTemporary ident(this);
11685
11686 GPRReg propertyGPR = property.gpr();
11687 GPRReg identGPR = ident.gpr();
11688
11689 speculateString(propertyEdge, propertyGPR);
11690 speculateStringIdentAndLoadStorage(propertyEdge, propertyGPR, identGPR);
11691
11692 useChildren(node);
11693
11694 flushRegisters();
11695 callOperation(operationDefineDataPropertyStringIdent, NoResult, baseGPR, identGPR, valueRegs, attributesGPR);
11696 m_jit.exceptionCheck();
11697 break;
11698 }
11699 case SymbolUse: {
11700 SpeculateCellOperand property(this, propertyEdge);
11701 GPRReg propertyGPR = property.gpr();
11702 speculateSymbol(propertyEdge, propertyGPR);
11703
11704 useChildren(node);
11705
11706 flushRegisters();
11707 callOperation(operationDefineDataPropertySymbol, NoResult, baseGPR, propertyGPR, valueRegs, attributesGPR);
11708 m_jit.exceptionCheck();
11709 break;
11710 }
11711 case UntypedUse: {
11712 JSValueOperand property(this, propertyEdge);
11713 JSValueRegs propertyRegs = property.jsValueRegs();
11714
11715 useChildren(node);
11716
11717 flushRegisters();
11718 callOperation(operationDefineDataProperty, NoResult, baseGPR, propertyRegs, valueRegs, attributesGPR);
11719 m_jit.exceptionCheck();
11720 break;
11721 }
11722 default:
11723 RELEASE_ASSERT_NOT_REACHED();
11724 }
11725
11726 noResult(node, UseChildrenCalledExplicitly);
11727}
11728
11729void SpeculativeJIT::compileDefineAccessorProperty(Node* node)
11730{
11731#if USE(JSVALUE64)
11732 static_assert(GPRInfo::numberOfRegisters >= 5, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
11733#else
11734 static_assert(GPRInfo::numberOfRegisters >= 6, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
11735#endif
11736
11737 SpeculateCellOperand base(this, m_jit.graph().varArgChild(node, 0));
11738 GPRReg baseGPR = base.gpr();
11739
11740 SpeculateCellOperand getter(this, m_jit.graph().varArgChild(node, 2));
11741 GPRReg getterGPR = getter.gpr();
11742
11743 SpeculateCellOperand setter(this, m_jit.graph().varArgChild(node, 3));
11744 GPRReg setterGPR = setter.gpr();
11745
11746 SpeculateInt32Operand attributes(this, m_jit.graph().varArgChild(node, 4));
11747 GPRReg attributesGPR = attributes.gpr();
11748
11749 Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
11750 switch (propertyEdge.useKind()) {
11751 case StringUse: {
11752 SpeculateCellOperand property(this, propertyEdge);
11753 GPRReg propertyGPR = property.gpr();
11754 speculateString(propertyEdge, propertyGPR);
11755
11756 useChildren(node);
11757
11758 flushRegisters();
11759 callOperation(operationDefineAccessorPropertyString, NoResult, baseGPR, propertyGPR, getterGPR, setterGPR, attributesGPR);
11760 m_jit.exceptionCheck();
11761 break;
11762 }
11763 case StringIdentUse: {
11764 SpeculateCellOperand property(this, propertyEdge);
11765 GPRTemporary ident(this);
11766
11767 GPRReg propertyGPR = property.gpr();
11768 GPRReg identGPR = ident.gpr();
11769
11770 speculateString(propertyEdge, propertyGPR);
11771 speculateStringIdentAndLoadStorage(propertyEdge, propertyGPR, identGPR);
11772
11773 useChildren(node);
11774
11775 flushRegisters();
11776 callOperation(operationDefineAccessorPropertyStringIdent, NoResult, baseGPR, identGPR, getterGPR, setterGPR, attributesGPR);
11777 m_jit.exceptionCheck();
11778 break;
11779 }
11780 case SymbolUse: {
11781 SpeculateCellOperand property(this, propertyEdge);
11782 GPRReg propertyGPR = property.gpr();
11783 speculateSymbol(propertyEdge, propertyGPR);
11784
11785 useChildren(node);
11786
11787 flushRegisters();
11788 callOperation(operationDefineAccessorPropertySymbol, NoResult, baseGPR, propertyGPR, getterGPR, setterGPR, attributesGPR);
11789 m_jit.exceptionCheck();
11790 break;
11791 }
11792 case UntypedUse: {
11793 JSValueOperand property(this, propertyEdge);
11794 JSValueRegs propertyRegs = property.jsValueRegs();
11795
11796 useChildren(node);
11797
11798 flushRegisters();
11799 callOperation(operationDefineAccessorProperty, NoResult, baseGPR, propertyRegs, getterGPR, setterGPR, attributesGPR);
11800 m_jit.exceptionCheck();
11801 break;
11802 }
11803 default:
11804 RELEASE_ASSERT_NOT_REACHED();
11805 }
11806
11807 noResult(node, UseChildrenCalledExplicitly);
11808}
11809
11810void SpeculativeJIT::emitAllocateButterfly(GPRReg storageResultGPR, GPRReg sizeGPR, GPRReg scratch1, GPRReg scratch2, GPRReg scratch3, MacroAssembler::JumpList& slowCases)
11811{
11812 RELEASE_ASSERT(RegisterSet(storageResultGPR, sizeGPR, scratch1, scratch2, scratch3).numberOfSetGPRs() == 5);
11813 ASSERT((1 << 3) == sizeof(JSValue));
11814 m_jit.zeroExtend32ToPtr(sizeGPR, scratch1);
11815 m_jit.lshift32(TrustedImm32(3), scratch1);
11816 m_jit.add32(TrustedImm32(sizeof(IndexingHeader)), scratch1, scratch2);
11817#if !ASSERT_DISABLED
11818 MacroAssembler::Jump didNotOverflow = m_jit.branch32(MacroAssembler::AboveOrEqual, scratch2, sizeGPR);
11819 m_jit.abortWithReason(UncheckedOverflow);
11820 didNotOverflow.link(&m_jit);
11821#endif
11822 m_jit.emitAllocateVariableSized(
11823 storageResultGPR, m_jit.vm()->jsValueGigacageAuxiliarySpace, scratch2, scratch1, scratch3, slowCases);
11824 m_jit.addPtr(TrustedImm32(sizeof(IndexingHeader)), storageResultGPR);
11825
11826 m_jit.store32(sizeGPR, MacroAssembler::Address(storageResultGPR, Butterfly::offsetOfPublicLength()));
11827 m_jit.store32(sizeGPR, MacroAssembler::Address(storageResultGPR, Butterfly::offsetOfVectorLength()));
11828}
11829
11830void SpeculativeJIT::compileNormalizeMapKey(Node* node)
11831{
11832 ASSERT(node->child1().useKind() == UntypedUse);
11833 JSValueOperand key(this, node->child1());
11834 JSValueRegsTemporary result(this, Reuse, key);
11835 GPRTemporary scratch(this);
11836 FPRTemporary doubleValue(this);
11837 FPRTemporary temp(this);
11838
11839 JSValueRegs keyRegs = key.jsValueRegs();
11840 JSValueRegs resultRegs = result.regs();
11841 GPRReg scratchGPR = scratch.gpr();
11842 FPRReg doubleValueFPR = doubleValue.fpr();
11843 FPRReg tempFPR = temp.fpr();
11844
11845 CCallHelpers::JumpList passThroughCases;
11846 CCallHelpers::JumpList doneCases;
11847
11848 passThroughCases.append(m_jit.branchIfNotNumber(keyRegs, scratchGPR));
11849 passThroughCases.append(m_jit.branchIfInt32(keyRegs));
11850
11851#if USE(JSVALUE64)
11852 m_jit.unboxDoubleWithoutAssertions(keyRegs.gpr(), scratchGPR, doubleValueFPR);
11853#else
11854 unboxDouble(keyRegs.tagGPR(), keyRegs.payloadGPR(), doubleValueFPR, tempFPR);
11855#endif
11856 auto notNaN = m_jit.branchIfNotNaN(doubleValueFPR);
11857 m_jit.moveTrustedValue(jsNaN(), resultRegs);
11858 doneCases.append(m_jit.jump());
11859
11860 notNaN.link(&m_jit);
11861 m_jit.truncateDoubleToInt32(doubleValueFPR, scratchGPR);
11862 m_jit.convertInt32ToDouble(scratchGPR, tempFPR);
11863 passThroughCases.append(m_jit.branchDouble(JITCompiler::DoubleNotEqual, doubleValueFPR, tempFPR));
11864
11865 m_jit.boxInt32(scratchGPR, resultRegs);
11866 doneCases.append(m_jit.jump());
11867
11868 passThroughCases.link(&m_jit);
11869 m_jit.moveValueRegs(keyRegs, resultRegs);
11870
11871 doneCases.link(&m_jit);
11872 jsValueResult(resultRegs, node);
11873}
11874
11875void SpeculativeJIT::compileGetMapBucketHead(Node* node)
11876{
11877 SpeculateCellOperand map(this, node->child1());
11878 GPRTemporary bucket(this);
11879
11880 GPRReg mapGPR = map.gpr();
11881 GPRReg bucketGPR = bucket.gpr();
11882
11883 if (node->child1().useKind() == MapObjectUse)
11884 speculateMapObject(node->child1(), mapGPR);
11885 else if (node->child1().useKind() == SetObjectUse)
11886 speculateSetObject(node->child1(), mapGPR);
11887 else
11888 RELEASE_ASSERT_NOT_REACHED();
11889
11890 ASSERT(HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfHead() == HashMapImpl<HashMapBucket<HashMapBucketDataKeyValue>>::offsetOfHead());
11891 m_jit.loadPtr(MacroAssembler::Address(mapGPR, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfHead()), bucketGPR);
11892 cellResult(bucketGPR, node);
11893}
11894
11895void SpeculativeJIT::compileGetMapBucketNext(Node* node)
11896{
11897 SpeculateCellOperand bucket(this, node->child1());
11898 GPRTemporary result(this);
11899
11900 GPRReg bucketGPR = bucket.gpr();
11901 GPRReg resultGPR = result.gpr();
11902
11903 ASSERT(HashMapBucket<HashMapBucketDataKey>::offsetOfNext() == HashMapBucket<HashMapBucketDataKeyValue>::offsetOfNext());
11904 ASSERT(HashMapBucket<HashMapBucketDataKey>::offsetOfKey() == HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey());
11905 m_jit.loadPtr(MacroAssembler::Address(bucketGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfNext()), resultGPR);
11906
11907 MacroAssembler::Label loop = m_jit.label();
11908 auto notBucket = m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR);
11909#if USE(JSVALUE32_64)
11910 auto done = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::Address(resultGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey() + TagOffset), TrustedImm32(JSValue::EmptyValueTag));
11911#else
11912 auto done = m_jit.branchTest64(MacroAssembler::NonZero, MacroAssembler::Address(resultGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey()));
11913#endif
11914 m_jit.loadPtr(MacroAssembler::Address(resultGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfNext()), resultGPR);
11915 m_jit.jump().linkTo(loop, &m_jit);
11916
11917 notBucket.link(&m_jit);
11918 JSCell* sentinel = nullptr;
11919 if (node->bucketOwnerType() == BucketOwnerType::Map)
11920 sentinel = m_jit.vm()->sentinelMapBucket();
11921 else {
11922 ASSERT(node->bucketOwnerType() == BucketOwnerType::Set);
11923 sentinel = m_jit.vm()->sentinelSetBucket();
11924 }
11925 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), sentinel), resultGPR);
11926 done.link(&m_jit);
11927
11928 cellResult(resultGPR, node);
11929}
11930
11931void SpeculativeJIT::compileLoadKeyFromMapBucket(Node* node)
11932{
11933 SpeculateCellOperand bucket(this, node->child1());
11934 JSValueRegsTemporary result(this);
11935
11936 GPRReg bucketGPR = bucket.gpr();
11937 JSValueRegs resultRegs = result.regs();
11938
11939 m_jit.loadValue(MacroAssembler::Address(bucketGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey()), resultRegs);
11940 jsValueResult(resultRegs, node);
11941}
11942
11943void SpeculativeJIT::compileLoadValueFromMapBucket(Node* node)
11944{
11945 SpeculateCellOperand bucket(this, node->child1());
11946 JSValueRegsTemporary result(this);
11947
11948 GPRReg bucketGPR = bucket.gpr();
11949 JSValueRegs resultRegs = result.regs();
11950
11951 m_jit.loadValue(MacroAssembler::Address(bucketGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfValue()), resultRegs);
11952 jsValueResult(resultRegs, node);
11953}
11954
11955void SpeculativeJIT::compileExtractValueFromWeakMapGet(Node* node)
11956{
11957 JSValueOperand value(this, node->child1());
11958 JSValueRegsTemporary result(this, Reuse, value);
11959
11960 JSValueRegs valueRegs = value.jsValueRegs();
11961 JSValueRegs resultRegs = result.regs();
11962
11963#if USE(JSVALUE64)
11964 m_jit.moveValueRegs(valueRegs, resultRegs);
11965 auto done = m_jit.branchTestPtr(CCallHelpers::NonZero, resultRegs.payloadGPR());
11966 m_jit.moveValue(jsUndefined(), resultRegs);
11967 done.link(&m_jit);
11968#else
11969 auto isEmpty = m_jit.branchIfEmpty(valueRegs.tagGPR());
11970 m_jit.moveValueRegs(valueRegs, resultRegs);
11971 auto done = m_jit.jump();
11972
11973 isEmpty.link(&m_jit);
11974 m_jit.moveValue(jsUndefined(), resultRegs);
11975
11976 done.link(&m_jit);
11977#endif
11978
11979 jsValueResult(resultRegs, node, DataFormatJS);
11980}
11981
11982void SpeculativeJIT::compileThrow(Node* node)
11983{
11984 JSValueOperand value(this, node->child1());
11985 JSValueRegs valueRegs = value.jsValueRegs();
11986 flushRegisters();
11987 callOperation(operationThrowDFG, valueRegs);
11988 m_jit.exceptionCheck();
11989 m_jit.breakpoint();
11990 noResult(node);
11991}
11992
11993void SpeculativeJIT::compileThrowStaticError(Node* node)
11994{
11995 SpeculateCellOperand message(this, node->child1());
11996 GPRReg messageGPR = message.gpr();
11997 speculateString(node->child1(), messageGPR);
11998 flushRegisters();
11999 callOperation(operationThrowStaticError, messageGPR, node->errorType());
12000 m_jit.exceptionCheck();
12001 m_jit.breakpoint();
12002 noResult(node);
12003}
12004
12005void SpeculativeJIT::compileGetEnumerableLength(Node* node)
12006{
12007 SpeculateCellOperand enumerator(this, node->child1());
12008 GPRFlushedCallResult result(this);
12009 GPRReg resultGPR = result.gpr();
12010
12011 m_jit.load32(MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::indexedLengthOffset()), resultGPR);
12012 int32Result(resultGPR, node);
12013}
12014
12015void SpeculativeJIT::compileHasGenericProperty(Node* node)
12016{
12017 JSValueOperand base(this, node->child1());
12018 SpeculateCellOperand property(this, node->child2());
12019
12020 JSValueRegs baseRegs = base.jsValueRegs();
12021 GPRReg propertyGPR = property.gpr();
12022
12023 flushRegisters();
12024 JSValueRegsFlushedCallResult result(this);
12025 JSValueRegs resultRegs = result.regs();
12026 callOperation(operationHasGenericProperty, resultRegs, baseRegs, propertyGPR);
12027 m_jit.exceptionCheck();
12028 blessedBooleanResult(resultRegs.payloadGPR(), node);
12029}
12030
12031void SpeculativeJIT::compileToIndexString(Node* node)
12032{
12033 SpeculateInt32Operand index(this, node->child1());
12034 GPRReg indexGPR = index.gpr();
12035
12036 flushRegisters();
12037 GPRFlushedCallResult result(this);
12038 GPRReg resultGPR = result.gpr();
12039 callOperation(operationToIndexString, resultGPR, indexGPR);
12040 m_jit.exceptionCheck();
12041 cellResult(resultGPR, node);
12042}
12043
12044void SpeculativeJIT::compilePutByIdFlush(Node* node)
12045{
12046 SpeculateCellOperand base(this, node->child1());
12047 JSValueOperand value(this, node->child2());
12048 GPRTemporary scratch(this);
12049
12050 GPRReg baseGPR = base.gpr();
12051 JSValueRegs valueRegs = value.jsValueRegs();
12052 GPRReg scratchGPR = scratch.gpr();
12053 flushRegisters();
12054
12055 cachedPutById(node->origin.semantic, baseGPR, valueRegs, scratchGPR, node->identifierNumber(), NotDirect, MacroAssembler::Jump(), DontSpill);
12056
12057 noResult(node);
12058}
12059
12060void SpeculativeJIT::compilePutById(Node* node)
12061{
12062 SpeculateCellOperand base(this, node->child1());
12063 JSValueOperand value(this, node->child2());
12064 GPRTemporary scratch(this);
12065
12066 GPRReg baseGPR = base.gpr();
12067 JSValueRegs valueRegs = value.jsValueRegs();
12068 GPRReg scratchGPR = scratch.gpr();
12069
12070 cachedPutById(node->origin.semantic, baseGPR, valueRegs, scratchGPR, node->identifierNumber(), NotDirect);
12071
12072 noResult(node);
12073}
12074
12075void SpeculativeJIT::compilePutByIdDirect(Node* node)
12076{
12077 SpeculateCellOperand base(this, node->child1());
12078 JSValueOperand value(this, node->child2());
12079 GPRTemporary scratch(this);
12080
12081 GPRReg baseGPR = base.gpr();
12082 JSValueRegs valueRegs = value.jsValueRegs();
12083 GPRReg scratchGPR = scratch.gpr();
12084
12085 cachedPutById(node->origin.semantic, baseGPR, valueRegs, scratchGPR, node->identifierNumber(), Direct);
12086
12087 noResult(node);
12088}
12089
12090void SpeculativeJIT::compilePutByIdWithThis(Node* node)
12091{
12092 JSValueOperand base(this, node->child1());
12093 JSValueRegs baseRegs = base.jsValueRegs();
12094 JSValueOperand thisValue(this, node->child2());
12095 JSValueRegs thisRegs = thisValue.jsValueRegs();
12096 JSValueOperand value(this, node->child3());
12097 JSValueRegs valueRegs = value.jsValueRegs();
12098
12099 flushRegisters();
12100 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByIdWithThisStrict : operationPutByIdWithThis,
12101 NoResult, baseRegs, thisRegs, valueRegs, identifierUID(node->identifierNumber()));
12102 m_jit.exceptionCheck();
12103
12104 noResult(node);
12105}
12106
12107void SpeculativeJIT::compileGetByOffset(Node* node)
12108{
12109 StorageOperand storage(this, node->child1());
12110 JSValueRegsTemporary result(this, Reuse, storage);
12111
12112 GPRReg storageGPR = storage.gpr();
12113 JSValueRegs resultRegs = result.regs();
12114
12115 StorageAccessData& storageAccessData = node->storageAccessData();
12116
12117 m_jit.loadValue(JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset)), resultRegs);
12118
12119 jsValueResult(resultRegs, node);
12120}
12121
12122void SpeculativeJIT::compilePutByOffset(Node* node)
12123{
12124 StorageOperand storage(this, node->child1());
12125 JSValueOperand value(this, node->child3());
12126
12127 GPRReg storageGPR = storage.gpr();
12128 JSValueRegs valueRegs = value.jsValueRegs();
12129
12130 speculate(node, node->child2());
12131
12132 StorageAccessData& storageAccessData = node->storageAccessData();
12133
12134 m_jit.storeValue(valueRegs, JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset)));
12135
12136 noResult(node);
12137}
12138
12139void SpeculativeJIT::compileMatchStructure(Node* node)
12140{
12141 SpeculateCellOperand base(this, node->child1());
12142 GPRTemporary temp(this);
12143 GPRReg baseGPR = base.gpr();
12144 GPRReg tempGPR = temp.gpr();
12145
12146 m_jit.load32(JITCompiler::Address(baseGPR, JSCell::structureIDOffset()), tempGPR);
12147
12148 auto& variants = node->matchStructureData().variants;
12149 Vector<int64_t> cases;
12150 for (MatchStructureVariant& variant : variants)
12151 cases.append(bitwise_cast<int32_t>(variant.structure->id()));
12152
12153 BinarySwitch binarySwitch(tempGPR, cases, BinarySwitch::Int32);
12154 JITCompiler::JumpList done;
12155 while (binarySwitch.advance(m_jit)) {
12156 m_jit.boxBooleanPayload(variants[binarySwitch.caseIndex()].result, tempGPR);
12157 done.append(m_jit.jump());
12158 }
12159 speculationCheck(BadCache, JSValueRegs(), node, binarySwitch.fallThrough());
12160
12161 done.link(&m_jit);
12162
12163 blessedBooleanResult(tempGPR, node);
12164}
12165
12166void SpeculativeJIT::compileHasStructureProperty(Node* node)
12167{
12168 JSValueOperand base(this, node->child1());
12169 SpeculateCellOperand property(this, node->child2());
12170 SpeculateCellOperand enumerator(this, node->child3());
12171 JSValueRegsTemporary result(this);
12172
12173 JSValueRegs baseRegs = base.jsValueRegs();
12174 GPRReg propertyGPR = property.gpr();
12175 JSValueRegs resultRegs = result.regs();
12176
12177 CCallHelpers::JumpList wrongStructure;
12178
12179 wrongStructure.append(m_jit.branchIfNotCell(baseRegs));
12180
12181 m_jit.load32(MacroAssembler::Address(baseRegs.payloadGPR(), JSCell::structureIDOffset()), resultRegs.payloadGPR());
12182 wrongStructure.append(m_jit.branch32(MacroAssembler::NotEqual,
12183 resultRegs.payloadGPR(),
12184 MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::cachedStructureIDOffset())));
12185
12186 moveTrueTo(resultRegs.payloadGPR());
12187 MacroAssembler::Jump done = m_jit.jump();
12188
12189 done.link(&m_jit);
12190
12191 addSlowPathGenerator(slowPathCall(wrongStructure, this, operationHasGenericProperty, resultRegs, baseRegs, propertyGPR));
12192 blessedBooleanResult(resultRegs.payloadGPR(), node);
12193}
12194
12195void SpeculativeJIT::compileGetPropertyEnumerator(Node* node)
12196{
12197 if (node->child1().useKind() == CellUse) {
12198 SpeculateCellOperand base(this, node->child1());
12199 GPRReg baseGPR = base.gpr();
12200
12201 flushRegisters();
12202 GPRFlushedCallResult result(this);
12203 GPRReg resultGPR = result.gpr();
12204 callOperation(operationGetPropertyEnumeratorCell, resultGPR, baseGPR);
12205 m_jit.exceptionCheck();
12206 cellResult(resultGPR, node);
12207 return;
12208 }
12209
12210 JSValueOperand base(this, node->child1());
12211 JSValueRegs baseRegs = base.jsValueRegs();
12212
12213 flushRegisters();
12214 GPRFlushedCallResult result(this);
12215 GPRReg resultGPR = result.gpr();
12216 callOperation(operationGetPropertyEnumerator, resultGPR, baseRegs);
12217 m_jit.exceptionCheck();
12218 cellResult(resultGPR, node);
12219}
12220
12221void SpeculativeJIT::compileGetEnumeratorPname(Node* node)
12222{
12223 ASSERT(node->op() == GetEnumeratorStructurePname || node->op() == GetEnumeratorGenericPname);
12224 SpeculateCellOperand enumerator(this, node->child1());
12225 SpeculateStrictInt32Operand index(this, node->child2());
12226 GPRTemporary scratch(this);
12227 JSValueRegsTemporary result(this);
12228
12229 GPRReg enumeratorGPR = enumerator.gpr();
12230 GPRReg indexGPR = index.gpr();
12231 GPRReg scratchGPR = scratch.gpr();
12232 JSValueRegs resultRegs = result.regs();
12233
12234 MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, indexGPR,
12235 MacroAssembler::Address(enumeratorGPR, (node->op() == GetEnumeratorStructurePname)
12236 ? JSPropertyNameEnumerator::endStructurePropertyIndexOffset()
12237 : JSPropertyNameEnumerator::endGenericPropertyIndexOffset()));
12238
12239 m_jit.moveValue(jsNull(), resultRegs);
12240
12241 MacroAssembler::Jump done = m_jit.jump();
12242 inBounds.link(&m_jit);
12243
12244 m_jit.loadPtr(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), scratchGPR);
12245 m_jit.loadPtr(MacroAssembler::BaseIndex(scratchGPR, indexGPR, MacroAssembler::ScalePtr), resultRegs.payloadGPR());
12246#if USE(JSVALUE32_64)
12247 m_jit.move(MacroAssembler::TrustedImm32(JSValue::CellTag), resultRegs.tagGPR());
12248#endif
12249
12250 done.link(&m_jit);
12251 jsValueResult(resultRegs, node);
12252}
12253
12254void SpeculativeJIT::compileGetExecutable(Node* node)
12255{
12256 SpeculateCellOperand function(this, node->child1());
12257 GPRTemporary result(this, Reuse, function);
12258 GPRReg functionGPR = function.gpr();
12259 GPRReg resultGPR = result.gpr();
12260 speculateCellType(node->child1(), functionGPR, SpecFunction, JSFunctionType);
12261 m_jit.loadPtr(JITCompiler::Address(functionGPR, JSFunction::offsetOfExecutable()), resultGPR);
12262 cellResult(resultGPR, node);
12263}
12264
12265void SpeculativeJIT::compileGetGetter(Node* node)
12266{
12267 SpeculateCellOperand op1(this, node->child1());
12268 GPRTemporary result(this, Reuse, op1);
12269
12270 GPRReg op1GPR = op1.gpr();
12271 GPRReg resultGPR = result.gpr();
12272
12273 m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfGetter()), resultGPR);
12274
12275 cellResult(resultGPR, node);
12276}
12277
12278void SpeculativeJIT::compileGetSetter(Node* node)
12279{
12280 SpeculateCellOperand op1(this, node->child1());
12281 GPRTemporary result(this, Reuse, op1);
12282
12283 GPRReg op1GPR = op1.gpr();
12284 GPRReg resultGPR = result.gpr();
12285
12286 m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfSetter()), resultGPR);
12287
12288 cellResult(resultGPR, node);
12289}
12290
12291void SpeculativeJIT::compileGetCallee(Node* node)
12292{
12293 GPRTemporary result(this);
12294 m_jit.loadPtr(JITCompiler::payloadFor(CallFrameSlot::callee), result.gpr());
12295 cellResult(result.gpr(), node);
12296}
12297
12298void SpeculativeJIT::compileSetCallee(Node* node)
12299{
12300 SpeculateCellOperand callee(this, node->child1());
12301 m_jit.storeCell(callee.gpr(), JITCompiler::payloadFor(CallFrameSlot::callee));
12302 noResult(node);
12303}
12304
12305void SpeculativeJIT::compileGetArgumentCountIncludingThis(Node* node)
12306{
12307 GPRTemporary result(this);
12308 VirtualRegister argumentCountRegister;
12309 if (InlineCallFrame* inlineCallFrame = node->argumentsInlineCallFrame())
12310 argumentCountRegister = inlineCallFrame->argumentCountRegister;
12311 else
12312 argumentCountRegister = VirtualRegister(CallFrameSlot::argumentCount);
12313 m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), result.gpr());
12314 int32Result(result.gpr(), node);
12315}
12316
12317void SpeculativeJIT::compileSetArgumentCountIncludingThis(Node* node)
12318{
12319 m_jit.store32(TrustedImm32(node->argumentCountIncludingThis()), JITCompiler::payloadFor(CallFrameSlot::argumentCount));
12320 noResult(node);
12321}
12322
12323void SpeculativeJIT::compileStrCat(Node* node)
12324{
12325 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
12326 JSValueOperand op2(this, node->child2(), ManualOperandSpeculation);
12327 JSValueOperand op3(this, node->child3(), ManualOperandSpeculation);
12328
12329 JSValueRegs op1Regs = op1.jsValueRegs();
12330 JSValueRegs op2Regs = op2.jsValueRegs();
12331 JSValueRegs op3Regs;
12332
12333 if (node->child3())
12334 op3Regs = op3.jsValueRegs();
12335
12336 flushRegisters();
12337
12338 GPRFlushedCallResult result(this);
12339 if (node->child3())
12340 callOperation(operationStrCat3, result.gpr(), op1Regs, op2Regs, op3Regs);
12341 else
12342 callOperation(operationStrCat2, result.gpr(), op1Regs, op2Regs);
12343 m_jit.exceptionCheck();
12344
12345 cellResult(result.gpr(), node);
12346}
12347
12348void SpeculativeJIT::compileNewArrayBuffer(Node* node)
12349{
12350 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
12351 auto* array = node->castOperand<JSImmutableButterfly*>();
12352
12353 IndexingType indexingMode = node->indexingMode();
12354 RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingMode));
12355
12356 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(indexingMode)) {
12357 GPRTemporary result(this);
12358 GPRTemporary scratch1(this);
12359 GPRTemporary scratch2(this);
12360
12361 GPRReg resultGPR = result.gpr();
12362 GPRReg scratch1GPR = scratch1.gpr();
12363 GPRReg scratch2GPR = scratch2.gpr();
12364
12365 MacroAssembler::JumpList slowCases;
12366
12367 emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), TrustedImmPtr(array->toButterfly()), scratch1GPR, scratch2GPR, slowCases);
12368
12369 addSlowPathGenerator(slowPathCall(slowCases, this, operationNewArrayBuffer, result.gpr(), structure, array));
12370
12371 DFG_ASSERT(m_jit.graph(), node, indexingMode & IsArray, indexingMode);
12372 cellResult(resultGPR, node);
12373 return;
12374 }
12375
12376 flushRegisters();
12377 GPRFlushedCallResult result(this);
12378
12379 callOperation(operationNewArrayBuffer, result.gpr(), structure, TrustedImmPtr(node->cellOperand()));
12380 m_jit.exceptionCheck();
12381
12382 cellResult(result.gpr(), node);
12383}
12384
12385void SpeculativeJIT::compileNewArrayWithSize(Node* node)
12386{
12387 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
12388 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(node->indexingType())) {
12389 SpeculateStrictInt32Operand size(this, node->child1());
12390 GPRTemporary result(this);
12391
12392 GPRReg sizeGPR = size.gpr();
12393 GPRReg resultGPR = result.gpr();
12394
12395 compileAllocateNewArrayWithSize(globalObject, resultGPR, sizeGPR, node->indexingType());
12396 cellResult(resultGPR, node);
12397 return;
12398 }
12399
12400 SpeculateStrictInt32Operand size(this, node->child1());
12401 GPRReg sizeGPR = size.gpr();
12402 flushRegisters();
12403 GPRFlushedCallResult result(this);
12404 GPRReg resultGPR = result.gpr();
12405 GPRReg structureGPR = AssemblyHelpers::selectScratchGPR(sizeGPR);
12406 MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH));
12407 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()))), structureGPR);
12408 MacroAssembler::Jump done = m_jit.jump();
12409 bigLength.link(&m_jit);
12410 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage))), structureGPR);
12411 done.link(&m_jit);
12412 callOperation(operationNewArrayWithSize, resultGPR, structureGPR, sizeGPR, nullptr);
12413 m_jit.exceptionCheck();
12414 cellResult(resultGPR, node);
12415}
12416
12417void SpeculativeJIT::compileNewTypedArray(Node* node)
12418{
12419 switch (node->child1().useKind()) {
12420 case Int32Use:
12421 compileNewTypedArrayWithSize(node);
12422 break;
12423 case UntypedUse: {
12424 JSValueOperand argument(this, node->child1());
12425 JSValueRegs argumentRegs = argument.jsValueRegs();
12426
12427 flushRegisters();
12428
12429 GPRFlushedCallResult result(this);
12430 GPRReg resultGPR = result.gpr();
12431
12432 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
12433 callOperation(
12434 operationNewTypedArrayWithOneArgumentForType(node->typedArrayType()),
12435 resultGPR, m_jit.graph().registerStructure(globalObject->typedArrayStructureConcurrently(node->typedArrayType())), argumentRegs);
12436 m_jit.exceptionCheck();
12437
12438 cellResult(resultGPR, node);
12439 break;
12440 }
12441 default:
12442 RELEASE_ASSERT_NOT_REACHED();
12443 break;
12444 }
12445}
12446
12447void SpeculativeJIT::compileToThis(Node* node)
12448{
12449 ASSERT(node->child1().useKind() == UntypedUse);
12450 JSValueOperand thisValue(this, node->child1());
12451 JSValueRegsTemporary temp(this);
12452
12453 JSValueRegs thisValueRegs = thisValue.jsValueRegs();
12454 JSValueRegs tempRegs = temp.regs();
12455
12456 MacroAssembler::JumpList slowCases;
12457 slowCases.append(m_jit.branchIfNotCell(thisValueRegs));
12458 slowCases.append(
12459 m_jit.branchTest8(
12460 MacroAssembler::NonZero,
12461 MacroAssembler::Address(thisValueRegs.payloadGPR(), JSCell::typeInfoFlagsOffset()),
12462 MacroAssembler::TrustedImm32(OverridesToThis)));
12463 m_jit.moveValueRegs(thisValueRegs, tempRegs);
12464
12465 J_JITOperation_EJ function;
12466 if (m_jit.isStrictModeFor(node->origin.semantic))
12467 function = operationToThisStrict;
12468 else
12469 function = operationToThis;
12470 addSlowPathGenerator(slowPathCall(slowCases, this, function, tempRegs, thisValueRegs));
12471
12472 jsValueResult(tempRegs, node);
12473}
12474
12475void SpeculativeJIT::compileObjectKeys(Node* node)
12476{
12477 switch (node->child1().useKind()) {
12478 case ObjectUse: {
12479 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
12480 SpeculateCellOperand object(this, node->child1());
12481 GPRTemporary structure(this);
12482 GPRTemporary scratch(this);
12483 GPRTemporary scratch2(this);
12484 GPRTemporary scratch3(this);
12485 GPRTemporary result(this);
12486
12487 GPRReg objectGPR = object.gpr();
12488 GPRReg structureGPR = structure.gpr();
12489 GPRReg scratchGPR = scratch.gpr();
12490 GPRReg scratch2GPR = scratch2.gpr();
12491 GPRReg scratch3GPR = scratch3.gpr();
12492 GPRReg resultGPR = result.gpr();
12493
12494 speculateObject(node->child1(), objectGPR);
12495
12496 CCallHelpers::JumpList slowCases;
12497 m_jit.emitLoadStructure(*m_jit.vm(), objectGPR, structureGPR, scratchGPR);
12498 m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::previousOrRareDataOffset()), scratchGPR);
12499
12500 slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR));
12501 slowCases.append(m_jit.branch32(CCallHelpers::Equal, CCallHelpers::Address(scratchGPR, JSCell::structureIDOffset()), TrustedImm32(bitwise_cast<int32_t>(m_jit.vm()->structureStructure->structureID()))));
12502
12503 m_jit.loadPtr(CCallHelpers::Address(scratchGPR, StructureRareData::offsetOfCachedOwnKeys()), scratchGPR);
12504
12505 ASSERT(bitwise_cast<uintptr_t>(StructureRareData::cachedOwnKeysSentinel()) == 1);
12506 slowCases.append(m_jit.branchPtr(CCallHelpers::BelowOrEqual, scratchGPR, TrustedImmPtr(bitwise_cast<void*>(StructureRareData::cachedOwnKeysSentinel()))));
12507
12508 MacroAssembler::JumpList slowButArrayBufferCases;
12509
12510 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
12511 RegisteredStructure arrayStructure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous));
12512
12513 m_jit.move(scratchGPR, scratch3GPR);
12514 m_jit.addPtr(TrustedImmPtr(JSImmutableButterfly::offsetOfData()), scratchGPR);
12515
12516 emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(arrayStructure), scratchGPR, structureGPR, scratch2GPR, slowButArrayBufferCases);
12517
12518 addSlowPathGenerator(slowPathCall(slowButArrayBufferCases, this, operationNewArrayBuffer, resultGPR, arrayStructure, scratch3GPR));
12519
12520 addSlowPathGenerator(slowPathCall(slowCases, this, operationObjectKeysObject, resultGPR, objectGPR));
12521
12522 cellResult(resultGPR, node);
12523 break;
12524 }
12525
12526 SpeculateCellOperand object(this, node->child1());
12527
12528 GPRReg objectGPR = object.gpr();
12529
12530 speculateObject(node->child1(), objectGPR);
12531
12532 flushRegisters();
12533 GPRFlushedCallResult result(this);
12534 GPRReg resultGPR = result.gpr();
12535 callOperation(operationObjectKeysObject, resultGPR, objectGPR);
12536 m_jit.exceptionCheck();
12537
12538 cellResult(resultGPR, node);
12539 break;
12540 }
12541
12542 case UntypedUse: {
12543 JSValueOperand object(this, node->child1());
12544
12545 JSValueRegs objectRegs = object.jsValueRegs();
12546
12547 flushRegisters();
12548 GPRFlushedCallResult result(this);
12549 GPRReg resultGPR = result.gpr();
12550 callOperation(operationObjectKeys, resultGPR, objectRegs);
12551 m_jit.exceptionCheck();
12552
12553 cellResult(resultGPR, node);
12554 break;
12555 }
12556
12557 default:
12558 RELEASE_ASSERT_NOT_REACHED();
12559 break;
12560 }
12561}
12562
12563void SpeculativeJIT::compileObjectCreate(Node* node)
12564{
12565 switch (node->child1().useKind()) {
12566 case ObjectUse: {
12567 SpeculateCellOperand prototype(this, node->child1());
12568
12569 GPRReg prototypeGPR = prototype.gpr();
12570
12571 speculateObject(node->child1(), prototypeGPR);
12572
12573 flushRegisters();
12574 GPRFlushedCallResult result(this);
12575 GPRReg resultGPR = result.gpr();
12576 callOperation(operationObjectCreateObject, resultGPR, prototypeGPR);
12577 m_jit.exceptionCheck();
12578
12579 cellResult(resultGPR, node);
12580 break;
12581 }
12582
12583 case UntypedUse: {
12584 JSValueOperand prototype(this, node->child1());
12585
12586 JSValueRegs prototypeRegs = prototype.jsValueRegs();
12587
12588 flushRegisters();
12589 GPRFlushedCallResult result(this);
12590 GPRReg resultGPR = result.gpr();
12591 callOperation(operationObjectCreate, resultGPR, prototypeRegs);
12592 m_jit.exceptionCheck();
12593
12594 cellResult(resultGPR, node);
12595 break;
12596 }
12597
12598 default:
12599 RELEASE_ASSERT_NOT_REACHED();
12600 break;
12601 }
12602}
12603
12604void SpeculativeJIT::compileCreateThis(Node* node)
12605{
12606 // Note that there is not so much profit to speculate here. The only things we
12607 // speculate on are (1) that it's a cell, since that eliminates cell checks
12608 // later if the proto is reused, and (2) if we have a FinalObject prediction
12609 // then we speculate because we want to get recompiled if it isn't (since
12610 // otherwise we'd start taking slow path a lot).
12611
12612 SpeculateCellOperand callee(this, node->child1());
12613 GPRTemporary result(this);
12614 GPRTemporary allocator(this);
12615 GPRTemporary structure(this);
12616 GPRTemporary scratch(this);
12617
12618 GPRReg calleeGPR = callee.gpr();
12619 GPRReg resultGPR = result.gpr();
12620 GPRReg allocatorGPR = allocator.gpr();
12621 GPRReg structureGPR = structure.gpr();
12622 GPRReg scratchGPR = scratch.gpr();
12623 // Rare data is only used to access the allocator & structure
12624 // We can avoid using an additional GPR this way
12625 GPRReg rareDataGPR = structureGPR;
12626 GPRReg inlineCapacityGPR = rareDataGPR;
12627
12628 MacroAssembler::JumpList slowPath;
12629
12630 slowPath.append(m_jit.branchIfNotFunction(calleeGPR));
12631 m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfRareData()), rareDataGPR);
12632 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, rareDataGPR));
12633 m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfileWithPrototype::offsetOfAllocator()), allocatorGPR);
12634 m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfileWithPrototype::offsetOfStructure()), structureGPR);
12635
12636 auto butterfly = TrustedImmPtr(nullptr);
12637 emitAllocateJSObject(resultGPR, JITAllocator::variable(), allocatorGPR, structureGPR, butterfly, scratchGPR, slowPath);
12638
12639 m_jit.load8(JITCompiler::Address(structureGPR, Structure::inlineCapacityOffset()), inlineCapacityGPR);
12640 m_jit.emitInitializeInlineStorage(resultGPR, inlineCapacityGPR);
12641 m_jit.mutatorFence(*m_jit.vm());
12642
12643 addSlowPathGenerator(slowPathCall(slowPath, this, operationCreateThis, resultGPR, calleeGPR, node->inlineCapacity()));
12644
12645 cellResult(resultGPR, node);
12646}
12647
12648void SpeculativeJIT::compileNewObject(Node* node)
12649{
12650 GPRTemporary result(this);
12651 GPRTemporary allocator(this);
12652 GPRTemporary scratch(this);
12653
12654 GPRReg resultGPR = result.gpr();
12655 GPRReg allocatorGPR = allocator.gpr();
12656 GPRReg scratchGPR = scratch.gpr();
12657
12658 MacroAssembler::JumpList slowPath;
12659
12660 RegisteredStructure structure = node->structure();
12661 size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity());
12662 Allocator allocatorValue = allocatorForNonVirtualConcurrently<JSFinalObject>(*m_jit.vm(), allocationSize, AllocatorForMode::AllocatorIfExists);
12663 if (!allocatorValue)
12664 slowPath.append(m_jit.jump());
12665 else {
12666 auto butterfly = TrustedImmPtr(nullptr);
12667 emitAllocateJSObject(resultGPR, JITAllocator::constant(allocatorValue), allocatorGPR, TrustedImmPtr(structure), butterfly, scratchGPR, slowPath);
12668 m_jit.emitInitializeInlineStorage(resultGPR, structure->inlineCapacity());
12669 m_jit.mutatorFence(*m_jit.vm());
12670 }
12671
12672 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewObject, resultGPR, structure));
12673
12674 cellResult(resultGPR, node);
12675}
12676
12677void SpeculativeJIT::compileToPrimitive(Node* node)
12678{
12679 DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse, node->child1().useKind());
12680 JSValueOperand argument(this, node->child1());
12681 JSValueRegsTemporary result(this, Reuse, argument);
12682
12683 JSValueRegs argumentRegs = argument.jsValueRegs();
12684 JSValueRegs resultRegs = result.regs();
12685
12686 argument.use();
12687
12688 MacroAssembler::Jump alreadyPrimitive = m_jit.branchIfNotCell(argumentRegs);
12689 MacroAssembler::Jump notPrimitive = m_jit.branchIfObject(argumentRegs.payloadGPR());
12690
12691 alreadyPrimitive.link(&m_jit);
12692 m_jit.moveValueRegs(argumentRegs, resultRegs);
12693
12694 addSlowPathGenerator(slowPathCall(notPrimitive, this, operationToPrimitive, resultRegs, argumentRegs));
12695
12696 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
12697}
12698
12699void SpeculativeJIT::compileLogShadowChickenPrologue(Node* node)
12700{
12701 flushRegisters();
12702 prepareForExternalCall();
12703 m_jit.emitStoreCodeOrigin(node->origin.semantic);
12704
12705 GPRTemporary scratch1(this, GPRInfo::nonArgGPR0); // This must be a non-argument GPR.
12706 GPRReg scratch1Reg = scratch1.gpr();
12707 GPRTemporary scratch2(this);
12708 GPRReg scratch2Reg = scratch2.gpr();
12709 GPRTemporary shadowPacket(this);
12710 GPRReg shadowPacketReg = shadowPacket.gpr();
12711
12712 m_jit.ensureShadowChickenPacket(*m_jit.vm(), shadowPacketReg, scratch1Reg, scratch2Reg);
12713
12714 SpeculateCellOperand scope(this, node->child1());
12715 GPRReg scopeReg = scope.gpr();
12716
12717 m_jit.logShadowChickenProloguePacket(shadowPacketReg, scratch1Reg, scopeReg);
12718 noResult(node);
12719}
12720
12721void SpeculativeJIT::compileLogShadowChickenTail(Node* node)
12722{
12723 flushRegisters();
12724 prepareForExternalCall();
12725 CallSiteIndex callSiteIndex = m_jit.emitStoreCodeOrigin(node->origin.semantic);
12726
12727 GPRTemporary scratch1(this, GPRInfo::nonArgGPR0); // This must be a non-argument GPR.
12728 GPRReg scratch1Reg = scratch1.gpr();
12729 GPRTemporary scratch2(this);
12730 GPRReg scratch2Reg = scratch2.gpr();
12731 GPRTemporary shadowPacket(this);
12732 GPRReg shadowPacketReg = shadowPacket.gpr();
12733
12734 m_jit.ensureShadowChickenPacket(*m_jit.vm(), shadowPacketReg, scratch1Reg, scratch2Reg);
12735
12736 JSValueOperand thisValue(this, node->child1());
12737 JSValueRegs thisRegs = thisValue.jsValueRegs();
12738 SpeculateCellOperand scope(this, node->child2());
12739 GPRReg scopeReg = scope.gpr();
12740
12741 m_jit.logShadowChickenTailPacket(shadowPacketReg, thisRegs, scopeReg, m_jit.codeBlock(), callSiteIndex);
12742 noResult(node);
12743}
12744
12745void SpeculativeJIT::compileSetAdd(Node* node)
12746{
12747 SpeculateCellOperand set(this, node->child1());
12748 JSValueOperand key(this, node->child2());
12749 SpeculateInt32Operand hash(this, node->child3());
12750
12751 GPRReg setGPR = set.gpr();
12752 JSValueRegs keyRegs = key.jsValueRegs();
12753 GPRReg hashGPR = hash.gpr();
12754
12755 speculateSetObject(node->child1(), setGPR);
12756
12757 flushRegisters();
12758 GPRFlushedCallResult result(this);
12759 GPRReg resultGPR = result.gpr();
12760 callOperation(operationSetAdd, resultGPR, setGPR, keyRegs, hashGPR);
12761 m_jit.exceptionCheck();
12762 cellResult(resultGPR, node);
12763}
12764
12765void SpeculativeJIT::compileMapSet(Node* node)
12766{
12767 SpeculateCellOperand map(this, m_jit.graph().varArgChild(node, 0));
12768 JSValueOperand key(this, m_jit.graph().varArgChild(node, 1));
12769 JSValueOperand value(this, m_jit.graph().varArgChild(node, 2));
12770 SpeculateInt32Operand hash(this, m_jit.graph().varArgChild(node, 3));
12771
12772 GPRReg mapGPR = map.gpr();
12773 JSValueRegs keyRegs = key.jsValueRegs();
12774 JSValueRegs valueRegs = value.jsValueRegs();
12775 GPRReg hashGPR = hash.gpr();
12776
12777 speculateMapObject(m_jit.graph().varArgChild(node, 0), mapGPR);
12778
12779 flushRegisters();
12780 GPRFlushedCallResult result(this);
12781 GPRReg resultGPR = result.gpr();
12782 callOperation(operationMapSet, resultGPR, mapGPR, keyRegs, valueRegs, hashGPR);
12783 m_jit.exceptionCheck();
12784 cellResult(resultGPR, node);
12785}
12786
12787void SpeculativeJIT::compileWeakMapGet(Node* node)
12788{
12789 GPRTemporary mask(this);
12790 GPRTemporary buffer(this);
12791 JSValueRegsTemporary result(this);
12792
12793 GPRReg maskGPR = mask.gpr();
12794 GPRReg bufferGPR = buffer.gpr();
12795 JSValueRegs resultRegs = result.regs();
12796
12797 GPRTemporary index;
12798 GPRReg indexGPR { InvalidGPRReg };
12799 {
12800 SpeculateInt32Operand hash(this, node->child3());
12801 GPRReg hashGPR = hash.gpr();
12802 index = GPRTemporary(this, Reuse, hash);
12803 indexGPR = index.gpr();
12804 m_jit.move(hashGPR, indexGPR);
12805 }
12806
12807 {
12808 SpeculateCellOperand weakMap(this, node->child1());
12809 GPRReg weakMapGPR = weakMap.gpr();
12810 if (node->child1().useKind() == WeakMapObjectUse)
12811 speculateWeakMapObject(node->child1(), weakMapGPR);
12812 else
12813 speculateWeakSetObject(node->child1(), weakMapGPR);
12814
12815 ASSERT(WeakMapImpl<WeakMapBucket<WeakMapBucketDataKey>>::offsetOfCapacity() == WeakMapImpl<WeakMapBucket<WeakMapBucketDataKeyValue>>::offsetOfCapacity());
12816 ASSERT(WeakMapImpl<WeakMapBucket<WeakMapBucketDataKey>>::offsetOfBuffer() == WeakMapImpl<WeakMapBucket<WeakMapBucketDataKeyValue>>::offsetOfBuffer());
12817 m_jit.load32(MacroAssembler::Address(weakMapGPR, WeakMapImpl<WeakMapBucket<WeakMapBucketDataKey>>::offsetOfCapacity()), maskGPR);
12818 m_jit.loadPtr(MacroAssembler::Address(weakMapGPR, WeakMapImpl<WeakMapBucket<WeakMapBucketDataKey>>::offsetOfBuffer()), bufferGPR);
12819 }
12820
12821 SpeculateCellOperand key(this, node->child2());
12822 GPRReg keyGPR = key.gpr();
12823 speculateObject(node->child2(), keyGPR);
12824
12825#if USE(JSVALUE32_64)
12826 GPRReg bucketGPR = resultRegs.tagGPR();
12827#else
12828 GPRTemporary bucket(this);
12829 GPRReg bucketGPR = bucket.gpr();
12830#endif
12831
12832 m_jit.sub32(TrustedImm32(1), maskGPR);
12833
12834 MacroAssembler::Label loop = m_jit.label();
12835 m_jit.and32(maskGPR, indexGPR);
12836 if (node->child1().useKind() == WeakSetObjectUse) {
12837 static_assert(sizeof(WeakMapBucket<WeakMapBucketDataKey>) == sizeof(void*), "");
12838 m_jit.zeroExtend32ToPtr(indexGPR, bucketGPR);
12839 m_jit.lshiftPtr(MacroAssembler::Imm32(sizeof(void*) == 4 ? 2 : 3), bucketGPR);
12840 m_jit.addPtr(bufferGPR, bucketGPR);
12841 } else {
12842 ASSERT(node->child1().useKind() == WeakMapObjectUse);
12843 static_assert(sizeof(WeakMapBucket<WeakMapBucketDataKeyValue>) == 16, "");
12844 m_jit.zeroExtend32ToPtr(indexGPR, bucketGPR);
12845 m_jit.lshiftPtr(MacroAssembler::Imm32(4), bucketGPR);
12846 m_jit.addPtr(bufferGPR, bucketGPR);
12847 }
12848
12849 m_jit.loadPtr(MacroAssembler::Address(bucketGPR, WeakMapBucket<WeakMapBucketDataKeyValue>::offsetOfKey()), resultRegs.payloadGPR());
12850
12851 // They're definitely the same value, we found the bucket we were looking for!
12852 // The deleted key comparison is also done with this.
12853 auto found = m_jit.branchPtr(MacroAssembler::Equal, resultRegs.payloadGPR(), keyGPR);
12854
12855 auto notPresentInTable = m_jit.branchTestPtr(MacroAssembler::Zero, resultRegs.payloadGPR());
12856
12857 m_jit.add32(TrustedImm32(1), indexGPR);
12858 m_jit.jump().linkTo(loop, &m_jit);
12859
12860#if USE(JSVALUE32_64)
12861 notPresentInTable.link(&m_jit);
12862 m_jit.moveValue(JSValue(), resultRegs);
12863 auto notPresentInTableDone = m_jit.jump();
12864
12865 found.link(&m_jit);
12866 if (node->child1().useKind() == WeakSetObjectUse)
12867 m_jit.move(TrustedImm32(JSValue::CellTag), resultRegs.tagGPR());
12868 else
12869 m_jit.loadValue(MacroAssembler::Address(bucketGPR, WeakMapBucket<WeakMapBucketDataKeyValue>::offsetOfValue()), resultRegs);
12870
12871 notPresentInTableDone.link(&m_jit);
12872#else
12873 notPresentInTable.link(&m_jit);
12874 found.link(&m_jit);
12875
12876 // In 64bit environment, Empty bucket has JSEmpty value. Empty key is JSEmpty.
12877 // If empty bucket is found, we can use the same path used for the case of finding a bucket.
12878 if (node->child1().useKind() == WeakMapObjectUse)
12879 m_jit.loadValue(MacroAssembler::Address(bucketGPR, WeakMapBucket<WeakMapBucketDataKeyValue>::offsetOfValue()), resultRegs);
12880#endif
12881
12882 jsValueResult(resultRegs, node);
12883}
12884
12885void SpeculativeJIT::compileWeakSetAdd(Node* node)
12886{
12887 SpeculateCellOperand set(this, node->child1());
12888 SpeculateCellOperand key(this, node->child2());
12889 SpeculateInt32Operand hash(this, node->child3());
12890
12891 GPRReg setGPR = set.gpr();
12892 GPRReg keyGPR = key.gpr();
12893 GPRReg hashGPR = hash.gpr();
12894
12895 speculateWeakSetObject(node->child1(), setGPR);
12896 speculateObject(node->child2(), keyGPR);
12897
12898 flushRegisters();
12899 callOperation(operationWeakSetAdd, setGPR, keyGPR, hashGPR);
12900 m_jit.exceptionCheck();
12901 noResult(node);
12902}
12903
12904void SpeculativeJIT::compileWeakMapSet(Node* node)
12905{
12906 SpeculateCellOperand map(this, m_jit.graph().varArgChild(node, 0));
12907 SpeculateCellOperand key(this, m_jit.graph().varArgChild(node, 1));
12908 JSValueOperand value(this, m_jit.graph().varArgChild(node, 2));
12909 SpeculateInt32Operand hash(this, m_jit.graph().varArgChild(node, 3));
12910
12911 GPRReg mapGPR = map.gpr();
12912 GPRReg keyGPR = key.gpr();
12913 JSValueRegs valueRegs = value.jsValueRegs();
12914 GPRReg hashGPR = hash.gpr();
12915
12916 speculateWeakMapObject(m_jit.graph().varArgChild(node, 0), mapGPR);
12917 speculateObject(m_jit.graph().varArgChild(node, 1), keyGPR);
12918
12919 flushRegisters();
12920 callOperation(operationWeakMapSet, mapGPR, keyGPR, valueRegs, hashGPR);
12921 m_jit.exceptionCheck();
12922 noResult(node);
12923}
12924
12925void SpeculativeJIT::compileGetPrototypeOf(Node* node)
12926{
12927 switch (node->child1().useKind()) {
12928 case ArrayUse:
12929 case FunctionUse:
12930 case FinalObjectUse: {
12931 SpeculateCellOperand object(this, node->child1());
12932 GPRTemporary temp(this);
12933 GPRTemporary temp2(this);
12934
12935 GPRReg objectGPR = object.gpr();
12936 GPRReg tempGPR = temp.gpr();
12937 GPRReg temp2GPR = temp2.gpr();
12938
12939 switch (node->child1().useKind()) {
12940 case ArrayUse:
12941 speculateArray(node->child1(), objectGPR);
12942 break;
12943 case FunctionUse:
12944 speculateFunction(node->child1(), objectGPR);
12945 break;
12946 case FinalObjectUse:
12947 speculateFinalObject(node->child1(), objectGPR);
12948 break;
12949 default:
12950 RELEASE_ASSERT_NOT_REACHED();
12951 break;
12952 }
12953
12954 m_jit.emitLoadStructure(*m_jit.vm(), objectGPR, tempGPR, temp2GPR);
12955
12956 AbstractValue& value = m_state.forNode(node->child1());
12957 if ((value.m_type && !(value.m_type & ~SpecObject)) && value.m_structure.isFinite()) {
12958 bool hasPolyProto = false;
12959 bool hasMonoProto = false;
12960 value.m_structure.forEach([&] (RegisteredStructure structure) {
12961 if (structure->hasPolyProto())
12962 hasPolyProto = true;
12963 else
12964 hasMonoProto = true;
12965 });
12966
12967 if (hasMonoProto && !hasPolyProto) {
12968#if USE(JSVALUE64)
12969 m_jit.load64(MacroAssembler::Address(tempGPR, Structure::prototypeOffset()), tempGPR);
12970 jsValueResult(tempGPR, node);
12971#else
12972 m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + TagOffset), temp2GPR);
12973 m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + PayloadOffset), tempGPR);
12974 jsValueResult(temp2GPR, tempGPR, node);
12975#endif
12976 return;
12977 }
12978
12979 if (hasPolyProto && !hasMonoProto) {
12980#if USE(JSVALUE64)
12981 m_jit.load64(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset)), tempGPR);
12982 jsValueResult(tempGPR, node);
12983#else
12984 m_jit.load32(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset) + TagOffset), temp2GPR);
12985 m_jit.load32(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset) + PayloadOffset), tempGPR);
12986 jsValueResult(temp2GPR, tempGPR, node);
12987#endif
12988 return;
12989 }
12990 }
12991
12992#if USE(JSVALUE64)
12993 m_jit.load64(MacroAssembler::Address(tempGPR, Structure::prototypeOffset()), tempGPR);
12994 auto hasMonoProto = m_jit.branchIfNotEmpty(tempGPR);
12995 m_jit.load64(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset)), tempGPR);
12996 hasMonoProto.link(&m_jit);
12997 jsValueResult(tempGPR, node);
12998#else
12999 m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + TagOffset), temp2GPR);
13000 m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + PayloadOffset), tempGPR);
13001 auto hasMonoProto = m_jit.branchIfNotEmpty(temp2GPR);
13002 m_jit.load32(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset) + TagOffset), temp2GPR);
13003 m_jit.load32(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset) + PayloadOffset), tempGPR);
13004 hasMonoProto.link(&m_jit);
13005 jsValueResult(temp2GPR, tempGPR, node);
13006#endif
13007 return;
13008 }
13009 case ObjectUse: {
13010 SpeculateCellOperand value(this, node->child1());
13011 JSValueRegsTemporary result(this);
13012
13013 GPRReg valueGPR = value.gpr();
13014 JSValueRegs resultRegs = result.regs();
13015
13016 speculateObject(node->child1(), valueGPR);
13017
13018 flushRegisters();
13019 callOperation(operationGetPrototypeOfObject, resultRegs, valueGPR);
13020 m_jit.exceptionCheck();
13021 jsValueResult(resultRegs, node);
13022 return;
13023 }
13024 default: {
13025 JSValueOperand value(this, node->child1());
13026 JSValueRegsTemporary result(this);
13027
13028 JSValueRegs valueRegs = value.jsValueRegs();
13029 JSValueRegs resultRegs = result.regs();
13030
13031 flushRegisters();
13032 callOperation(operationGetPrototypeOf, resultRegs, valueRegs);
13033 m_jit.exceptionCheck();
13034 jsValueResult(resultRegs, node);
13035 return;
13036 }
13037 }
13038}
13039
13040void SpeculativeJIT::compileIdentity(Node* node)
13041{
13042 speculate(node, node->child1());
13043 switch (node->child1().useKind()) {
13044#if USE(JSVALUE64)
13045 case DoubleRepAnyIntUse:
13046#endif
13047 case DoubleRepUse:
13048 case DoubleRepRealUse: {
13049 SpeculateDoubleOperand op(this, node->child1());
13050 FPRTemporary scratch(this, op);
13051 m_jit.moveDouble(op.fpr(), scratch.fpr());
13052 doubleResult(scratch.fpr(), node);
13053 break;
13054 }
13055#if USE(JSVALUE64)
13056 case Int52RepUse: {
13057 SpeculateInt52Operand op(this, node->child1());
13058 GPRTemporary result(this, Reuse, op);
13059 m_jit.move(op.gpr(), result.gpr());
13060 int52Result(result.gpr(), node);
13061 break;
13062 }
13063#endif
13064 default: {
13065 JSValueOperand op(this, node->child1(), ManualOperandSpeculation);
13066 JSValueRegsTemporary result(this, Reuse, op);
13067 JSValueRegs opRegs = op.jsValueRegs();
13068 JSValueRegs resultRegs = result.regs();
13069 m_jit.moveValueRegs(opRegs, resultRegs);
13070 jsValueResult(resultRegs, node);
13071 break;
13072 }
13073 }
13074}
13075
13076void SpeculativeJIT::compileMiscStrictEq(Node* node)
13077{
13078 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
13079 JSValueOperand op2(this, node->child2(), ManualOperandSpeculation);
13080 GPRTemporary result(this);
13081
13082 if (node->child1().useKind() == MiscUse)
13083 speculateMisc(node->child1(), op1.jsValueRegs());
13084 if (node->child2().useKind() == MiscUse)
13085 speculateMisc(node->child2(), op2.jsValueRegs());
13086
13087#if USE(JSVALUE64)
13088 m_jit.compare64(JITCompiler::Equal, op1.gpr(), op2.gpr(), result.gpr());
13089#else
13090 m_jit.move(TrustedImm32(0), result.gpr());
13091 JITCompiler::Jump notEqual = m_jit.branch32(JITCompiler::NotEqual, op1.tagGPR(), op2.tagGPR());
13092 m_jit.compare32(JITCompiler::Equal, op1.payloadGPR(), op2.payloadGPR(), result.gpr());
13093 notEqual.link(&m_jit);
13094#endif
13095 unblessedBooleanResult(result.gpr(), node);
13096}
13097
13098void SpeculativeJIT::emitInitializeButterfly(GPRReg storageGPR, GPRReg sizeGPR, JSValueRegs emptyValueRegs, GPRReg scratchGPR)
13099{
13100 m_jit.zeroExtend32ToPtr(sizeGPR, scratchGPR);
13101 MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratchGPR);
13102 MacroAssembler::Label loop = m_jit.label();
13103 m_jit.sub32(TrustedImm32(1), scratchGPR);
13104 m_jit.storeValue(emptyValueRegs, MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight));
13105 m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
13106 done.link(&m_jit);
13107}
13108
13109void SpeculativeJIT::compileAllocateNewArrayWithSize(JSGlobalObject* globalObject, GPRReg resultGPR, GPRReg sizeGPR, IndexingType indexingType, bool shouldConvertLargeSizeToArrayStorage)
13110{
13111 GPRTemporary storage(this);
13112 GPRTemporary scratch(this);
13113 GPRTemporary scratch2(this);
13114
13115 GPRReg storageGPR = storage.gpr();
13116 GPRReg scratchGPR = scratch.gpr();
13117 GPRReg scratch2GPR = scratch2.gpr();
13118
13119 m_jit.move(TrustedImmPtr(nullptr), storageGPR);
13120
13121 MacroAssembler::JumpList slowCases;
13122 if (shouldConvertLargeSizeToArrayStorage)
13123 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)));
13124#if !ASSERT_DISABLED
13125 else {
13126 MacroAssembler::Jump lengthIsWithinLimits;
13127 lengthIsWithinLimits = m_jit.branch32(MacroAssembler::Below, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH));
13128 m_jit.abortWithReason(UncheckedOverflow);
13129 lengthIsWithinLimits.link(&m_jit);
13130 }
13131#endif
13132
13133 // We can use resultGPR as a scratch right now.
13134 emitAllocateButterfly(storageGPR, sizeGPR, scratchGPR, scratch2GPR, resultGPR, slowCases);
13135
13136#if USE(JSVALUE64)
13137 JSValueRegs emptyValueRegs(scratchGPR);
13138 if (hasDouble(indexingType))
13139 m_jit.move(TrustedImm64(bitwise_cast<int64_t>(PNaN)), emptyValueRegs.gpr());
13140 else
13141 m_jit.move(TrustedImm64(JSValue::encode(JSValue())), emptyValueRegs.gpr());
13142#else
13143 JSValueRegs emptyValueRegs(scratchGPR, scratch2GPR);
13144 if (hasDouble(indexingType))
13145 m_jit.moveValue(JSValue(JSValue::EncodeAsDouble, PNaN), emptyValueRegs);
13146 else
13147 m_jit.moveValue(JSValue(), emptyValueRegs);
13148#endif
13149 emitInitializeButterfly(storageGPR, sizeGPR, emptyValueRegs, resultGPR);
13150
13151 RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType));
13152
13153 emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
13154
13155 m_jit.mutatorFence(*m_jit.vm());
13156
13157 addSlowPathGenerator(std::make_unique<CallArrayAllocatorWithVariableSizeSlowPathGenerator>(
13158 slowCases, this, operationNewArrayWithSize, resultGPR,
13159 structure,
13160 shouldConvertLargeSizeToArrayStorage ? m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)) : structure,
13161 sizeGPR, storageGPR));
13162}
13163
13164void SpeculativeJIT::compileHasIndexedProperty(Node* node)
13165{
13166 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
13167 SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 1));
13168 GPRTemporary result(this);
13169
13170 GPRReg baseGPR = base.gpr();
13171 GPRReg indexGPR = index.gpr();
13172 GPRReg resultGPR = result.gpr();
13173
13174 MacroAssembler::JumpList slowCases;
13175 ArrayMode mode = node->arrayMode();
13176 switch (mode.type()) {
13177 case Array::Int32:
13178 case Array::Contiguous: {
13179 ASSERT(!!m_graph.varArgChild(node, 2));
13180 StorageOperand storage(this, m_graph.varArgChild(node, 2));
13181 GPRTemporary scratch(this);
13182
13183 GPRReg storageGPR = storage.gpr();
13184 GPRReg scratchGPR = scratch.gpr();
13185
13186 MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
13187 if (mode.isInBounds())
13188 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, outOfBounds);
13189 else
13190 slowCases.append(outOfBounds);
13191
13192#if USE(JSVALUE64)
13193 m_jit.load64(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchGPR);
13194 slowCases.append(m_jit.branchIfEmpty(scratchGPR));
13195#else
13196 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR);
13197 slowCases.append(m_jit.branchIfEmpty(scratchGPR));
13198#endif
13199 m_jit.move(TrustedImm32(1), resultGPR);
13200 break;
13201 }
13202 case Array::Double: {
13203 ASSERT(!!m_graph.varArgChild(node, 2));
13204 StorageOperand storage(this, m_graph.varArgChild(node, 2));
13205 FPRTemporary scratch(this);
13206 FPRReg scratchFPR = scratch.fpr();
13207 GPRReg storageGPR = storage.gpr();
13208
13209 MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
13210 if (mode.isInBounds())
13211 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, outOfBounds);
13212 else
13213 slowCases.append(outOfBounds);
13214
13215 m_jit.loadDouble(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchFPR);
13216 slowCases.append(m_jit.branchIfNaN(scratchFPR));
13217 m_jit.move(TrustedImm32(1), resultGPR);
13218 break;
13219 }
13220 case Array::ArrayStorage: {
13221 ASSERT(!!m_graph.varArgChild(node, 2));
13222 StorageOperand storage(this, m_graph.varArgChild(node, 2));
13223 GPRTemporary scratch(this);
13224
13225 GPRReg storageGPR = storage.gpr();
13226 GPRReg scratchGPR = scratch.gpr();
13227
13228 MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
13229 if (mode.isInBounds())
13230 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, outOfBounds);
13231 else
13232 slowCases.append(outOfBounds);
13233
13234#if USE(JSVALUE64)
13235 m_jit.load64(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()), scratchGPR);
13236 slowCases.append(m_jit.branchIfEmpty(scratchGPR));
13237#else
13238 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR);
13239 slowCases.append(m_jit.branchIfEmpty(scratchGPR));
13240#endif
13241 m_jit.move(TrustedImm32(1), resultGPR);
13242 break;
13243 }
13244 default: {
13245 slowCases.append(m_jit.jump());
13246 break;
13247 }
13248 }
13249
13250 addSlowPathGenerator(slowPathCall(slowCases, this, operationHasIndexedPropertyByInt, resultGPR, baseGPR, indexGPR, static_cast<int32_t>(node->internalMethodType())));
13251
13252 unblessedBooleanResult(resultGPR, node);
13253}
13254
13255void SpeculativeJIT::compileGetDirectPname(Node* node)
13256{
13257 Edge& baseEdge = m_jit.graph().varArgChild(node, 0);
13258 Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
13259 Edge& indexEdge = m_jit.graph().varArgChild(node, 2);
13260
13261 SpeculateCellOperand base(this, baseEdge);
13262 SpeculateCellOperand property(this, propertyEdge);
13263 GPRReg baseGPR = base.gpr();
13264 GPRReg propertyGPR = property.gpr();
13265
13266#if CPU(X86)
13267 // Not enough registers on X86 for this code, so always use the slow path.
13268 speculate(node, indexEdge);
13269 flushRegisters();
13270 JSValueRegsFlushedCallResult result(this);
13271 JSValueRegs resultRegs = result.regs();
13272 callOperation(operationGetByValCell, resultRegs, baseGPR, CCallHelpers::CellValue(propertyGPR));
13273 m_jit.exceptionCheck();
13274 jsValueResult(resultRegs, node);
13275#else
13276 Edge& enumeratorEdge = m_jit.graph().varArgChild(node, 3);
13277 SpeculateStrictInt32Operand index(this, indexEdge);
13278 SpeculateCellOperand enumerator(this, enumeratorEdge);
13279 GPRTemporary scratch(this);
13280 JSValueRegsTemporary result(this);
13281
13282 GPRReg indexGPR = index.gpr();
13283 GPRReg enumeratorGPR = enumerator.gpr();
13284 GPRReg scratchGPR = scratch.gpr();
13285 JSValueRegs resultRegs = result.regs();
13286
13287 MacroAssembler::JumpList slowPath;
13288
13289 // Check the structure
13290 m_jit.load32(MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), scratchGPR);
13291 slowPath.append(
13292 m_jit.branch32(
13293 MacroAssembler::NotEqual,
13294 scratchGPR,
13295 MacroAssembler::Address(
13296 enumeratorGPR, JSPropertyNameEnumerator::cachedStructureIDOffset())));
13297
13298 // Compute the offset
13299 // If index is less than the enumerator's cached inline storage, then it's an inline access
13300 MacroAssembler::Jump outOfLineAccess = m_jit.branch32(MacroAssembler::AboveOrEqual,
13301 indexGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()));
13302
13303 m_jit.loadValue(MacroAssembler::BaseIndex(baseGPR, indexGPR, MacroAssembler::TimesEight, JSObject::offsetOfInlineStorage()), resultRegs);
13304
13305 MacroAssembler::Jump done = m_jit.jump();
13306
13307 // Otherwise it's out of line
13308 outOfLineAccess.link(&m_jit);
13309 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), resultRegs.payloadGPR());
13310 m_jit.move(indexGPR, scratchGPR);
13311 m_jit.sub32(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), scratchGPR);
13312 m_jit.neg32(scratchGPR);
13313 m_jit.signExtend32ToPtr(scratchGPR, scratchGPR);
13314 int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
13315 m_jit.loadValue(MacroAssembler::BaseIndex(resultRegs.payloadGPR(), scratchGPR, MacroAssembler::TimesEight, offsetOfFirstProperty), resultRegs);
13316
13317 done.link(&m_jit);
13318
13319 addSlowPathGenerator(slowPathCall(slowPath, this, operationGetByValCell, resultRegs, baseGPR, CCallHelpers::CellValue(propertyGPR)));
13320
13321 jsValueResult(resultRegs, node);
13322#endif
13323}
13324
13325void SpeculativeJIT::compileExtractCatchLocal(Node* node)
13326{
13327 JSValueRegsTemporary result(this);
13328 JSValueRegs resultRegs = result.regs();
13329
13330 JSValue* ptr = &reinterpret_cast<JSValue*>(m_jit.jitCode()->common.catchOSREntryBuffer->dataBuffer())[node->catchOSREntryIndex()];
13331 m_jit.loadValue(ptr, resultRegs);
13332 jsValueResult(resultRegs, node);
13333}
13334
13335void SpeculativeJIT::compileClearCatchLocals(Node* node)
13336{
13337 ScratchBuffer* scratchBuffer = m_jit.jitCode()->common.catchOSREntryBuffer;
13338 ASSERT(scratchBuffer);
13339 GPRTemporary scratch(this);
13340 GPRReg scratchGPR = scratch.gpr();
13341 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratchGPR);
13342 m_jit.storePtr(TrustedImmPtr(nullptr), scratchGPR);
13343 noResult(node);
13344}
13345
13346void SpeculativeJIT::compileProfileType(Node* node)
13347{
13348 JSValueOperand value(this, node->child1());
13349 GPRTemporary scratch1(this);
13350 GPRTemporary scratch2(this);
13351 GPRTemporary scratch3(this);
13352
13353 JSValueRegs valueRegs = value.jsValueRegs();
13354 GPRReg scratch1GPR = scratch1.gpr();
13355 GPRReg scratch2GPR = scratch2.gpr();
13356 GPRReg scratch3GPR = scratch3.gpr();
13357
13358 MacroAssembler::JumpList jumpToEnd;
13359
13360 jumpToEnd.append(m_jit.branchIfEmpty(valueRegs));
13361
13362 TypeLocation* cachedTypeLocation = node->typeLocation();
13363 // Compile in a predictive type check, if possible, to see if we can skip writing to the log.
13364 // These typechecks are inlined to match those of the 64-bit JSValue type checks.
13365 if (cachedTypeLocation->m_lastSeenType == TypeUndefined)
13366 jumpToEnd.append(m_jit.branchIfUndefined(valueRegs));
13367 else if (cachedTypeLocation->m_lastSeenType == TypeNull)
13368 jumpToEnd.append(m_jit.branchIfNull(valueRegs));
13369 else if (cachedTypeLocation->m_lastSeenType == TypeBoolean)
13370 jumpToEnd.append(m_jit.branchIfBoolean(valueRegs, scratch1GPR));
13371 else if (cachedTypeLocation->m_lastSeenType == TypeAnyInt)
13372 jumpToEnd.append(m_jit.branchIfInt32(valueRegs));
13373 else if (cachedTypeLocation->m_lastSeenType == TypeNumber)
13374 jumpToEnd.append(m_jit.branchIfNumber(valueRegs, scratch1GPR));
13375 else if (cachedTypeLocation->m_lastSeenType == TypeString) {
13376 MacroAssembler::Jump isNotCell = m_jit.branchIfNotCell(valueRegs);
13377 jumpToEnd.append(m_jit.branchIfString(valueRegs.payloadGPR()));
13378 isNotCell.link(&m_jit);
13379 }
13380
13381 // Load the TypeProfilerLog into Scratch2.
13382 TypeProfilerLog* cachedTypeProfilerLog = m_jit.vm()->typeProfilerLog();
13383 m_jit.move(TrustedImmPtr(cachedTypeProfilerLog), scratch2GPR);
13384
13385 // Load the next LogEntry into Scratch1.
13386 m_jit.loadPtr(MacroAssembler::Address(scratch2GPR, TypeProfilerLog::currentLogEntryOffset()), scratch1GPR);
13387
13388 // Store the JSValue onto the log entry.
13389 m_jit.storeValue(valueRegs, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::valueOffset()));
13390
13391 // Store the structureID of the cell if valueRegs is a cell, otherwise, store 0 on the log entry.
13392 MacroAssembler::Jump isNotCell = m_jit.branchIfNotCell(valueRegs);
13393 m_jit.load32(MacroAssembler::Address(valueRegs.payloadGPR(), JSCell::structureIDOffset()), scratch3GPR);
13394 m_jit.store32(scratch3GPR, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::structureIDOffset()));
13395 MacroAssembler::Jump skipIsCell = m_jit.jump();
13396 isNotCell.link(&m_jit);
13397 m_jit.store32(TrustedImm32(0), MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::structureIDOffset()));
13398 skipIsCell.link(&m_jit);
13399
13400 // Store the typeLocation on the log entry.
13401 m_jit.move(TrustedImmPtr(cachedTypeLocation), scratch3GPR);
13402 m_jit.storePtr(scratch3GPR, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::locationOffset()));
13403
13404 // Increment the current log entry.
13405 m_jit.addPtr(TrustedImm32(sizeof(TypeProfilerLog::LogEntry)), scratch1GPR);
13406 m_jit.storePtr(scratch1GPR, MacroAssembler::Address(scratch2GPR, TypeProfilerLog::currentLogEntryOffset()));
13407 MacroAssembler::Jump clearLog = m_jit.branchPtr(MacroAssembler::Equal, scratch1GPR, TrustedImmPtr(cachedTypeProfilerLog->logEndPtr()));
13408 addSlowPathGenerator(
13409 slowPathCall(clearLog, this, operationProcessTypeProfilerLogDFG, NoResult));
13410
13411 jumpToEnd.link(&m_jit);
13412
13413 noResult(node);
13414}
13415
13416void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, JSValueRegs valueRegs, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
13417{
13418 RegisterSet usedRegisters = this->usedRegisters();
13419 if (spillMode == DontSpill) {
13420 // We've already flushed registers to the stack, we don't need to spill these.
13421 usedRegisters.set(baseGPR, false);
13422 usedRegisters.set(valueRegs, false);
13423 }
13424 CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
13425 JITPutByIdGenerator gen(
13426 m_jit.codeBlock(), codeOrigin, callSite, usedRegisters,
13427 JSValueRegs::payloadOnly(baseGPR), valueRegs,
13428 scratchGPR, m_jit.ecmaModeFor(codeOrigin), putKind);
13429
13430 gen.generateFastPath(m_jit);
13431
13432 JITCompiler::JumpList slowCases;
13433 if (slowPathTarget.isSet())
13434 slowCases.append(slowPathTarget);
13435 slowCases.append(gen.slowPathJump());
13436
13437 auto slowPath = slowPathCall(
13438 slowCases, this, gen.slowPathFunction(), NoResult, gen.stubInfo(), valueRegs,
13439 CCallHelpers::CellValue(baseGPR), identifierUID(identifierNumber));
13440
13441 m_jit.addPutById(gen, slowPath.get());
13442 addSlowPathGenerator(WTFMove(slowPath));
13443}
13444
13445void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node* node, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
13446{
13447 ASSERT(node->isBinaryUseKind(UntypedUse));
13448 JSValueOperand arg1(this, node->child1());
13449 JSValueOperand arg2(this, node->child2());
13450
13451 JSValueRegs arg1Regs = arg1.jsValueRegs();
13452 JSValueRegs arg2Regs = arg2.jsValueRegs();
13453
13454 JITCompiler::JumpList slowPath;
13455
13456 if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) {
13457 GPRFlushedCallResult result(this);
13458 GPRReg resultGPR = result.gpr();
13459
13460 arg1.use();
13461 arg2.use();
13462
13463 flushRegisters();
13464 callOperation(helperFunction, resultGPR, arg1Regs, arg2Regs);
13465 m_jit.exceptionCheck();
13466
13467 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
13468 return;
13469 }
13470
13471 GPRTemporary result(this, Reuse, arg1, TagWord);
13472 GPRReg resultGPR = result.gpr();
13473
13474 arg1.use();
13475 arg2.use();
13476
13477 if (!isKnownInteger(node->child1().node()))
13478 slowPath.append(m_jit.branchIfNotInt32(arg1Regs));
13479 if (!isKnownInteger(node->child2().node()))
13480 slowPath.append(m_jit.branchIfNotInt32(arg2Regs));
13481
13482 m_jit.compare32(cond, arg1Regs.payloadGPR(), arg2Regs.payloadGPR(), resultGPR);
13483
13484 if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node()))
13485 addSlowPathGenerator(slowPathCall(slowPath, this, helperFunction, resultGPR, arg1Regs, arg2Regs));
13486
13487 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
13488}
13489
13490void SpeculativeJIT::nonSpeculativePeepholeBranch(Node* node, Node* branchNode, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
13491{
13492 BasicBlock* taken = branchNode->branchData()->taken.block;
13493 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
13494
13495 JITCompiler::ResultCondition callResultCondition = JITCompiler::NonZero;
13496
13497 // The branch instruction will branch to the taken block.
13498 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
13499 if (taken == nextBlock()) {
13500 cond = JITCompiler::invert(cond);
13501 callResultCondition = JITCompiler::Zero;
13502 BasicBlock* tmp = taken;
13503 taken = notTaken;
13504 notTaken = tmp;
13505 }
13506
13507 JSValueOperand arg1(this, node->child1());
13508 JSValueOperand arg2(this, node->child2());
13509 JSValueRegs arg1Regs = arg1.jsValueRegs();
13510 JSValueRegs arg2Regs = arg2.jsValueRegs();
13511
13512 JITCompiler::JumpList slowPath;
13513
13514 if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) {
13515 GPRFlushedCallResult result(this);
13516 GPRReg resultGPR = result.gpr();
13517
13518 arg1.use();
13519 arg2.use();
13520
13521 flushRegisters();
13522 callOperation(helperFunction, resultGPR, arg1Regs, arg2Regs);
13523 m_jit.exceptionCheck();
13524
13525 branchTest32(callResultCondition, resultGPR, taken);
13526 } else {
13527 GPRTemporary result(this, Reuse, arg2, TagWord);
13528 GPRReg resultGPR = result.gpr();
13529
13530 arg1.use();
13531 arg2.use();
13532
13533 if (!isKnownInteger(node->child1().node()))
13534 slowPath.append(m_jit.branchIfNotInt32(arg1Regs));
13535 if (!isKnownInteger(node->child2().node()))
13536 slowPath.append(m_jit.branchIfNotInt32(arg2Regs));
13537
13538 branch32(cond, arg1Regs.payloadGPR(), arg2Regs.payloadGPR(), taken);
13539
13540 if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node())) {
13541 jump(notTaken, ForceJump);
13542
13543 slowPath.link(&m_jit);
13544
13545 silentSpillAllRegisters(resultGPR);
13546 callOperation(helperFunction, resultGPR, arg1Regs, arg2Regs);
13547 silentFillAllRegisters();
13548 m_jit.exceptionCheck();
13549
13550 branchTest32(callResultCondition, resultGPR, taken);
13551 }
13552 }
13553
13554 jump(notTaken);
13555
13556 m_indexInBlock = m_block->size() - 1;
13557 m_currentNode = branchNode;
13558}
13559
13560void SpeculativeJIT::compileBigIntEquality(Node* node)
13561{
13562 // FIXME: [ESNext][BigInt] Create specialized version of strict equals for BigIntUse
13563 // https://bugs.webkit.org/show_bug.cgi?id=182895
13564 SpeculateCellOperand left(this, node->child1());
13565 SpeculateCellOperand right(this, node->child2());
13566 GPRTemporary result(this, Reuse, left);
13567 GPRReg leftGPR = left.gpr();
13568 GPRReg rightGPR = right.gpr();
13569 GPRReg resultGPR = result.gpr();
13570
13571 left.use();
13572 right.use();
13573
13574 speculateBigInt(node->child1(), leftGPR);
13575 speculateBigInt(node->child2(), rightGPR);
13576
13577 JITCompiler::Jump notEqualCase = m_jit.branchPtr(JITCompiler::NotEqual, leftGPR, rightGPR);
13578
13579 m_jit.move(JITCompiler::TrustedImm32(1), resultGPR);
13580
13581 JITCompiler::Jump done = m_jit.jump();
13582
13583 notEqualCase.link(&m_jit);
13584
13585 silentSpillAllRegisters(resultGPR);
13586 callOperation(operationCompareStrictEqCell, resultGPR, leftGPR, rightGPR);
13587 silentFillAllRegisters();
13588
13589 done.link(&m_jit);
13590
13591 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
13592}
13593
13594void SpeculativeJIT::compileMakeRope(Node* node)
13595{
13596 ASSERT(node->child1().useKind() == KnownStringUse);
13597 ASSERT(node->child2().useKind() == KnownStringUse);
13598 ASSERT(!node->child3() || node->child3().useKind() == KnownStringUse);
13599
13600 SpeculateCellOperand op1(this, node->child1());
13601 SpeculateCellOperand op2(this, node->child2());
13602 SpeculateCellOperand op3(this, node->child3());
13603 GPRReg opGPRs[3];
13604 unsigned numOpGPRs;
13605 opGPRs[0] = op1.gpr();
13606 opGPRs[1] = op2.gpr();
13607 if (node->child3()) {
13608 opGPRs[2] = op3.gpr();
13609 numOpGPRs = 3;
13610 } else {
13611 opGPRs[2] = InvalidGPRReg;
13612 numOpGPRs = 2;
13613 }
13614
13615#if CPU(ADDRESS64)
13616 Edge edges[3] = {
13617 node->child1(),
13618 node->child2(),
13619 node->child3()
13620 };
13621
13622 GPRTemporary result(this);
13623 GPRTemporary allocator(this);
13624 GPRTemporary scratch(this);
13625 GPRTemporary scratch2(this);
13626 GPRReg resultGPR = result.gpr();
13627 GPRReg allocatorGPR = allocator.gpr();
13628 GPRReg scratchGPR = scratch.gpr();
13629 GPRReg scratch2GPR = scratch2.gpr();
13630
13631 CCallHelpers::JumpList slowPath;
13632 Allocator allocatorValue = allocatorForNonVirtualConcurrently<JSRopeString>(*m_jit.vm(), sizeof(JSRopeString), AllocatorForMode::AllocatorIfExists);
13633 emitAllocateJSCell(resultGPR, JITAllocator::constant(allocatorValue), allocatorGPR, TrustedImmPtr(m_jit.graph().registerStructure(m_jit.vm()->stringStructure.get())), scratchGPR, slowPath);
13634
13635 // 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.
13636 m_jit.storePtr(TrustedImmPtr(JSString::isRopeInPointer), CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber0()));
13637
13638 {
13639 if (JSString* string = edges[0]->dynamicCastConstant<JSString*>(*m_jit.vm())) {
13640 m_jit.move(TrustedImm32(string->is8Bit() ? StringImpl::flagIs8Bit() : 0), scratchGPR);
13641 m_jit.move(TrustedImm32(string->length()), allocatorGPR);
13642 } else {
13643 bool needsRopeCase = canBeRope(edges[0]);
13644 m_jit.loadPtr(CCallHelpers::Address(opGPRs[0], JSString::offsetOfValue()), scratch2GPR);
13645 CCallHelpers::Jump isRope;
13646 if (needsRopeCase)
13647 isRope = m_jit.branchIfRopeStringImpl(scratch2GPR);
13648
13649 m_jit.load32(CCallHelpers::Address(scratch2GPR, StringImpl::flagsOffset()), scratchGPR);
13650 m_jit.load32(CCallHelpers::Address(scratch2GPR, StringImpl::lengthMemoryOffset()), allocatorGPR);
13651
13652 if (needsRopeCase) {
13653 auto done = m_jit.jump();
13654
13655 isRope.link(&m_jit);
13656 m_jit.load32(CCallHelpers::Address(opGPRs[0], JSRopeString::offsetOfFlags()), scratchGPR);
13657 m_jit.load32(CCallHelpers::Address(opGPRs[0], JSRopeString::offsetOfLength()), allocatorGPR);
13658 done.link(&m_jit);
13659 }
13660 }
13661
13662 if (!ASSERT_DISABLED) {
13663 CCallHelpers::Jump ok = m_jit.branch32(
13664 CCallHelpers::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
13665 m_jit.abortWithReason(DFGNegativeStringLength);
13666 ok.link(&m_jit);
13667 }
13668 }
13669
13670 for (unsigned i = 1; i < numOpGPRs; ++i) {
13671 if (JSString* string = edges[i]->dynamicCastConstant<JSString*>(*m_jit.vm())) {
13672 m_jit.and32(TrustedImm32(string->is8Bit() ? StringImpl::flagIs8Bit() : 0), scratchGPR);
13673 speculationCheck(
13674 Uncountable, JSValueSource(), nullptr,
13675 m_jit.branchAdd32(
13676 CCallHelpers::Overflow,
13677 TrustedImm32(string->length()), allocatorGPR));
13678 } else {
13679 bool needsRopeCase = canBeRope(edges[i]);
13680 m_jit.loadPtr(CCallHelpers::Address(opGPRs[i], JSString::offsetOfValue()), scratch2GPR);
13681 CCallHelpers::Jump isRope;
13682 if (needsRopeCase)
13683 isRope = m_jit.branchIfRopeStringImpl(scratch2GPR);
13684
13685 m_jit.and32(CCallHelpers::Address(scratch2GPR, StringImpl::flagsOffset()), scratchGPR);
13686 speculationCheck(
13687 Uncountable, JSValueSource(), nullptr,
13688 m_jit.branchAdd32(
13689 CCallHelpers::Overflow,
13690 CCallHelpers::Address(scratch2GPR, StringImpl::lengthMemoryOffset()), allocatorGPR));
13691 if (needsRopeCase) {
13692 auto done = m_jit.jump();
13693
13694 isRope.link(&m_jit);
13695 m_jit.and32(CCallHelpers::Address(opGPRs[i], JSRopeString::offsetOfFlags()), scratchGPR);
13696 m_jit.load32(CCallHelpers::Address(opGPRs[i], JSRopeString::offsetOfLength()), scratch2GPR);
13697 speculationCheck(
13698 Uncountable, JSValueSource(), nullptr,
13699 m_jit.branchAdd32(
13700 CCallHelpers::Overflow, scratch2GPR, allocatorGPR));
13701 done.link(&m_jit);
13702 }
13703 }
13704 }
13705
13706 if (!ASSERT_DISABLED) {
13707 CCallHelpers::Jump ok = m_jit.branch32(
13708 CCallHelpers::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
13709 m_jit.abortWithReason(DFGNegativeStringLength);
13710 ok.link(&m_jit);
13711 }
13712
13713 static_assert(StringImpl::flagIs8Bit() == JSRopeString::is8BitInPointer, "");
13714 m_jit.and32(TrustedImm32(StringImpl::flagIs8Bit()), scratchGPR);
13715 m_jit.orPtr(opGPRs[0], scratchGPR);
13716 m_jit.orPtr(TrustedImmPtr(JSString::isRopeInPointer), scratchGPR);
13717 m_jit.storePtr(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber0()));
13718
13719 m_jit.move(opGPRs[1], scratchGPR);
13720 m_jit.lshiftPtr(TrustedImm32(32), scratchGPR);
13721 m_jit.orPtr(allocatorGPR, scratchGPR);
13722 m_jit.storePtr(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber1()));
13723
13724 if (numOpGPRs == 2) {
13725 m_jit.move(opGPRs[1], scratchGPR);
13726 m_jit.rshiftPtr(TrustedImm32(32), scratchGPR);
13727 m_jit.storePtr(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2()));
13728 } else {
13729 m_jit.move(opGPRs[1], scratchGPR);
13730 m_jit.rshiftPtr(TrustedImm32(32), scratchGPR);
13731 m_jit.move(opGPRs[2], scratch2GPR);
13732 m_jit.lshiftPtr(TrustedImm32(16), scratch2GPR);
13733 m_jit.orPtr(scratch2GPR, scratchGPR);
13734 m_jit.storePtr(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2()));
13735 }
13736
13737 auto isNonEmptyString = m_jit.branchTest32(CCallHelpers::NonZero, allocatorGPR);
13738
13739 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(&m_jit.graph().m_vm)), resultGPR);
13740
13741 isNonEmptyString.link(&m_jit);
13742 m_jit.mutatorFence(*m_jit.vm());
13743
13744 switch (numOpGPRs) {
13745 case 2:
13746 addSlowPathGenerator(slowPathCall(
13747 slowPath, this, operationMakeRope2, resultGPR, opGPRs[0], opGPRs[1]));
13748 break;
13749 case 3:
13750 addSlowPathGenerator(slowPathCall(
13751 slowPath, this, operationMakeRope3, resultGPR, opGPRs[0], opGPRs[1], opGPRs[2]));
13752 break;
13753 default:
13754 RELEASE_ASSERT_NOT_REACHED();
13755 break;
13756 }
13757
13758 cellResult(resultGPR, node);
13759#else
13760 flushRegisters();
13761 GPRFlushedCallResult result(this);
13762 GPRReg resultGPR = result.gpr();
13763 switch (numOpGPRs) {
13764 case 2:
13765 callOperation(operationMakeRope2, resultGPR, opGPRs[0], opGPRs[1]);
13766 m_jit.exceptionCheck();
13767 break;
13768 case 3:
13769 callOperation(operationMakeRope3, resultGPR, opGPRs[0], opGPRs[1], opGPRs[2]);
13770 m_jit.exceptionCheck();
13771 break;
13772 default:
13773 RELEASE_ASSERT_NOT_REACHED();
13774 break;
13775 }
13776
13777 cellResult(resultGPR, node);
13778#endif
13779}
13780
13781} } // namespace JSC::DFG
13782
13783#endif
13784