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