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 "DateInstance.h"
43#include "DirectArguments.h"
44#include "DisallowMacroScratchRegisterUsage.h"
45#include "JITAddGenerator.h"
46#include "JITBitAndGenerator.h"
47#include "JITBitOrGenerator.h"
48#include "JITBitXorGenerator.h"
49#include "JITDivGenerator.h"
50#include "JITLeftShiftGenerator.h"
51#include "JITMulGenerator.h"
52#include "JITRightShiftGenerator.h"
53#include "JITSubGenerator.h"
54#include "JSAsyncFunction.h"
55#include "JSAsyncGeneratorFunction.h"
56#include "JSCInlines.h"
57#include "JSFixedArray.h"
58#include "JSGeneratorFunction.h"
59#include "JSImmutableButterfly.h"
60#include "JSLexicalEnvironment.h"
61#include "JSPropertyNameEnumerator.h"
62#include "LinkBuffer.h"
63#include "RegExpObject.h"
64#include "ScopedArguments.h"
65#include "ScratchRegisterAllocator.h"
66#include "SuperSampler.h"
67#include "TypeProfilerLog.h"
68#include "WeakMapImpl.h"
69#include <wtf/BitVector.h>
70#include <wtf/Box.h>
71#include <wtf/MathExtras.h>
72
73namespace JSC { namespace DFG {
74
75SpeculativeJIT::SpeculativeJIT(JITCompiler& jit)
76 : m_jit(jit)
77 , m_graph(m_jit.graph())
78 , m_currentNode(0)
79 , m_lastGeneratedNode(LastNodeType)
80 , m_indexInBlock(0)
81 , m_generationInfo(m_jit.graph().frameRegisterCount())
82 , m_compileOkay(true)
83 , m_state(m_jit.graph())
84 , m_interpreter(m_jit.graph(), m_state)
85 , m_stream(&jit.jitCode()->variableEventStream)
86 , m_minifiedGraph(&jit.jitCode()->minifiedDFG)
87{
88}
89
90SpeculativeJIT::~SpeculativeJIT()
91{
92}
93
94void SpeculativeJIT::emitAllocateRawObject(GPRReg resultGPR, RegisteredStructure structure, GPRReg storageGPR, unsigned numElements, unsigned vectorLength)
95{
96 ASSERT(!isCopyOnWrite(structure->indexingMode()));
97 IndexingType indexingType = structure->indexingType();
98 bool hasIndexingHeader = hasIndexedProperties(indexingType);
99
100 unsigned inlineCapacity = structure->inlineCapacity();
101 unsigned outOfLineCapacity = structure->outOfLineCapacity();
102
103 GPRTemporary scratch(this);
104 GPRTemporary scratch2(this);
105 GPRReg scratchGPR = scratch.gpr();
106 GPRReg scratch2GPR = scratch2.gpr();
107
108 ASSERT(vectorLength >= numElements);
109 vectorLength = Butterfly::optimalContiguousVectorLength(structure.get(), vectorLength);
110
111 JITCompiler::JumpList slowCases;
112
113 size_t size = 0;
114 if (hasIndexingHeader)
115 size += vectorLength * sizeof(JSValue) + sizeof(IndexingHeader);
116 size += outOfLineCapacity * sizeof(JSValue);
117
118 m_jit.move(TrustedImmPtr(nullptr), storageGPR);
119
120 VM& vm = this->vm();
121 if (size) {
122 if (Allocator allocator = vm.jsValueGigacageAuxiliarySpace.allocatorForNonVirtual(size, AllocatorForMode::AllocatorIfExists)) {
123 m_jit.emitAllocate(storageGPR, JITAllocator::constant(allocator), scratchGPR, scratch2GPR, slowCases);
124
125 m_jit.addPtr(
126 TrustedImm32(outOfLineCapacity * sizeof(JSValue) + sizeof(IndexingHeader)),
127 storageGPR);
128
129 if (hasIndexingHeader)
130 m_jit.store32(TrustedImm32(vectorLength), MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
131 } else
132 slowCases.append(m_jit.jump());
133 }
134
135 size_t allocationSize = JSFinalObject::allocationSize(inlineCapacity);
136 Allocator allocator = allocatorForNonVirtualConcurrently<JSFinalObject>(vm, allocationSize, AllocatorForMode::AllocatorIfExists);
137 if (allocator) {
138 emitAllocateJSObject(resultGPR, JITAllocator::constant(allocator), scratchGPR, TrustedImmPtr(structure), storageGPR, scratch2GPR, slowCases);
139 m_jit.emitInitializeInlineStorage(resultGPR, structure->inlineCapacity());
140 } else
141 slowCases.append(m_jit.jump());
142
143 // I want a slow path that also loads out the storage pointer, and that's
144 // what this custom CallArrayAllocatorSlowPathGenerator gives me. It's a lot
145 // of work for a very small piece of functionality. :-/
146 addSlowPathGenerator(makeUnique<CallArrayAllocatorSlowPathGenerator>(
147 slowCases, this, operationNewRawObject, resultGPR, storageGPR,
148 structure, vectorLength));
149
150 if (numElements < vectorLength) {
151#if USE(JSVALUE64)
152 if (hasDouble(structure->indexingType()))
153 m_jit.move(TrustedImm64(bitwise_cast<int64_t>(PNaN)), scratchGPR);
154 else
155 m_jit.move(TrustedImm64(JSValue::encode(JSValue())), scratchGPR);
156 for (unsigned i = numElements; i < vectorLength; ++i)
157 m_jit.store64(scratchGPR, MacroAssembler::Address(storageGPR, sizeof(double) * i));
158#else
159 EncodedValueDescriptor value;
160 if (hasDouble(structure->indexingType()))
161 value.asInt64 = JSValue::encode(JSValue(JSValue::EncodeAsDouble, PNaN));
162 else
163 value.asInt64 = JSValue::encode(JSValue());
164 for (unsigned i = numElements; i < vectorLength; ++i) {
165 m_jit.store32(TrustedImm32(value.asBits.tag), MacroAssembler::Address(storageGPR, sizeof(double) * i + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
166 m_jit.store32(TrustedImm32(value.asBits.payload), MacroAssembler::Address(storageGPR, sizeof(double) * i + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
167 }
168#endif
169 }
170
171 if (hasIndexingHeader)
172 m_jit.store32(TrustedImm32(numElements), MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
173
174 m_jit.emitInitializeOutOfLineStorage(storageGPR, structure->outOfLineCapacity());
175
176 m_jit.mutatorFence(vm);
177}
178
179void SpeculativeJIT::emitGetLength(InlineCallFrame* inlineCallFrame, GPRReg lengthGPR, bool includeThis)
180{
181 if (inlineCallFrame && !inlineCallFrame->isVarargs())
182 m_jit.move(TrustedImm32(inlineCallFrame->argumentCountIncludingThis - !includeThis), lengthGPR);
183 else {
184 VirtualRegister argumentCountRegister = m_jit.argumentCount(inlineCallFrame);
185 m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), lengthGPR);
186 if (!includeThis)
187 m_jit.sub32(TrustedImm32(1), lengthGPR);
188 }
189}
190
191void SpeculativeJIT::emitGetLength(CodeOrigin origin, GPRReg lengthGPR, bool includeThis)
192{
193 emitGetLength(origin.inlineCallFrame(), lengthGPR, includeThis);
194}
195
196void SpeculativeJIT::emitGetCallee(CodeOrigin origin, GPRReg calleeGPR)
197{
198 auto* inlineCallFrame = origin.inlineCallFrame();
199 if (inlineCallFrame) {
200 if (inlineCallFrame->isClosureCall) {
201 m_jit.loadPtr(
202 JITCompiler::addressFor(inlineCallFrame->calleeRecovery.virtualRegister()),
203 calleeGPR);
204 } else {
205 m_jit.move(
206 TrustedImmPtr::weakPointer(m_jit.graph(), inlineCallFrame->calleeRecovery.constant().asCell()),
207 calleeGPR);
208 }
209 } else
210 m_jit.loadPtr(JITCompiler::addressFor(CallFrameSlot::callee), calleeGPR);
211}
212
213void SpeculativeJIT::emitGetArgumentStart(CodeOrigin origin, GPRReg startGPR)
214{
215 m_jit.addPtr(
216 TrustedImm32(
217 JITCompiler::argumentsStart(origin).offset() * static_cast<int>(sizeof(Register))),
218 GPRInfo::callFrameRegister, startGPR);
219}
220
221MacroAssembler::Jump SpeculativeJIT::emitOSRExitFuzzCheck()
222{
223 if (!Options::useOSRExitFuzz()
224 || !canUseOSRExitFuzzing(m_jit.graph().baselineCodeBlockFor(m_origin.semantic))
225 || !doOSRExitFuzzing())
226 return MacroAssembler::Jump();
227
228 MacroAssembler::Jump result;
229
230 m_jit.pushToSave(GPRInfo::regT0);
231 m_jit.load32(&g_numberOfOSRExitFuzzChecks, GPRInfo::regT0);
232 m_jit.add32(TrustedImm32(1), GPRInfo::regT0);
233 m_jit.store32(GPRInfo::regT0, &g_numberOfOSRExitFuzzChecks);
234 unsigned atOrAfter = Options::fireOSRExitFuzzAtOrAfter();
235 unsigned at = Options::fireOSRExitFuzzAt();
236 if (at || atOrAfter) {
237 unsigned threshold;
238 MacroAssembler::RelationalCondition condition;
239 if (atOrAfter) {
240 threshold = atOrAfter;
241 condition = MacroAssembler::Below;
242 } else {
243 threshold = at;
244 condition = MacroAssembler::NotEqual;
245 }
246 MacroAssembler::Jump ok = m_jit.branch32(
247 condition, GPRInfo::regT0, MacroAssembler::TrustedImm32(threshold));
248 m_jit.popToRestore(GPRInfo::regT0);
249 result = m_jit.jump();
250 ok.link(&m_jit);
251 }
252 m_jit.popToRestore(GPRInfo::regT0);
253
254 return result;
255}
256
257void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail)
258{
259 if (!m_compileOkay)
260 return;
261 JITCompiler::Jump fuzzJump = emitOSRExitFuzzCheck();
262 if (fuzzJump.isSet()) {
263 JITCompiler::JumpList jumpsToFail;
264 jumpsToFail.append(fuzzJump);
265 jumpsToFail.append(jumpToFail);
266 m_jit.appendExitInfo(jumpsToFail);
267 } else
268 m_jit.appendExitInfo(jumpToFail);
269 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(m_currentNode, node), this, m_stream->size()));
270}
271
272void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, const MacroAssembler::JumpList& jumpsToFail)
273{
274 if (!m_compileOkay)
275 return;
276 JITCompiler::Jump fuzzJump = emitOSRExitFuzzCheck();
277 if (fuzzJump.isSet()) {
278 JITCompiler::JumpList myJumpsToFail;
279 myJumpsToFail.append(jumpsToFail);
280 myJumpsToFail.append(fuzzJump);
281 m_jit.appendExitInfo(myJumpsToFail);
282 } else
283 m_jit.appendExitInfo(jumpsToFail);
284 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(m_currentNode, node), this, m_stream->size()));
285}
286
287OSRExitJumpPlaceholder SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node)
288{
289 if (!m_compileOkay)
290 return OSRExitJumpPlaceholder();
291 unsigned index = m_jit.jitCode()->osrExit.size();
292 m_jit.appendExitInfo();
293 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(m_currentNode, node), this, m_stream->size()));
294 return OSRExitJumpPlaceholder(index);
295}
296
297OSRExitJumpPlaceholder SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse)
298{
299 return speculationCheck(kind, jsValueSource, nodeUse.node());
300}
301
302void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail)
303{
304 speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail);
305}
306
307void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, const MacroAssembler::JumpList& jumpsToFail)
308{
309 speculationCheck(kind, jsValueSource, nodeUse.node(), jumpsToFail);
310}
311
312void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
313{
314 if (!m_compileOkay)
315 return;
316 unsigned recoveryIndex = m_jit.jitCode()->appendSpeculationRecovery(recovery);
317 m_jit.appendExitInfo(jumpToFail);
318 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(m_currentNode, node), this, m_stream->size(), recoveryIndex));
319}
320
321void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
322{
323 speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail, recovery);
324}
325
326void SpeculativeJIT::emitInvalidationPoint(Node* node)
327{
328 if (!m_compileOkay)
329 return;
330 OSRExitCompilationInfo& info = m_jit.appendExitInfo(JITCompiler::JumpList());
331 m_jit.jitCode()->appendOSRExit(OSRExit(
332 UncountableInvalidation, JSValueSource(), MethodOfGettingAValueProfile(),
333 this, m_stream->size()));
334 info.m_replacementSource = m_jit.watchpointLabel();
335 ASSERT(info.m_replacementSource.isSet());
336 noResult(node);
337}
338
339void SpeculativeJIT::unreachable(Node* node)
340{
341 m_compileOkay = false;
342 m_jit.abortWithReason(DFGUnreachableNode, node->op());
343}
344
345void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, Node* node)
346{
347 if (!m_compileOkay)
348 return;
349 speculationCheck(kind, jsValueRegs, node, m_jit.jump());
350 m_compileOkay = false;
351 if (verboseCompilationEnabled())
352 dataLog("Bailing compilation.\n");
353}
354
355void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, Edge nodeUse)
356{
357 terminateSpeculativeExecution(kind, jsValueRegs, nodeUse.node());
358}
359
360void SpeculativeJIT::typeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail, ExitKind exitKind)
361{
362 ASSERT(needsTypeCheck(edge, typesPassedThrough));
363 m_interpreter.filter(edge, typesPassedThrough);
364 speculationCheck(exitKind, source, edge.node(), jumpToFail);
365}
366
367RegisterSet SpeculativeJIT::usedRegisters()
368{
369 RegisterSet result;
370
371 for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
372 GPRReg gpr = GPRInfo::toRegister(i);
373 if (m_gprs.isInUse(gpr))
374 result.set(gpr);
375 }
376 for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
377 FPRReg fpr = FPRInfo::toRegister(i);
378 if (m_fprs.isInUse(fpr))
379 result.set(fpr);
380 }
381
382 // FIXME: This is overly conservative. We could subtract out those callee-saves that we
383 // actually saved.
384 // https://bugs.webkit.org/show_bug.cgi?id=185686
385 result.merge(RegisterSet::stubUnavailableRegisters());
386
387 return result;
388}
389
390void SpeculativeJIT::addSlowPathGenerator(std::unique_ptr<SlowPathGenerator> slowPathGenerator)
391{
392 m_slowPathGenerators.append(WTFMove(slowPathGenerator));
393}
394
395void SpeculativeJIT::addSlowPathGeneratorLambda(Function<void()>&& lambda)
396{
397 m_slowPathLambdas.append(SlowPathLambda{ WTFMove(lambda), m_currentNode, static_cast<unsigned>(m_stream->size()) });
398}
399
400void SpeculativeJIT::runSlowPathGenerators(PCToCodeOriginMapBuilder& pcToCodeOriginMapBuilder)
401{
402 for (auto& slowPathGenerator : m_slowPathGenerators) {
403 pcToCodeOriginMapBuilder.appendItem(m_jit.labelIgnoringWatchpoints(), slowPathGenerator->origin().semantic);
404 slowPathGenerator->generate(this);
405 }
406 for (auto& slowPathLambda : m_slowPathLambdas) {
407 Node* currentNode = slowPathLambda.currentNode;
408 m_currentNode = currentNode;
409 m_outOfLineStreamIndex = slowPathLambda.streamIndex;
410 pcToCodeOriginMapBuilder.appendItem(m_jit.labelIgnoringWatchpoints(), currentNode->origin.semantic);
411 slowPathLambda.generator();
412 m_outOfLineStreamIndex = WTF::nullopt;
413 }
414}
415
416void SpeculativeJIT::clearGenerationInfo()
417{
418 for (unsigned i = 0; i < m_generationInfo.size(); ++i)
419 m_generationInfo[i] = GenerationInfo();
420 m_gprs = RegisterBank<GPRInfo>();
421 m_fprs = RegisterBank<FPRInfo>();
422}
423
424SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForGPR(VirtualRegister spillMe, GPRReg source)
425{
426 GenerationInfo& info = generationInfoFromVirtualRegister(spillMe);
427 Node* node = info.node();
428 DataFormat registerFormat = info.registerFormat();
429 ASSERT(registerFormat != DataFormatNone);
430 ASSERT(registerFormat != DataFormatDouble);
431
432 SilentSpillAction spillAction;
433 SilentFillAction fillAction;
434
435 if (!info.needsSpill())
436 spillAction = DoNothingForSpill;
437 else {
438#if USE(JSVALUE64)
439 ASSERT(info.gpr() == source);
440 if (registerFormat == DataFormatInt32)
441 spillAction = Store32Payload;
442 else if (registerFormat == DataFormatCell || registerFormat == DataFormatStorage)
443 spillAction = StorePtr;
444 else if (registerFormat == DataFormatInt52 || registerFormat == DataFormatStrictInt52)
445 spillAction = Store64;
446 else {
447 ASSERT(registerFormat & DataFormatJS);
448 spillAction = Store64;
449 }
450#elif USE(JSVALUE32_64)
451 if (registerFormat & DataFormatJS) {
452 ASSERT(info.tagGPR() == source || info.payloadGPR() == source);
453 spillAction = source == info.tagGPR() ? Store32Tag : Store32Payload;
454 } else {
455 ASSERT(info.gpr() == source);
456 spillAction = Store32Payload;
457 }
458#endif
459 }
460
461 if (registerFormat == DataFormatInt32) {
462 ASSERT(info.gpr() == source);
463 ASSERT(isJSInt32(info.registerFormat()));
464 if (node->hasConstant()) {
465 ASSERT(node->isInt32Constant());
466 fillAction = SetInt32Constant;
467 } else
468 fillAction = Load32Payload;
469 } else if (registerFormat == DataFormatBoolean) {
470#if USE(JSVALUE64)
471 RELEASE_ASSERT_NOT_REACHED();
472#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
473 fillAction = DoNothingForFill;
474#endif
475#elif USE(JSVALUE32_64)
476 ASSERT(info.gpr() == source);
477 if (node->hasConstant()) {
478 ASSERT(node->isBooleanConstant());
479 fillAction = SetBooleanConstant;
480 } else
481 fillAction = Load32Payload;
482#endif
483 } else if (registerFormat == DataFormatCell) {
484 ASSERT(info.gpr() == source);
485 if (node->hasConstant()) {
486 DFG_ASSERT(m_jit.graph(), m_currentNode, node->isCellConstant());
487 node->asCell(); // To get the assertion.
488 fillAction = SetCellConstant;
489 } else {
490#if USE(JSVALUE64)
491 fillAction = LoadPtr;
492#else
493 fillAction = Load32Payload;
494#endif
495 }
496 } else if (registerFormat == DataFormatStorage) {
497 ASSERT(info.gpr() == source);
498 fillAction = LoadPtr;
499 } else if (registerFormat == DataFormatInt52) {
500 if (node->hasConstant())
501 fillAction = SetInt52Constant;
502 else if (info.spillFormat() == DataFormatInt52)
503 fillAction = Load64;
504 else if (info.spillFormat() == DataFormatStrictInt52)
505 fillAction = Load64ShiftInt52Left;
506 else if (info.spillFormat() == DataFormatNone)
507 fillAction = Load64;
508 else {
509 RELEASE_ASSERT_NOT_REACHED();
510#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
511 fillAction = Load64; // Make GCC happy.
512#endif
513 }
514 } else if (registerFormat == DataFormatStrictInt52) {
515 if (node->hasConstant())
516 fillAction = SetStrictInt52Constant;
517 else if (info.spillFormat() == DataFormatInt52)
518 fillAction = Load64ShiftInt52Right;
519 else if (info.spillFormat() == DataFormatStrictInt52)
520 fillAction = Load64;
521 else if (info.spillFormat() == DataFormatNone)
522 fillAction = Load64;
523 else {
524 RELEASE_ASSERT_NOT_REACHED();
525#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
526 fillAction = Load64; // Make GCC happy.
527#endif
528 }
529 } else {
530 ASSERT(registerFormat & DataFormatJS);
531#if USE(JSVALUE64)
532 ASSERT(info.gpr() == source);
533 if (node->hasConstant()) {
534 if (node->isCellConstant())
535 fillAction = SetTrustedJSConstant;
536 else
537 fillAction = SetJSConstant;
538 } else if (info.spillFormat() == DataFormatInt32) {
539 ASSERT(registerFormat == DataFormatJSInt32);
540 fillAction = Load32PayloadBoxInt;
541 } else
542 fillAction = Load64;
543#else
544 ASSERT(info.tagGPR() == source || info.payloadGPR() == source);
545 if (node->hasConstant())
546 fillAction = info.tagGPR() == source ? SetJSConstantTag : SetJSConstantPayload;
547 else if (info.payloadGPR() == source)
548 fillAction = Load32Payload;
549 else { // Fill the Tag
550 switch (info.spillFormat()) {
551 case DataFormatInt32:
552 ASSERT(registerFormat == DataFormatJSInt32);
553 fillAction = SetInt32Tag;
554 break;
555 case DataFormatCell:
556 ASSERT(registerFormat == DataFormatJSCell);
557 fillAction = SetCellTag;
558 break;
559 case DataFormatBoolean:
560 ASSERT(registerFormat == DataFormatJSBoolean);
561 fillAction = SetBooleanTag;
562 break;
563 default:
564 fillAction = Load32Tag;
565 break;
566 }
567 }
568#endif
569 }
570
571 return SilentRegisterSavePlan(spillAction, fillAction, node, source);
572}
573
574SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForFPR(VirtualRegister spillMe, FPRReg source)
575{
576 GenerationInfo& info = generationInfoFromVirtualRegister(spillMe);
577 Node* node = info.node();
578 ASSERT(info.registerFormat() == DataFormatDouble);
579
580 SilentSpillAction spillAction;
581 SilentFillAction fillAction;
582
583 if (!info.needsSpill())
584 spillAction = DoNothingForSpill;
585 else {
586 ASSERT(!node->hasConstant());
587 ASSERT(info.spillFormat() == DataFormatNone);
588 ASSERT(info.fpr() == source);
589 spillAction = StoreDouble;
590 }
591
592#if USE(JSVALUE64)
593 if (node->hasConstant()) {
594 node->asNumber(); // To get the assertion.
595 fillAction = SetDoubleConstant;
596 } else {
597 ASSERT(info.spillFormat() == DataFormatNone || info.spillFormat() == DataFormatDouble);
598 fillAction = LoadDouble;
599 }
600#elif USE(JSVALUE32_64)
601 ASSERT(info.registerFormat() == DataFormatDouble);
602 if (node->hasConstant()) {
603 node->asNumber(); // To get the assertion.
604 fillAction = SetDoubleConstant;
605 } else
606 fillAction = LoadDouble;
607#endif
608
609 return SilentRegisterSavePlan(spillAction, fillAction, node, source);
610}
611
612void SpeculativeJIT::silentSpill(const SilentRegisterSavePlan& plan)
613{
614 switch (plan.spillAction()) {
615 case DoNothingForSpill:
616 break;
617 case Store32Tag:
618 m_jit.store32(plan.gpr(), JITCompiler::tagFor(plan.node()->virtualRegister()));
619 break;
620 case Store32Payload:
621 m_jit.store32(plan.gpr(), JITCompiler::payloadFor(plan.node()->virtualRegister()));
622 break;
623 case StorePtr:
624 m_jit.storePtr(plan.gpr(), JITCompiler::addressFor(plan.node()->virtualRegister()));
625 break;
626#if USE(JSVALUE64)
627 case Store64:
628 m_jit.store64(plan.gpr(), JITCompiler::addressFor(plan.node()->virtualRegister()));
629 break;
630#endif
631 case StoreDouble:
632 m_jit.storeDouble(plan.fpr(), JITCompiler::addressFor(plan.node()->virtualRegister()));
633 break;
634 default:
635 RELEASE_ASSERT_NOT_REACHED();
636 }
637}
638
639void SpeculativeJIT::silentFill(const SilentRegisterSavePlan& plan)
640{
641 switch (plan.fillAction()) {
642 case DoNothingForFill:
643 break;
644 case SetInt32Constant:
645 m_jit.move(Imm32(plan.node()->asInt32()), plan.gpr());
646 break;
647#if USE(JSVALUE64)
648 case SetInt52Constant:
649 m_jit.move(Imm64(plan.node()->asAnyInt() << JSValue::int52ShiftAmount), plan.gpr());
650 break;
651 case SetStrictInt52Constant:
652 m_jit.move(Imm64(plan.node()->asAnyInt()), plan.gpr());
653 break;
654#endif // USE(JSVALUE64)
655 case SetBooleanConstant:
656 m_jit.move(TrustedImm32(plan.node()->asBoolean()), plan.gpr());
657 break;
658 case SetCellConstant:
659 ASSERT(plan.node()->constant()->value().isCell());
660 m_jit.move(TrustedImmPtr(plan.node()->constant()), plan.gpr());
661 break;
662#if USE(JSVALUE64)
663 case SetTrustedJSConstant:
664 m_jit.move(valueOfJSConstantAsImm64(plan.node()).asTrustedImm64(), plan.gpr());
665 break;
666 case SetJSConstant:
667 m_jit.move(valueOfJSConstantAsImm64(plan.node()), plan.gpr());
668 break;
669 case SetDoubleConstant:
670 m_jit.moveDouble(Imm64(reinterpretDoubleToInt64(plan.node()->asNumber())), plan.fpr());
671 break;
672 case Load32PayloadBoxInt:
673 m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr());
674 m_jit.or64(GPRInfo::numberTagRegister, plan.gpr());
675 break;
676 case Load32PayloadConvertToInt52:
677 m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr());
678 m_jit.signExtend32ToPtr(plan.gpr(), plan.gpr());
679 m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), plan.gpr());
680 break;
681 case Load32PayloadSignExtend:
682 m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr());
683 m_jit.signExtend32ToPtr(plan.gpr(), plan.gpr());
684 break;
685#else
686 case SetJSConstantTag:
687 m_jit.move(Imm32(plan.node()->asJSValue().tag()), plan.gpr());
688 break;
689 case SetJSConstantPayload:
690 m_jit.move(Imm32(plan.node()->asJSValue().payload()), plan.gpr());
691 break;
692 case SetInt32Tag:
693 m_jit.move(TrustedImm32(JSValue::Int32Tag), plan.gpr());
694 break;
695 case SetCellTag:
696 m_jit.move(TrustedImm32(JSValue::CellTag), plan.gpr());
697 break;
698 case SetBooleanTag:
699 m_jit.move(TrustedImm32(JSValue::BooleanTag), plan.gpr());
700 break;
701 case SetDoubleConstant:
702 m_jit.loadDouble(TrustedImmPtr(m_jit.addressOfDoubleConstant(plan.node())), plan.fpr());
703 break;
704#endif
705 case Load32Tag:
706 m_jit.load32(JITCompiler::tagFor(plan.node()->virtualRegister()), plan.gpr());
707 break;
708 case Load32Payload:
709 m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr());
710 break;
711 case LoadPtr:
712 m_jit.loadPtr(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr());
713 break;
714#if USE(JSVALUE64)
715 case Load64:
716 m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr());
717 break;
718 case Load64ShiftInt52Right:
719 m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr());
720 m_jit.rshift64(TrustedImm32(JSValue::int52ShiftAmount), plan.gpr());
721 break;
722 case Load64ShiftInt52Left:
723 m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr());
724 m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), plan.gpr());
725 break;
726#endif
727 case LoadDouble:
728 m_jit.loadDouble(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.fpr());
729 break;
730 default:
731 RELEASE_ASSERT_NOT_REACHED();
732 }
733}
734
735JITCompiler::JumpList SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode)
736{
737 JITCompiler::JumpList result;
738
739 IndexingType indexingModeMask = IsArray | IndexingShapeMask;
740 if (arrayMode.action() == Array::Write)
741 indexingModeMask |= CopyOnWrite;
742
743 switch (arrayMode.type()) {
744 case Array::Int32:
745 case Array::Double:
746 case Array::Contiguous:
747 case Array::Undecided:
748 case Array::ArrayStorage: {
749 IndexingType shape = arrayMode.shapeMask();
750 switch (arrayMode.arrayClass()) {
751 case Array::OriginalArray:
752 case Array::OriginalCopyOnWriteArray:
753 RELEASE_ASSERT_NOT_REACHED();
754 return result;
755
756 case Array::Array:
757 m_jit.and32(TrustedImm32(indexingModeMask), tempGPR);
758 result.append(m_jit.branch32(
759 MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | shape)));
760 return result;
761
762 case Array::NonArray:
763 case Array::OriginalNonArray:
764 m_jit.and32(TrustedImm32(indexingModeMask), tempGPR);
765 result.append(m_jit.branch32(
766 MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape)));
767 return result;
768
769 case Array::PossiblyArray:
770 m_jit.and32(TrustedImm32(indexingModeMask & ~IsArray), tempGPR);
771 result.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape)));
772 return result;
773 }
774
775 RELEASE_ASSERT_NOT_REACHED();
776 return result;
777 }
778
779 case Array::SlowPutArrayStorage: {
780 ASSERT(!arrayMode.isJSArrayWithOriginalStructure());
781
782 switch (arrayMode.arrayClass()) {
783 case Array::OriginalArray:
784 case Array::OriginalCopyOnWriteArray:
785 RELEASE_ASSERT_NOT_REACHED();
786 return result;
787
788 case Array::Array:
789 result.append(
790 m_jit.branchTest32(
791 MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(IsArray)));
792 break;
793
794 case Array::NonArray:
795 case Array::OriginalNonArray:
796 result.append(
797 m_jit.branchTest32(
798 MacroAssembler::NonZero, tempGPR, MacroAssembler::TrustedImm32(IsArray)));
799 break;
800
801 case Array::PossiblyArray:
802 break;
803 }
804
805 m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR);
806 m_jit.sub32(TrustedImm32(ArrayStorageShape), tempGPR);
807 result.append(
808 m_jit.branch32(
809 MacroAssembler::Above, tempGPR,
810 TrustedImm32(SlowPutArrayStorageShape - ArrayStorageShape)));
811 return result;
812 }
813 default:
814 CRASH();
815 break;
816 }
817
818 return result;
819}
820
821void SpeculativeJIT::checkArray(Node* node)
822{
823 ASSERT(node->arrayMode().isSpecific());
824 ASSERT(!node->arrayMode().doesConversion());
825
826 SpeculateCellOperand base(this, node->child1());
827 GPRReg baseReg = base.gpr();
828
829 if (node->arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))) {
830 noResult(m_currentNode);
831 return;
832 }
833
834 switch (node->arrayMode().type()) {
835 case Array::AnyTypedArray:
836 case Array::String:
837 RELEASE_ASSERT_NOT_REACHED(); // Should have been a Phantom(String:)
838 return;
839 case Array::Int32:
840 case Array::Double:
841 case Array::Contiguous:
842 case Array::Undecided:
843 case Array::ArrayStorage:
844 case Array::SlowPutArrayStorage: {
845 GPRTemporary temp(this);
846 GPRReg tempGPR = temp.gpr();
847 m_jit.load8(MacroAssembler::Address(baseReg, JSCell::indexingTypeAndMiscOffset()), tempGPR);
848 speculationCheck(
849 BadIndexingType, JSValueSource::unboxedCell(baseReg), 0,
850 jumpSlowForUnwantedArrayMode(tempGPR, node->arrayMode()));
851
852 noResult(m_currentNode);
853 return;
854 }
855 case Array::DirectArguments:
856 speculateCellTypeWithoutTypeFiltering(node->child1(), baseReg, DirectArgumentsType);
857 noResult(m_currentNode);
858 return;
859 case Array::ScopedArguments:
860 speculateCellTypeWithoutTypeFiltering(node->child1(), baseReg, ScopedArgumentsType);
861 noResult(m_currentNode);
862 return;
863 default:
864 speculateCellTypeWithoutTypeFiltering(
865 node->child1(), baseReg,
866 typeForTypedArrayType(node->arrayMode().typedArrayType()));
867 noResult(m_currentNode);
868 return;
869 }
870}
871
872void SpeculativeJIT::arrayify(Node* node, GPRReg baseReg, GPRReg propertyReg)
873{
874 ASSERT(node->arrayMode().doesConversion());
875
876 GPRTemporary temp(this);
877 GPRTemporary structure;
878 GPRReg tempGPR = temp.gpr();
879 GPRReg structureGPR = InvalidGPRReg;
880
881 if (node->op() != ArrayifyToStructure) {
882 GPRTemporary realStructure(this);
883 structure.adopt(realStructure);
884 structureGPR = structure.gpr();
885 }
886
887 // We can skip all that comes next if we already have array storage.
888 MacroAssembler::JumpList slowPath;
889
890 if (node->op() == ArrayifyToStructure) {
891 ASSERT(!isCopyOnWrite(node->structure()->indexingMode()));
892 ASSERT((node->structure()->indexingType() & IndexingShapeMask) == node->arrayMode().shapeMask());
893 slowPath.append(m_jit.branchWeakStructure(
894 JITCompiler::NotEqual,
895 JITCompiler::Address(baseReg, JSCell::structureIDOffset()),
896 node->structure()));
897 } else {
898 m_jit.load8(
899 MacroAssembler::Address(baseReg, JSCell::indexingTypeAndMiscOffset()), tempGPR);
900
901 slowPath.append(jumpSlowForUnwantedArrayMode(tempGPR, node->arrayMode()));
902 }
903
904 addSlowPathGenerator(makeUnique<ArrayifySlowPathGenerator>(
905 slowPath, this, node, baseReg, propertyReg, tempGPR, structureGPR));
906
907 noResult(m_currentNode);
908}
909
910void SpeculativeJIT::arrayify(Node* node)
911{
912 ASSERT(node->arrayMode().isSpecific());
913
914 SpeculateCellOperand base(this, node->child1());
915
916 if (!node->child2()) {
917 arrayify(node, base.gpr(), InvalidGPRReg);
918 return;
919 }
920
921 SpeculateInt32Operand property(this, node->child2());
922
923 arrayify(node, base.gpr(), property.gpr());
924}
925
926GPRReg SpeculativeJIT::fillStorage(Edge edge)
927{
928 VirtualRegister virtualRegister = edge->virtualRegister();
929 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
930
931 switch (info.registerFormat()) {
932 case DataFormatNone: {
933 if (info.spillFormat() == DataFormatStorage) {
934 GPRReg gpr = allocate();
935 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
936 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
937 info.fillStorage(*m_stream, gpr);
938 return gpr;
939 }
940
941 // Must be a cell; fill it as a cell and then return the pointer.
942 return fillSpeculateCell(edge);
943 }
944
945 case DataFormatStorage: {
946 GPRReg gpr = info.gpr();
947 m_gprs.lock(gpr);
948 return gpr;
949 }
950
951 default:
952 return fillSpeculateCell(edge);
953 }
954}
955
956void SpeculativeJIT::useChildren(Node* node)
957{
958 if (node->flags() & NodeHasVarArgs) {
959 for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++) {
960 if (!!m_jit.graph().m_varArgChildren[childIdx])
961 use(m_jit.graph().m_varArgChildren[childIdx]);
962 }
963 } else {
964 Edge child1 = node->child1();
965 if (!child1) {
966 ASSERT(!node->child2() && !node->child3());
967 return;
968 }
969 use(child1);
970
971 Edge child2 = node->child2();
972 if (!child2) {
973 ASSERT(!node->child3());
974 return;
975 }
976 use(child2);
977
978 Edge child3 = node->child3();
979 if (!child3)
980 return;
981 use(child3);
982 }
983}
984
985void SpeculativeJIT::compileGetById(Node* node, AccessType accessType)
986{
987 ASSERT(accessType == AccessType::GetById || accessType == AccessType::GetByIdDirect || accessType == AccessType::TryGetById);
988
989 switch (node->child1().useKind()) {
990 case CellUse: {
991 SpeculateCellOperand base(this, node->child1());
992 JSValueRegsTemporary result(this, Reuse, base);
993
994 JSValueRegs baseRegs = JSValueRegs::payloadOnly(base.gpr());
995 JSValueRegs resultRegs = result.regs();
996
997 base.use();
998
999 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), NeedToSpill, accessType);
1000
1001 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
1002 break;
1003 }
1004
1005 case UntypedUse: {
1006 JSValueOperand base(this, node->child1());
1007 JSValueRegsTemporary result(this, Reuse, base);
1008
1009 JSValueRegs baseRegs = base.jsValueRegs();
1010 JSValueRegs resultRegs = result.regs();
1011
1012 base.use();
1013
1014 JITCompiler::Jump notCell = m_jit.branchIfNotCell(baseRegs);
1015
1016 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, NeedToSpill, accessType);
1017
1018 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
1019 break;
1020 }
1021
1022 default:
1023 DFG_CRASH(m_jit.graph(), node, "Bad use kind");
1024 break;
1025 }
1026}
1027
1028void SpeculativeJIT::compileGetByIdFlush(Node* node, AccessType accessType)
1029{
1030 switch (node->child1().useKind()) {
1031 case CellUse: {
1032 SpeculateCellOperand base(this, node->child1());
1033 JSValueRegs baseRegs = JSValueRegs::payloadOnly(base.gpr());
1034
1035 JSValueRegsFlushedCallResult result(this);
1036 JSValueRegs resultRegs = result.regs();
1037
1038 base.use();
1039
1040 flushRegisters();
1041
1042 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), DontSpill, accessType);
1043
1044 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
1045 break;
1046 }
1047
1048 case UntypedUse: {
1049 JSValueOperand base(this, node->child1());
1050 JSValueRegs baseRegs = base.jsValueRegs();
1051
1052 JSValueRegsFlushedCallResult result(this);
1053 JSValueRegs resultRegs = result.regs();
1054
1055 base.use();
1056
1057 flushRegisters();
1058
1059 JITCompiler::Jump notCell = m_jit.branchIfNotCell(baseRegs);
1060
1061 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, DontSpill, accessType);
1062
1063 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
1064 break;
1065 }
1066
1067 default:
1068 DFG_CRASH(m_jit.graph(), node, "Bad use kind");
1069 break;
1070 }
1071}
1072
1073void SpeculativeJIT::compileInById(Node* node)
1074{
1075 SpeculateCellOperand base(this, node->child1());
1076 JSValueRegsTemporary result(this, Reuse, base, PayloadWord);
1077
1078 GPRReg baseGPR = base.gpr();
1079 JSValueRegs resultRegs = result.regs();
1080
1081 base.use();
1082
1083 CodeOrigin codeOrigin = node->origin.semantic;
1084 CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
1085 RegisterSet usedRegisters = this->usedRegisters();
1086 JITInByIdGenerator gen(
1087 m_jit.codeBlock(), codeOrigin, callSite, usedRegisters, identifierUID(node->identifierNumber()),
1088 JSValueRegs::payloadOnly(baseGPR), resultRegs);
1089 gen.generateFastPath(m_jit);
1090
1091 auto slowPath = slowPathCall(
1092 gen.slowPathJump(), this, operationInByIdOptimize,
1093 NeedToSpill, ExceptionCheckRequirement::CheckNeeded,
1094 resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), gen.stubInfo(), CCallHelpers::CellValue(baseGPR), identifierUID(node->identifierNumber()));
1095
1096 m_jit.addInById(gen, slowPath.get());
1097 addSlowPathGenerator(WTFMove(slowPath));
1098
1099 blessedBooleanResult(resultRegs.payloadGPR(), node, UseChildrenCalledExplicitly);
1100}
1101
1102void SpeculativeJIT::compileInByVal(Node* node)
1103{
1104 SpeculateCellOperand base(this, node->child1());
1105 JSValueOperand key(this, node->child2());
1106
1107 GPRReg baseGPR = base.gpr();
1108 JSValueRegs regs = key.jsValueRegs();
1109
1110 base.use();
1111 key.use();
1112
1113 flushRegisters();
1114 JSValueRegsFlushedCallResult result(this);
1115 JSValueRegs resultRegs = result.regs();
1116 callOperation(operationInByVal, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, regs);
1117 m_jit.exceptionCheck();
1118 blessedBooleanResult(resultRegs.payloadGPR(), node, UseChildrenCalledExplicitly);
1119}
1120
1121void SpeculativeJIT::compileDeleteById(Node* node)
1122{
1123 JSValueOperand value(this, node->child1());
1124 GPRFlushedCallResult result(this);
1125
1126 JSValueRegs valueRegs = value.jsValueRegs();
1127 GPRReg resultGPR = result.gpr();
1128
1129 value.use();
1130
1131 flushRegisters();
1132 callOperation(operationDeleteById, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueRegs, identifierUID(node->identifierNumber()));
1133 m_jit.exceptionCheck();
1134
1135 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
1136}
1137
1138void SpeculativeJIT::compileDeleteByVal(Node* node)
1139{
1140 JSValueOperand base(this, node->child1());
1141 JSValueOperand key(this, node->child2());
1142 GPRFlushedCallResult result(this);
1143
1144 JSValueRegs baseRegs = base.jsValueRegs();
1145 JSValueRegs keyRegs = key.jsValueRegs();
1146 GPRReg resultGPR = result.gpr();
1147
1148 base.use();
1149 key.use();
1150
1151 flushRegisters();
1152 callOperation(operationDeleteByVal, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseRegs, keyRegs);
1153 m_jit.exceptionCheck();
1154
1155 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
1156}
1157
1158void SpeculativeJIT::compilePushWithScope(Node* node)
1159{
1160 SpeculateCellOperand currentScope(this, node->child1());
1161 GPRReg currentScopeGPR = currentScope.gpr();
1162
1163 GPRFlushedCallResult result(this);
1164 GPRReg resultGPR = result.gpr();
1165
1166 auto objectEdge = node->child2();
1167 if (objectEdge.useKind() == ObjectUse) {
1168 SpeculateCellOperand object(this, objectEdge);
1169 GPRReg objectGPR = object.gpr();
1170 speculateObject(objectEdge, objectGPR);
1171
1172 flushRegisters();
1173 callOperation(operationPushWithScopeObject, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), currentScopeGPR, objectGPR);
1174 // No exception check here as we did not have to call toObject().
1175 } else {
1176 ASSERT(objectEdge.useKind() == UntypedUse);
1177 JSValueOperand object(this, objectEdge);
1178 JSValueRegs objectRegs = object.jsValueRegs();
1179
1180 flushRegisters();
1181 callOperation(operationPushWithScope, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), currentScopeGPR, objectRegs);
1182 m_jit.exceptionCheck();
1183 }
1184
1185 cellResult(resultGPR, node);
1186}
1187
1188bool SpeculativeJIT::nonSpeculativeStrictEq(Node* node, bool invert)
1189{
1190 unsigned branchIndexInBlock = detectPeepHoleBranch();
1191 if (branchIndexInBlock != UINT_MAX) {
1192 Node* branchNode = m_block->at(branchIndexInBlock);
1193
1194 ASSERT(node->adjustedRefCount() == 1);
1195
1196 nonSpeculativePeepholeStrictEq(node, branchNode, invert);
1197
1198 m_indexInBlock = branchIndexInBlock;
1199 m_currentNode = branchNode;
1200
1201 return true;
1202 }
1203
1204 nonSpeculativeNonPeepholeStrictEq(node, invert);
1205
1206 return false;
1207}
1208
1209static const char* dataFormatString(DataFormat format)
1210{
1211 // These values correspond to the DataFormat enum.
1212 const char* strings[] = {
1213 "[ ]",
1214 "[ i]",
1215 "[ d]",
1216 "[ c]",
1217 "Err!",
1218 "Err!",
1219 "Err!",
1220 "Err!",
1221 "[J ]",
1222 "[Ji]",
1223 "[Jd]",
1224 "[Jc]",
1225 "Err!",
1226 "Err!",
1227 "Err!",
1228 "Err!",
1229 };
1230 return strings[format];
1231}
1232
1233void SpeculativeJIT::dump(const char* label)
1234{
1235 if (label)
1236 dataLogF("<%s>\n", label);
1237
1238 dataLogF(" gprs:\n");
1239 m_gprs.dump();
1240 dataLogF(" fprs:\n");
1241 m_fprs.dump();
1242 dataLogF(" VirtualRegisters:\n");
1243 for (unsigned i = 0; i < m_generationInfo.size(); ++i) {
1244 GenerationInfo& info = m_generationInfo[i];
1245 if (info.alive())
1246 dataLogF(" % 3d:%s%s", i, dataFormatString(info.registerFormat()), dataFormatString(info.spillFormat()));
1247 else
1248 dataLogF(" % 3d:[__][__]", i);
1249 if (info.registerFormat() == DataFormatDouble)
1250 dataLogF(":fpr%d\n", info.fpr());
1251 else if (info.registerFormat() != DataFormatNone
1252#if USE(JSVALUE32_64)
1253 && !(info.registerFormat() & DataFormatJS)
1254#endif
1255 ) {
1256 ASSERT(info.gpr() != InvalidGPRReg);
1257 dataLogF(":%s\n", GPRInfo::debugName(info.gpr()));
1258 } else
1259 dataLogF("\n");
1260 }
1261 if (label)
1262 dataLogF("</%s>\n", label);
1263}
1264
1265GPRTemporary::GPRTemporary()
1266 : m_jit(0)
1267 , m_gpr(InvalidGPRReg)
1268{
1269}
1270
1271GPRTemporary::GPRTemporary(SpeculativeJIT* jit)
1272 : m_jit(jit)
1273 , m_gpr(InvalidGPRReg)
1274{
1275 m_gpr = m_jit->allocate();
1276}
1277
1278GPRTemporary::GPRTemporary(SpeculativeJIT* jit, GPRReg specific)
1279 : m_jit(jit)
1280 , m_gpr(InvalidGPRReg)
1281{
1282 m_gpr = m_jit->allocate(specific);
1283}
1284
1285#if USE(JSVALUE32_64)
1286GPRTemporary::GPRTemporary(
1287 SpeculativeJIT* jit, ReuseTag, JSValueOperand& op1, WhichValueWord which)
1288 : m_jit(jit)
1289 , m_gpr(InvalidGPRReg)
1290{
1291 if (!op1.isDouble() && m_jit->canReuse(op1.node()))
1292 m_gpr = m_jit->reuse(op1.gpr(which));
1293 else
1294 m_gpr = m_jit->allocate();
1295}
1296#else // USE(JSVALUE32_64)
1297GPRTemporary::GPRTemporary(SpeculativeJIT* jit, ReuseTag, JSValueOperand& op1, WhichValueWord)
1298 : GPRTemporary(jit, Reuse, op1)
1299{
1300}
1301#endif
1302
1303JSValueRegsTemporary::JSValueRegsTemporary() { }
1304
1305JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit)
1306#if USE(JSVALUE64)
1307 : m_gpr(jit)
1308#else
1309 : m_payloadGPR(jit)
1310 , m_tagGPR(jit)
1311#endif
1312{
1313}
1314
1315#if USE(JSVALUE64)
1316template<typename T>
1317JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, T& operand, WhichValueWord)
1318 : m_gpr(jit, Reuse, operand)
1319{
1320}
1321#else
1322template<typename T>
1323JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, T& operand, WhichValueWord resultWord)
1324{
1325 if (resultWord == PayloadWord) {
1326 m_payloadGPR = GPRTemporary(jit, Reuse, operand);
1327 m_tagGPR = GPRTemporary(jit);
1328 } else {
1329 m_payloadGPR = GPRTemporary(jit);
1330 m_tagGPR = GPRTemporary(jit, Reuse, operand);
1331 }
1332}
1333#endif
1334
1335#if USE(JSVALUE64)
1336JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, JSValueOperand& operand)
1337{
1338 m_gpr = GPRTemporary(jit, Reuse, operand);
1339}
1340#else
1341JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, JSValueOperand& operand)
1342{
1343 if (jit->canReuse(operand.node())) {
1344 m_payloadGPR = GPRTemporary(jit, Reuse, operand, PayloadWord);
1345 m_tagGPR = GPRTemporary(jit, Reuse, operand, TagWord);
1346 } else {
1347 m_payloadGPR = GPRTemporary(jit);
1348 m_tagGPR = GPRTemporary(jit);
1349 }
1350}
1351#endif
1352
1353JSValueRegsTemporary::~JSValueRegsTemporary() { }
1354
1355JSValueRegs JSValueRegsTemporary::regs()
1356{
1357#if USE(JSVALUE64)
1358 return JSValueRegs(m_gpr.gpr());
1359#else
1360 return JSValueRegs(m_tagGPR.gpr(), m_payloadGPR.gpr());
1361#endif
1362}
1363
1364void GPRTemporary::adopt(GPRTemporary& other)
1365{
1366 ASSERT(!m_jit);
1367 ASSERT(m_gpr == InvalidGPRReg);
1368 ASSERT(other.m_jit);
1369 ASSERT(other.m_gpr != InvalidGPRReg);
1370 m_jit = other.m_jit;
1371 m_gpr = other.m_gpr;
1372 other.m_jit = 0;
1373 other.m_gpr = InvalidGPRReg;
1374}
1375
1376FPRTemporary::FPRTemporary(FPRTemporary&& other)
1377{
1378 ASSERT(other.m_jit);
1379 ASSERT(other.m_fpr != InvalidFPRReg);
1380 m_jit = other.m_jit;
1381 m_fpr = other.m_fpr;
1382
1383 other.m_jit = nullptr;
1384}
1385
1386FPRTemporary::FPRTemporary(SpeculativeJIT* jit)
1387 : m_jit(jit)
1388 , m_fpr(InvalidFPRReg)
1389{
1390 m_fpr = m_jit->fprAllocate();
1391}
1392
1393FPRTemporary::FPRTemporary(SpeculativeJIT* jit, SpeculateDoubleOperand& op1)
1394 : m_jit(jit)
1395 , m_fpr(InvalidFPRReg)
1396{
1397 if (m_jit->canReuse(op1.node()))
1398 m_fpr = m_jit->reuse(op1.fpr());
1399 else
1400 m_fpr = m_jit->fprAllocate();
1401}
1402
1403FPRTemporary::FPRTemporary(SpeculativeJIT* jit, SpeculateDoubleOperand& op1, SpeculateDoubleOperand& op2)
1404 : m_jit(jit)
1405 , m_fpr(InvalidFPRReg)
1406{
1407 if (m_jit->canReuse(op1.node()))
1408 m_fpr = m_jit->reuse(op1.fpr());
1409 else if (m_jit->canReuse(op2.node()))
1410 m_fpr = m_jit->reuse(op2.fpr());
1411 else if (m_jit->canReuse(op1.node(), op2.node()) && op1.fpr() == op2.fpr())
1412 m_fpr = m_jit->reuse(op1.fpr());
1413 else
1414 m_fpr = m_jit->fprAllocate();
1415}
1416
1417#if USE(JSVALUE32_64)
1418FPRTemporary::FPRTemporary(SpeculativeJIT* jit, JSValueOperand& op1)
1419 : m_jit(jit)
1420 , m_fpr(InvalidFPRReg)
1421{
1422 if (op1.isDouble() && m_jit->canReuse(op1.node()))
1423 m_fpr = m_jit->reuse(op1.fpr());
1424 else
1425 m_fpr = m_jit->fprAllocate();
1426}
1427#endif
1428
1429void SpeculativeJIT::compilePeepHoleDoubleBranch(Node* node, Node* branchNode, JITCompiler::DoubleCondition condition)
1430{
1431 BasicBlock* taken = branchNode->branchData()->taken.block;
1432 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1433
1434 if (taken == nextBlock()) {
1435 condition = MacroAssembler::invert(condition);
1436 std::swap(taken, notTaken);
1437 }
1438
1439 SpeculateDoubleOperand op1(this, node->child1());
1440 SpeculateDoubleOperand op2(this, node->child2());
1441
1442 branchDouble(condition, op1.fpr(), op2.fpr(), taken);
1443 jump(notTaken);
1444}
1445
1446void SpeculativeJIT::compilePeepHoleObjectEquality(Node* node, Node* branchNode)
1447{
1448 BasicBlock* taken = branchNode->branchData()->taken.block;
1449 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1450
1451 MacroAssembler::RelationalCondition condition = MacroAssembler::Equal;
1452
1453 if (taken == nextBlock()) {
1454 condition = MacroAssembler::NotEqual;
1455 BasicBlock* tmp = taken;
1456 taken = notTaken;
1457 notTaken = tmp;
1458 }
1459
1460 SpeculateCellOperand op1(this, node->child1());
1461 SpeculateCellOperand op2(this, node->child2());
1462
1463 GPRReg op1GPR = op1.gpr();
1464 GPRReg op2GPR = op2.gpr();
1465
1466 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
1467 if (m_state.forNode(node->child1()).m_type & ~SpecObject) {
1468 speculationCheck(
1469 BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), m_jit.branchIfNotObject(op1GPR));
1470 }
1471 if (m_state.forNode(node->child2()).m_type & ~SpecObject) {
1472 speculationCheck(
1473 BadType, JSValueSource::unboxedCell(op2GPR), node->child2(), m_jit.branchIfNotObject(op2GPR));
1474 }
1475 } else {
1476 if (m_state.forNode(node->child1()).m_type & ~SpecObject) {
1477 speculationCheck(
1478 BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
1479 m_jit.branchIfNotObject(op1GPR));
1480 }
1481 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
1482 m_jit.branchTest8(
1483 MacroAssembler::NonZero,
1484 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
1485 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1486
1487 if (m_state.forNode(node->child2()).m_type & ~SpecObject) {
1488 speculationCheck(
1489 BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
1490 m_jit.branchIfNotObject(op2GPR));
1491 }
1492 speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
1493 m_jit.branchTest8(
1494 MacroAssembler::NonZero,
1495 MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()),
1496 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
1497 }
1498
1499 branchPtr(condition, op1GPR, op2GPR, taken);
1500 jump(notTaken);
1501}
1502
1503void SpeculativeJIT::compilePeepHoleBooleanBranch(Node* node, Node* branchNode, JITCompiler::RelationalCondition condition)
1504{
1505 BasicBlock* taken = branchNode->branchData()->taken.block;
1506 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1507
1508 // The branch instruction will branch to the taken block.
1509 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
1510 if (taken == nextBlock()) {
1511 condition = JITCompiler::invert(condition);
1512 BasicBlock* tmp = taken;
1513 taken = notTaken;
1514 notTaken = tmp;
1515 }
1516
1517 if (node->child1()->isInt32Constant()) {
1518 int32_t imm = node->child1()->asInt32();
1519 SpeculateBooleanOperand op2(this, node->child2());
1520 branch32(condition, JITCompiler::Imm32(imm), op2.gpr(), taken);
1521 } else if (node->child2()->isInt32Constant()) {
1522 SpeculateBooleanOperand op1(this, node->child1());
1523 int32_t imm = node->child2()->asInt32();
1524 branch32(condition, op1.gpr(), JITCompiler::Imm32(imm), taken);
1525 } else {
1526 SpeculateBooleanOperand op1(this, node->child1());
1527 SpeculateBooleanOperand op2(this, node->child2());
1528 branch32(condition, op1.gpr(), op2.gpr(), taken);
1529 }
1530
1531 jump(notTaken);
1532}
1533
1534void SpeculativeJIT::compileStringSlice(Node* node)
1535{
1536 SpeculateCellOperand string(this, node->child1());
1537
1538 GPRReg stringGPR = string.gpr();
1539
1540 speculateString(node->child1(), stringGPR);
1541
1542 SpeculateInt32Operand start(this, node->child2());
1543 GPRReg startGPR = start.gpr();
1544
1545 Optional<SpeculateInt32Operand> end;
1546 Optional<GPRReg> endGPR;
1547 if (node->child3()) {
1548 end.emplace(this, node->child3());
1549 endGPR.emplace(end->gpr());
1550 }
1551
1552 GPRTemporary temp(this);
1553 GPRTemporary temp2(this);
1554 GPRTemporary startIndex(this);
1555
1556 GPRReg tempGPR = temp.gpr();
1557 GPRReg temp2GPR = temp2.gpr();
1558 GPRReg startIndexGPR = startIndex.gpr();
1559
1560 m_jit.loadPtr(CCallHelpers::Address(stringGPR, JSString::offsetOfValue()), tempGPR);
1561 auto isRope = m_jit.branchIfRopeStringImpl(tempGPR);
1562 {
1563 m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), temp2GPR);
1564
1565 emitPopulateSliceIndex(node->child2(), startGPR, temp2GPR, startIndexGPR);
1566
1567 if (node->child3())
1568 emitPopulateSliceIndex(node->child3(), endGPR.value(), temp2GPR, tempGPR);
1569 else
1570 m_jit.move(temp2GPR, tempGPR);
1571 }
1572
1573 CCallHelpers::JumpList doneCases;
1574 CCallHelpers::JumpList slowCases;
1575
1576 VM& vm = this->vm();
1577 auto nonEmptyCase = m_jit.branch32(MacroAssembler::Below, startIndexGPR, tempGPR);
1578 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(vm)), tempGPR);
1579 doneCases.append(m_jit.jump());
1580
1581 nonEmptyCase.link(&m_jit);
1582 m_jit.sub32(startIndexGPR, tempGPR); // the size of the sliced string.
1583 slowCases.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(1)));
1584
1585 // Refill StringImpl* here.
1586 m_jit.loadPtr(MacroAssembler::Address(stringGPR, JSString::offsetOfValue()), temp2GPR);
1587 m_jit.loadPtr(MacroAssembler::Address(temp2GPR, StringImpl::dataOffset()), tempGPR);
1588
1589 // Load the character into scratchReg
1590 m_jit.zeroExtend32ToPtr(startIndexGPR, startIndexGPR);
1591 auto is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(temp2GPR, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
1592
1593 m_jit.load8(MacroAssembler::BaseIndex(tempGPR, startIndexGPR, MacroAssembler::TimesOne, 0), tempGPR);
1594 auto cont8Bit = m_jit.jump();
1595
1596 is16Bit.link(&m_jit);
1597 m_jit.load16(MacroAssembler::BaseIndex(tempGPR, startIndexGPR, MacroAssembler::TimesTwo, 0), tempGPR);
1598
1599 auto bigCharacter = m_jit.branch32(MacroAssembler::Above, tempGPR, TrustedImm32(maxSingleCharacterString));
1600
1601 // 8 bit string values don't need the isASCII check.
1602 cont8Bit.link(&m_jit);
1603
1604 m_jit.lshift32(MacroAssembler::TrustedImm32(sizeof(void*) == 4 ? 2 : 3), tempGPR);
1605 m_jit.addPtr(TrustedImmPtr(vm.smallStrings.singleCharacterStrings()), tempGPR);
1606 m_jit.loadPtr(tempGPR, tempGPR);
1607
1608 addSlowPathGenerator(slowPathCall(bigCharacter, this, operationSingleCharacterString, tempGPR, &vm, tempGPR));
1609
1610 addSlowPathGenerator(slowPathCall(slowCases, this, operationStringSubstr, tempGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), stringGPR, startIndexGPR, tempGPR));
1611
1612 if (endGPR)
1613 addSlowPathGenerator(slowPathCall(isRope, this, operationStringSlice, tempGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), stringGPR, startGPR, *endGPR));
1614 else
1615 addSlowPathGenerator(slowPathCall(isRope, this, operationStringSlice, tempGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), stringGPR, startGPR, TrustedImm32(std::numeric_limits<int32_t>::max())));
1616
1617 doneCases.link(&m_jit);
1618 cellResult(tempGPR, node);
1619}
1620
1621void SpeculativeJIT::compileToLowerCase(Node* node)
1622{
1623 ASSERT(node->op() == ToLowerCase);
1624 SpeculateCellOperand string(this, node->child1());
1625 GPRTemporary temp(this);
1626 GPRTemporary index(this);
1627 GPRTemporary charReg(this);
1628 GPRTemporary length(this);
1629
1630 GPRReg stringGPR = string.gpr();
1631 GPRReg tempGPR = temp.gpr();
1632 GPRReg indexGPR = index.gpr();
1633 GPRReg charGPR = charReg.gpr();
1634 GPRReg lengthGPR = length.gpr();
1635
1636 speculateString(node->child1(), stringGPR);
1637
1638 CCallHelpers::JumpList slowPath;
1639
1640 m_jit.move(TrustedImmPtr(nullptr), indexGPR);
1641
1642 m_jit.loadPtr(MacroAssembler::Address(stringGPR, JSString::offsetOfValue()), tempGPR);
1643 slowPath.append(m_jit.branchIfRopeStringImpl(tempGPR));
1644 slowPath.append(m_jit.branchTest32(
1645 MacroAssembler::Zero, MacroAssembler::Address(tempGPR, StringImpl::flagsOffset()),
1646 MacroAssembler::TrustedImm32(StringImpl::flagIs8Bit())));
1647 m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), lengthGPR);
1648 m_jit.loadPtr(MacroAssembler::Address(tempGPR, StringImpl::dataOffset()), tempGPR);
1649
1650 auto loopStart = m_jit.label();
1651 auto loopDone = m_jit.branch32(CCallHelpers::AboveOrEqual, indexGPR, lengthGPR);
1652 m_jit.load8(MacroAssembler::BaseIndex(tempGPR, indexGPR, MacroAssembler::TimesOne), charGPR);
1653 slowPath.append(m_jit.branchTest32(CCallHelpers::NonZero, charGPR, TrustedImm32(~0x7F)));
1654 m_jit.sub32(TrustedImm32('A'), charGPR);
1655 slowPath.append(m_jit.branch32(CCallHelpers::BelowOrEqual, charGPR, TrustedImm32('Z' - 'A')));
1656
1657 m_jit.add32(TrustedImm32(1), indexGPR);
1658 m_jit.jump().linkTo(loopStart, &m_jit);
1659
1660 slowPath.link(&m_jit);
1661 silentSpillAllRegisters(lengthGPR);
1662 callOperation(operationToLowerCase, lengthGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), stringGPR, indexGPR);
1663 silentFillAllRegisters();
1664 m_jit.exceptionCheck();
1665 auto done = m_jit.jump();
1666
1667 loopDone.link(&m_jit);
1668 m_jit.move(stringGPR, lengthGPR);
1669
1670 done.link(&m_jit);
1671 cellResult(lengthGPR, node);
1672}
1673
1674void SpeculativeJIT::compilePeepHoleInt32Branch(Node* node, Node* branchNode, JITCompiler::RelationalCondition condition)
1675{
1676 BasicBlock* taken = branchNode->branchData()->taken.block;
1677 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
1678
1679 // The branch instruction will branch to the taken block.
1680 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
1681 if (taken == nextBlock()) {
1682 condition = JITCompiler::invert(condition);
1683 BasicBlock* tmp = taken;
1684 taken = notTaken;
1685 notTaken = tmp;
1686 }
1687
1688 if (node->child1()->isInt32Constant()) {
1689 int32_t imm = node->child1()->asInt32();
1690 SpeculateInt32Operand op2(this, node->child2());
1691 branch32(condition, JITCompiler::Imm32(imm), op2.gpr(), taken);
1692 } else if (node->child2()->isInt32Constant()) {
1693 SpeculateInt32Operand op1(this, node->child1());
1694 int32_t imm = node->child2()->asInt32();
1695 branch32(condition, op1.gpr(), JITCompiler::Imm32(imm), taken);
1696 } else {
1697 SpeculateInt32Operand op1(this, node->child1());
1698 SpeculateInt32Operand op2(this, node->child2());
1699 branch32(condition, op1.gpr(), op2.gpr(), taken);
1700 }
1701
1702 jump(notTaken);
1703}
1704
1705// Returns true if the compare is fused with a subsequent branch.
1706bool SpeculativeJIT::compilePeepHoleBranch(Node* node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_JITOperation_GJJ operation)
1707{
1708 // Fused compare & branch.
1709 unsigned branchIndexInBlock = detectPeepHoleBranch();
1710 if (branchIndexInBlock != UINT_MAX) {
1711 Node* branchNode = m_block->at(branchIndexInBlock);
1712
1713 // detectPeepHoleBranch currently only permits the branch to be the very next node,
1714 // so can be no intervening nodes to also reference the compare.
1715 ASSERT(node->adjustedRefCount() == 1);
1716
1717 if (node->isBinaryUseKind(Int32Use))
1718 compilePeepHoleInt32Branch(node, branchNode, condition);
1719#if USE(JSVALUE64)
1720 else if (node->isBinaryUseKind(Int52RepUse))
1721 compilePeepHoleInt52Branch(node, branchNode, condition);
1722#endif // USE(JSVALUE64)
1723 else if (node->isBinaryUseKind(StringUse) || node->isBinaryUseKind(StringIdentUse)) {
1724 // Use non-peephole comparison, for now.
1725 return false;
1726 } else if (node->isBinaryUseKind(DoubleRepUse))
1727 compilePeepHoleDoubleBranch(node, branchNode, doubleCondition);
1728 else if (node->op() == CompareEq) {
1729 if (node->isBinaryUseKind(BooleanUse))
1730 compilePeepHoleBooleanBranch(node, branchNode, condition);
1731 else if (node->isBinaryUseKind(SymbolUse))
1732 compilePeepHoleSymbolEquality(node, branchNode);
1733 else if (node->isBinaryUseKind(ObjectUse))
1734 compilePeepHoleObjectEquality(node, branchNode);
1735 else if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse))
1736 compilePeepHoleObjectToObjectOrOtherEquality(node->child1(), node->child2(), branchNode);
1737 else if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse))
1738 compilePeepHoleObjectToObjectOrOtherEquality(node->child2(), node->child1(), branchNode);
1739 else if (!needsTypeCheck(node->child1(), SpecOther))
1740 nonSpeculativePeepholeBranchNullOrUndefined(node->child2(), branchNode);
1741 else if (!needsTypeCheck(node->child2(), SpecOther))
1742 nonSpeculativePeepholeBranchNullOrUndefined(node->child1(), branchNode);
1743 else {
1744 nonSpeculativePeepholeBranch(node, branchNode, condition, operation);
1745 return true;
1746 }
1747 } else {
1748 nonSpeculativePeepholeBranch(node, branchNode, condition, operation);
1749 return true;
1750 }
1751
1752 use(node->child1());
1753 use(node->child2());
1754 m_indexInBlock = branchIndexInBlock;
1755 m_currentNode = branchNode;
1756 return true;
1757 }
1758 return false;
1759}
1760
1761void SpeculativeJIT::noticeOSRBirth(Node* node)
1762{
1763 if (!node->hasVirtualRegister())
1764 return;
1765
1766 VirtualRegister virtualRegister = node->virtualRegister();
1767 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
1768
1769 info.noticeOSRBirth(*m_stream, node, virtualRegister);
1770}
1771
1772void SpeculativeJIT::compileMovHint(Node* node)
1773{
1774 ASSERT(node->containsMovHint() && node->op() != ZombieHint);
1775
1776 Node* child = node->child1().node();
1777 noticeOSRBirth(child);
1778
1779 m_stream->appendAndLog(VariableEvent::movHint(MinifiedID(child), node->unlinkedLocal()));
1780}
1781
1782void SpeculativeJIT::bail(AbortReason reason)
1783{
1784 if (verboseCompilationEnabled())
1785 dataLog("Bailing compilation.\n");
1786 m_compileOkay = true;
1787 m_jit.abortWithReason(reason, m_lastGeneratedNode);
1788 clearGenerationInfo();
1789}
1790
1791void SpeculativeJIT::compileCurrentBlock()
1792{
1793 ASSERT(m_compileOkay);
1794
1795 if (!m_block)
1796 return;
1797
1798 ASSERT(m_block->isReachable);
1799
1800 m_jit.blockHeads()[m_block->index] = m_jit.label();
1801
1802 if (!m_block->intersectionOfCFAHasVisited) {
1803 // Don't generate code for basic blocks that are unreachable according to CFA.
1804 // But to be sure that nobody has generated a jump to this block, drop in a
1805 // breakpoint here.
1806 m_jit.abortWithReason(DFGUnreachableBasicBlock);
1807 return;
1808 }
1809
1810 if (m_block->isCatchEntrypoint) {
1811 m_jit.addPtr(CCallHelpers::TrustedImm32(-(m_jit.graph().frameRegisterCount() * sizeof(Register))), GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
1812 if (Options::zeroStackFrame())
1813 m_jit.clearStackFrame(GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister, GPRInfo::regT0, m_jit.graph().frameRegisterCount() * sizeof(Register));
1814 m_jit.emitSaveCalleeSaves();
1815 m_jit.emitMaterializeTagCheckRegisters();
1816 m_jit.emitPutToCallFrameHeader(m_jit.codeBlock(), CallFrameSlot::codeBlock);
1817 }
1818
1819 m_stream->appendAndLog(VariableEvent::reset());
1820
1821 m_jit.jitAssertHasValidCallFrame();
1822 m_jit.jitAssertTagsInPlace();
1823 m_jit.jitAssertArgumentCountSane();
1824
1825 m_state.reset();
1826 m_state.beginBasicBlock(m_block);
1827
1828 for (size_t i = m_block->variablesAtHead.size(); i--;) {
1829 int operand = m_block->variablesAtHead.operandForIndex(i);
1830 Node* node = m_block->variablesAtHead[i];
1831 if (!node)
1832 continue; // No need to record dead SetLocal's.
1833
1834 VariableAccessData* variable = node->variableAccessData();
1835 DataFormat format;
1836 if (!node->refCount())
1837 continue; // No need to record dead SetLocal's.
1838 format = dataFormatFor(variable->flushFormat());
1839 m_stream->appendAndLog(
1840 VariableEvent::setLocal(
1841 VirtualRegister(operand),
1842 variable->machineLocal(),
1843 format));
1844 }
1845
1846 m_origin = NodeOrigin();
1847
1848 for (m_indexInBlock = 0; m_indexInBlock < m_block->size(); ++m_indexInBlock) {
1849 m_currentNode = m_block->at(m_indexInBlock);
1850
1851 // We may have hit a contradiction that the CFA was aware of but that the JIT
1852 // didn't cause directly.
1853 if (!m_state.isValid()) {
1854 bail(DFGBailedAtTopOfBlock);
1855 return;
1856 }
1857
1858 m_interpreter.startExecuting();
1859 m_interpreter.executeKnownEdgeTypes(m_currentNode);
1860 m_jit.setForNode(m_currentNode);
1861 m_origin = m_currentNode->origin;
1862 m_lastGeneratedNode = m_currentNode->op();
1863
1864 ASSERT(m_currentNode->shouldGenerate());
1865
1866 if (verboseCompilationEnabled())
1867 dataLogLn("SpeculativeJIT generating Node @", (int)m_currentNode->index(), " (", m_currentNode->origin.semantic.bytecodeIndex().offset(), ") at JIT offset 0x", m_jit.debugOffset());
1868
1869 if (Options::validateDFGExceptionHandling() && (mayExit(m_jit.graph(), m_currentNode) != DoesNotExit || m_currentNode->isTerminal()))
1870 m_jit.jitReleaseAssertNoException(m_jit.vm());
1871
1872 m_jit.pcToCodeOriginMapBuilder().appendItem(m_jit.labelIgnoringWatchpoints(), m_origin.semantic);
1873
1874 compile(m_currentNode);
1875
1876 if (belongsInMinifiedGraph(m_currentNode->op()))
1877 m_minifiedGraph->append(MinifiedNode::fromNode(m_currentNode));
1878
1879#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
1880 m_jit.clearRegisterAllocationOffsets();
1881#endif
1882
1883 if (!m_compileOkay) {
1884 bail(DFGBailedAtEndOfNode);
1885 return;
1886 }
1887
1888 // Make sure that the abstract state is rematerialized for the next node.
1889 m_interpreter.executeEffects(m_indexInBlock);
1890 }
1891
1892 // Perform the most basic verification that children have been used correctly.
1893 if (!ASSERT_DISABLED) {
1894 for (auto& info : m_generationInfo)
1895 RELEASE_ASSERT(!info.alive());
1896 }
1897}
1898
1899// If we are making type predictions about our arguments then
1900// we need to check that they are correct on function entry.
1901void SpeculativeJIT::checkArgumentTypes()
1902{
1903 ASSERT(!m_currentNode);
1904 m_origin = NodeOrigin(CodeOrigin(BytecodeIndex(0)), CodeOrigin(BytecodeIndex(0)), true);
1905
1906 auto& arguments = m_jit.graph().m_rootToArguments.find(m_jit.graph().block(0))->value;
1907 for (int i = 0; i < m_jit.codeBlock()->numParameters(); ++i) {
1908 Node* node = arguments[i];
1909 if (!node) {
1910 // The argument is dead. We don't do any checks for such arguments.
1911 continue;
1912 }
1913
1914 ASSERT(node->op() == SetArgumentDefinitely);
1915 ASSERT(node->shouldGenerate());
1916
1917 VariableAccessData* variableAccessData = node->variableAccessData();
1918 FlushFormat format = variableAccessData->flushFormat();
1919
1920 if (format == FlushedJSValue)
1921 continue;
1922
1923 VirtualRegister virtualRegister = variableAccessData->local();
1924
1925 JSValueSource valueSource = JSValueSource(JITCompiler::addressFor(virtualRegister));
1926
1927#if USE(JSVALUE64)
1928 switch (format) {
1929 case FlushedInt32: {
1930 speculationCheck(BadType, valueSource, node, m_jit.branch64(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::numberTagRegister));
1931 break;
1932 }
1933 case FlushedBoolean: {
1934 GPRTemporary temp(this);
1935 m_jit.load64(JITCompiler::addressFor(virtualRegister), temp.gpr());
1936 m_jit.xor64(TrustedImm32(JSValue::ValueFalse), temp.gpr());
1937 speculationCheck(BadType, valueSource, node, m_jit.branchTest64(MacroAssembler::NonZero, temp.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
1938 break;
1939 }
1940 case FlushedCell: {
1941 speculationCheck(BadType, valueSource, node, m_jit.branchTest64(MacroAssembler::NonZero, JITCompiler::addressFor(virtualRegister), GPRInfo::notCellMaskRegister));
1942 break;
1943 }
1944 default:
1945 RELEASE_ASSERT_NOT_REACHED();
1946 break;
1947 }
1948#else
1949 switch (format) {
1950 case FlushedInt32: {
1951 speculationCheck(BadType, valueSource, node, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)));
1952 break;
1953 }
1954 case FlushedBoolean: {
1955 speculationCheck(BadType, valueSource, node, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)));
1956 break;
1957 }
1958 case FlushedCell: {
1959 speculationCheck(BadType, valueSource, node, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag)));
1960 break;
1961 }
1962 default:
1963 RELEASE_ASSERT_NOT_REACHED();
1964 break;
1965 }
1966#endif
1967 }
1968
1969 m_origin = NodeOrigin();
1970}
1971
1972bool SpeculativeJIT::compile()
1973{
1974 checkArgumentTypes();
1975
1976 ASSERT(!m_currentNode);
1977 for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().numBlocks(); ++blockIndex) {
1978 m_jit.setForBlockIndex(blockIndex);
1979 m_block = m_jit.graph().block(blockIndex);
1980 compileCurrentBlock();
1981 }
1982 linkBranches();
1983 return true;
1984}
1985
1986void SpeculativeJIT::createOSREntries()
1987{
1988 for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().numBlocks(); ++blockIndex) {
1989 BasicBlock* block = m_jit.graph().block(blockIndex);
1990 if (!block)
1991 continue;
1992 if (block->isOSRTarget || block->isCatchEntrypoint) {
1993 // Currently we don't have OSR entry trampolines. We could add them
1994 // here if need be.
1995 m_osrEntryHeads.append(m_jit.blockHeads()[blockIndex]);
1996 }
1997 }
1998}
1999
2000void SpeculativeJIT::linkOSREntries(LinkBuffer& linkBuffer)
2001{
2002 unsigned osrEntryIndex = 0;
2003 for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().numBlocks(); ++blockIndex) {
2004 BasicBlock* block = m_jit.graph().block(blockIndex);
2005 if (!block)
2006 continue;
2007 if (!block->isOSRTarget && !block->isCatchEntrypoint)
2008 continue;
2009 if (block->isCatchEntrypoint) {
2010 auto& argumentsVector = m_jit.graph().m_rootToArguments.find(block)->value;
2011 Vector<FlushFormat> argumentFormats;
2012 argumentFormats.reserveInitialCapacity(argumentsVector.size());
2013 for (Node* setArgument : argumentsVector) {
2014 if (setArgument) {
2015 FlushFormat flushFormat = setArgument->variableAccessData()->flushFormat();
2016 ASSERT(flushFormat == FlushedInt32 || flushFormat == FlushedCell || flushFormat == FlushedBoolean || flushFormat == FlushedJSValue);
2017 argumentFormats.uncheckedAppend(flushFormat);
2018 } else
2019 argumentFormats.uncheckedAppend(DeadFlush);
2020 }
2021 m_jit.noticeCatchEntrypoint(*block, m_osrEntryHeads[osrEntryIndex++], linkBuffer, WTFMove(argumentFormats));
2022 } else {
2023 ASSERT(block->isOSRTarget);
2024 m_jit.noticeOSREntry(*block, m_osrEntryHeads[osrEntryIndex++], linkBuffer);
2025 }
2026 }
2027
2028 m_jit.jitCode()->finalizeOSREntrypoints();
2029 m_jit.jitCode()->common.finalizeCatchEntrypoints();
2030
2031 ASSERT(osrEntryIndex == m_osrEntryHeads.size());
2032
2033 if (verboseCompilationEnabled()) {
2034 DumpContext dumpContext;
2035 dataLog("OSR Entries:\n");
2036 for (OSREntryData& entryData : m_jit.jitCode()->osrEntry)
2037 dataLog(" ", inContext(entryData, &dumpContext), "\n");
2038 if (!dumpContext.isEmpty())
2039 dumpContext.dump(WTF::dataFile());
2040 }
2041}
2042
2043void SpeculativeJIT::compileCheckTraps(Node* node)
2044{
2045 ASSERT(Options::usePollingTraps());
2046 GPRTemporary unused(this);
2047 GPRReg unusedGPR = unused.gpr();
2048
2049 JITCompiler::Jump needTrapHandling = m_jit.branchTest8(JITCompiler::NonZero,
2050 JITCompiler::AbsoluteAddress(m_jit.vm().needTrapHandlingAddress()));
2051
2052 addSlowPathGenerator(slowPathCall(needTrapHandling, this, operationHandleTraps, unusedGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic))));
2053 noResult(node);
2054}
2055
2056void SpeculativeJIT::compileDoublePutByVal(Node* node, SpeculateCellOperand& base, SpeculateStrictInt32Operand& property)
2057{
2058 Edge child3 = m_jit.graph().varArgChild(node, 2);
2059 Edge child4 = m_jit.graph().varArgChild(node, 3);
2060
2061 ArrayMode arrayMode = node->arrayMode();
2062
2063 GPRReg baseReg = base.gpr();
2064 GPRReg propertyReg = property.gpr();
2065
2066 SpeculateDoubleOperand value(this, child3);
2067
2068 FPRReg valueReg = value.fpr();
2069
2070 DFG_TYPE_CHECK(
2071 JSValueRegs(), child3, SpecFullRealNumber,
2072 m_jit.branchIfNaN(valueReg));
2073
2074 if (!m_compileOkay)
2075 return;
2076
2077 StorageOperand storage(this, child4);
2078 GPRReg storageReg = storage.gpr();
2079
2080 if (node->op() == PutByValAlias) {
2081 // Store the value to the array.
2082 GPRReg propertyReg = property.gpr();
2083 FPRReg valueReg = value.fpr();
2084 m_jit.storeDouble(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight));
2085
2086 noResult(m_currentNode);
2087 return;
2088 }
2089
2090 GPRTemporary temporary;
2091 GPRReg temporaryReg = temporaryRegisterForPutByVal(temporary, node);
2092
2093 MacroAssembler::Jump slowCase;
2094
2095 if (arrayMode.isInBounds()) {
2096 speculationCheck(
2097 OutOfBounds, JSValueRegs(), 0,
2098 m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
2099 } else {
2100 MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
2101
2102 slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength()));
2103
2104 if (!arrayMode.isOutOfBounds())
2105 speculationCheck(OutOfBounds, JSValueRegs(), 0, slowCase);
2106
2107 m_jit.add32(TrustedImm32(1), propertyReg, temporaryReg);
2108 m_jit.store32(temporaryReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
2109
2110 inBounds.link(&m_jit);
2111 }
2112
2113 m_jit.storeDouble(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight));
2114
2115 base.use();
2116 property.use();
2117 value.use();
2118 storage.use();
2119
2120 if (arrayMode.isOutOfBounds()) {
2121 addSlowPathGenerator(
2122 slowPathCall(
2123 slowCase, this,
2124 m_jit.isStrictModeFor(node->origin.semantic)
2125 ? (node->op() == PutByValDirect ? operationPutDoubleByValDirectBeyondArrayBoundsStrict : operationPutDoubleByValBeyondArrayBoundsStrict)
2126 : (node->op() == PutByValDirect ? operationPutDoubleByValDirectBeyondArrayBoundsNonStrict : operationPutDoubleByValBeyondArrayBoundsNonStrict),
2127 NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg, valueReg));
2128 }
2129
2130 noResult(m_currentNode, UseChildrenCalledExplicitly);
2131}
2132
2133void SpeculativeJIT::compileGetCharCodeAt(Node* node)
2134{
2135 SpeculateCellOperand string(this, node->child1());
2136 SpeculateStrictInt32Operand index(this, node->child2());
2137 StorageOperand storage(this, node->child3());
2138
2139 GPRReg stringReg = string.gpr();
2140 GPRReg indexReg = index.gpr();
2141 GPRReg storageReg = storage.gpr();
2142
2143 ASSERT(speculationChecked(m_state.forNode(node->child1()).m_type, SpecString));
2144
2145 GPRTemporary scratch(this);
2146 GPRReg scratchReg = scratch.gpr();
2147
2148 m_jit.loadPtr(MacroAssembler::Address(stringReg, JSString::offsetOfValue()), scratchReg);
2149
2150 // unsigned comparison so we can filter out negative indices and indices that are too large
2151 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, indexReg, CCallHelpers::Address(scratchReg, StringImpl::lengthMemoryOffset())));
2152
2153 // Load the character into scratchReg
2154 JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
2155
2156 m_jit.load8(MacroAssembler::BaseIndex(storageReg, indexReg, MacroAssembler::TimesOne, 0), scratchReg);
2157 JITCompiler::Jump cont8Bit = m_jit.jump();
2158
2159 is16Bit.link(&m_jit);
2160
2161 m_jit.load16(MacroAssembler::BaseIndex(storageReg, indexReg, MacroAssembler::TimesTwo, 0), scratchReg);
2162
2163 cont8Bit.link(&m_jit);
2164
2165 int32Result(scratchReg, m_currentNode);
2166}
2167
2168void SpeculativeJIT::compileGetByValOnString(Node* node)
2169{
2170 SpeculateCellOperand base(this, m_graph.child(node, 0));
2171 SpeculateStrictInt32Operand property(this, m_graph.child(node, 1));
2172 StorageOperand storage(this, m_graph.child(node, 2));
2173 GPRReg baseReg = base.gpr();
2174 GPRReg propertyReg = property.gpr();
2175 GPRReg storageReg = storage.gpr();
2176
2177 GPRTemporary scratch(this);
2178 GPRReg scratchReg = scratch.gpr();
2179#if USE(JSVALUE32_64)
2180 GPRTemporary resultTag;
2181 GPRReg resultTagReg = InvalidGPRReg;
2182 if (node->arrayMode().isOutOfBounds()) {
2183 GPRTemporary realResultTag(this);
2184 resultTag.adopt(realResultTag);
2185 resultTagReg = resultTag.gpr();
2186 }
2187#endif
2188
2189 ASSERT(ArrayMode(Array::String, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.child(node, 0))));
2190
2191 // unsigned comparison so we can filter out negative indices and indices that are too large
2192 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), scratchReg);
2193 JITCompiler::Jump outOfBounds = m_jit.branch32(
2194 MacroAssembler::AboveOrEqual, propertyReg,
2195 MacroAssembler::Address(scratchReg, StringImpl::lengthMemoryOffset()));
2196 if (node->arrayMode().isInBounds())
2197 speculationCheck(OutOfBounds, JSValueRegs(), 0, outOfBounds);
2198
2199 // Load the character into scratchReg
2200 JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
2201
2202 m_jit.load8(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne, 0), scratchReg);
2203 JITCompiler::Jump cont8Bit = m_jit.jump();
2204
2205 is16Bit.link(&m_jit);
2206
2207 m_jit.load16(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo, 0), scratchReg);
2208
2209 JITCompiler::Jump bigCharacter =
2210 m_jit.branch32(MacroAssembler::Above, scratchReg, TrustedImm32(maxSingleCharacterString));
2211
2212 // 8 bit string values don't need the isASCII check.
2213 cont8Bit.link(&m_jit);
2214
2215 VM& vm = this->vm();
2216 m_jit.lshift32(MacroAssembler::TrustedImm32(sizeof(void*) == 4 ? 2 : 3), scratchReg);
2217 m_jit.addPtr(TrustedImmPtr(vm.smallStrings.singleCharacterStrings()), scratchReg);
2218 m_jit.loadPtr(scratchReg, scratchReg);
2219
2220 addSlowPathGenerator(
2221 slowPathCall(
2222 bigCharacter, this, operationSingleCharacterString, scratchReg, &vm, scratchReg));
2223
2224 if (node->arrayMode().isOutOfBounds()) {
2225#if USE(JSVALUE32_64)
2226 m_jit.move(TrustedImm32(JSValue::CellTag), resultTagReg);
2227#endif
2228
2229 JSGlobalObject* globalObject = m_jit.globalObjectFor(node->origin.semantic);
2230 Structure* stringPrototypeStructure = globalObject->stringPrototype()->structure(vm);
2231 Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(vm);
2232 WTF::loadLoadFence();
2233
2234 if (globalObject->stringPrototypeChainIsSane()) {
2235 // FIXME: This could be captured using a Speculation mode that means "out-of-bounds
2236 // loads return a trivial value". Something like SaneChainOutOfBounds. This should
2237 // speculate that we don't take negative out-of-bounds, or better yet, it should rely
2238 // on a stringPrototypeChainIsSane() guaranteeing that the prototypes have no negative
2239 // indexed properties either.
2240 // https://bugs.webkit.org/show_bug.cgi?id=144668
2241 m_jit.graph().registerAndWatchStructureTransition(stringPrototypeStructure);
2242 m_jit.graph().registerAndWatchStructureTransition(objectPrototypeStructure);
2243
2244#if USE(JSVALUE64)
2245 addSlowPathGenerator(makeUnique<SaneStringGetByValSlowPathGenerator>(
2246 outOfBounds, this, JSValueRegs(scratchReg), TrustedImmPtr::weakPointer(m_graph, globalObject), baseReg, propertyReg));
2247#else
2248 addSlowPathGenerator(makeUnique<SaneStringGetByValSlowPathGenerator>(
2249 outOfBounds, this, JSValueRegs(resultTagReg, scratchReg), TrustedImmPtr::weakPointer(m_graph, globalObject), baseReg, propertyReg));
2250#endif
2251 } else {
2252#if USE(JSVALUE64)
2253 addSlowPathGenerator(
2254 slowPathCall(
2255 outOfBounds, this, operationGetByValStringInt,
2256 scratchReg, TrustedImmPtr::weakPointer(m_graph, globalObject), baseReg, propertyReg));
2257#else
2258 addSlowPathGenerator(
2259 slowPathCall(
2260 outOfBounds, this, operationGetByValStringInt,
2261 JSValueRegs(resultTagReg, scratchReg), TrustedImmPtr::weakPointer(m_graph, globalObject), baseReg, propertyReg));
2262#endif
2263 }
2264
2265#if USE(JSVALUE64)
2266 jsValueResult(scratchReg, m_currentNode);
2267#else
2268 jsValueResult(resultTagReg, scratchReg, m_currentNode);
2269#endif
2270 } else
2271 cellResult(scratchReg, m_currentNode);
2272}
2273
2274void SpeculativeJIT::compileFromCharCode(Node* node)
2275{
2276 Edge& child = node->child1();
2277 if (child.useKind() == UntypedUse) {
2278 JSValueOperand opr(this, child);
2279 JSValueRegs oprRegs = opr.jsValueRegs();
2280
2281 flushRegisters();
2282 JSValueRegsFlushedCallResult result(this);
2283 JSValueRegs resultRegs = result.regs();
2284 callOperation(operationStringFromCharCodeUntyped, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), oprRegs);
2285 m_jit.exceptionCheck();
2286
2287 jsValueResult(resultRegs, node);
2288 return;
2289 }
2290
2291 SpeculateStrictInt32Operand property(this, child);
2292 GPRReg propertyReg = property.gpr();
2293 GPRTemporary smallStrings(this);
2294 GPRTemporary scratch(this);
2295 GPRReg scratchReg = scratch.gpr();
2296 GPRReg smallStringsReg = smallStrings.gpr();
2297
2298 JITCompiler::JumpList slowCases;
2299 slowCases.append(m_jit.branch32(MacroAssembler::Above, propertyReg, TrustedImm32(maxSingleCharacterString)));
2300 m_jit.move(TrustedImmPtr(vm().smallStrings.singleCharacterStrings()), smallStringsReg);
2301 m_jit.loadPtr(MacroAssembler::BaseIndex(smallStringsReg, propertyReg, MacroAssembler::ScalePtr, 0), scratchReg);
2302
2303 slowCases.append(m_jit.branchTest32(MacroAssembler::Zero, scratchReg));
2304 addSlowPathGenerator(slowPathCall(slowCases, this, operationStringFromCharCode, scratchReg, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), propertyReg));
2305 cellResult(scratchReg, m_currentNode);
2306}
2307
2308GeneratedOperandType SpeculativeJIT::checkGeneratedTypeForToInt32(Node* node)
2309{
2310 VirtualRegister virtualRegister = node->virtualRegister();
2311 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
2312
2313 switch (info.registerFormat()) {
2314 case DataFormatStorage:
2315 RELEASE_ASSERT_NOT_REACHED();
2316
2317 case DataFormatBoolean:
2318 case DataFormatCell:
2319 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
2320 return GeneratedOperandTypeUnknown;
2321
2322 case DataFormatNone:
2323 case DataFormatJSCell:
2324 case DataFormatJS:
2325 case DataFormatJSBoolean:
2326 case DataFormatJSDouble:
2327 return GeneratedOperandJSValue;
2328
2329 case DataFormatJSInt32:
2330 case DataFormatInt32:
2331 return GeneratedOperandInteger;
2332
2333 default:
2334 RELEASE_ASSERT_NOT_REACHED();
2335 return GeneratedOperandTypeUnknown;
2336 }
2337}
2338
2339void SpeculativeJIT::compileValueToInt32(Node* node)
2340{
2341 switch (node->child1().useKind()) {
2342#if USE(JSVALUE64)
2343 case Int52RepUse: {
2344 SpeculateStrictInt52Operand op1(this, node->child1());
2345 GPRTemporary result(this, Reuse, op1);
2346 GPRReg op1GPR = op1.gpr();
2347 GPRReg resultGPR = result.gpr();
2348 m_jit.zeroExtend32ToPtr(op1GPR, resultGPR);
2349 int32Result(resultGPR, node, DataFormatInt32);
2350 return;
2351 }
2352#endif // USE(JSVALUE64)
2353
2354 case DoubleRepUse: {
2355 GPRTemporary result(this);
2356 SpeculateDoubleOperand op1(this, node->child1());
2357 FPRReg fpr = op1.fpr();
2358 GPRReg gpr = result.gpr();
2359#if CPU(ARM64)
2360 if (MacroAssemblerARM64::supportsDoubleToInt32ConversionUsingJavaScriptSemantics())
2361 m_jit.convertDoubleToInt32UsingJavaScriptSemantics(fpr, gpr);
2362 else
2363#endif
2364 {
2365 JITCompiler::Jump notTruncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateFailed);
2366 addSlowPathGenerator(slowPathCall(notTruncatedToInteger, this,
2367 hasSensibleDoubleToInt() ? operationToInt32SensibleSlow : operationToInt32, NeedToSpill, ExceptionCheckRequirement::CheckNotNeeded, gpr, fpr));
2368 }
2369 int32Result(gpr, node);
2370 return;
2371 }
2372
2373 case NumberUse:
2374 case NotCellUse: {
2375 switch (checkGeneratedTypeForToInt32(node->child1().node())) {
2376 case GeneratedOperandInteger: {
2377 SpeculateInt32Operand op1(this, node->child1(), ManualOperandSpeculation);
2378 GPRTemporary result(this, Reuse, op1);
2379 m_jit.move(op1.gpr(), result.gpr());
2380 int32Result(result.gpr(), node, op1.format());
2381 return;
2382 }
2383 case GeneratedOperandJSValue: {
2384 GPRTemporary result(this);
2385#if USE(JSVALUE64)
2386 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
2387
2388 GPRReg gpr = op1.gpr();
2389 GPRReg resultGpr = result.gpr();
2390 FPRTemporary tempFpr(this);
2391 FPRReg fpr = tempFpr.fpr();
2392
2393 JITCompiler::Jump isInteger = m_jit.branchIfInt32(gpr);
2394 JITCompiler::JumpList converted;
2395
2396 if (node->child1().useKind() == NumberUse) {
2397 DFG_TYPE_CHECK(
2398 JSValueRegs(gpr), node->child1(), SpecBytecodeNumber,
2399 m_jit.branchIfNotNumber(gpr));
2400 } else {
2401 JITCompiler::Jump isNumber = m_jit.branchIfNumber(gpr);
2402
2403 DFG_TYPE_CHECK(
2404 JSValueRegs(gpr), node->child1(), ~SpecCellCheck, m_jit.branchIfCell(JSValueRegs(gpr)));
2405
2406 // It's not a cell: so true turns into 1 and all else turns into 0.
2407 m_jit.compare64(JITCompiler::Equal, gpr, TrustedImm32(JSValue::ValueTrue), resultGpr);
2408 converted.append(m_jit.jump());
2409
2410 isNumber.link(&m_jit);
2411 }
2412
2413 // First, if we get here we have a double encoded as a JSValue
2414 unboxDouble(gpr, resultGpr, fpr);
2415#if CPU(ARM64)
2416 if (MacroAssemblerARM64::supportsDoubleToInt32ConversionUsingJavaScriptSemantics())
2417 m_jit.convertDoubleToInt32UsingJavaScriptSemantics(fpr, resultGpr);
2418 else
2419#endif
2420 {
2421 silentSpillAllRegisters(resultGpr);
2422 callOperation(operationToInt32, resultGpr, fpr);
2423 silentFillAllRegisters();
2424 }
2425
2426 converted.append(m_jit.jump());
2427
2428 isInteger.link(&m_jit);
2429 m_jit.zeroExtend32ToPtr(gpr, resultGpr);
2430
2431 converted.link(&m_jit);
2432#else
2433 Node* childNode = node->child1().node();
2434 VirtualRegister virtualRegister = childNode->virtualRegister();
2435 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
2436
2437 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
2438
2439 GPRReg payloadGPR = op1.payloadGPR();
2440 GPRReg resultGpr = result.gpr();
2441
2442 JITCompiler::JumpList converted;
2443
2444 if (info.registerFormat() == DataFormatJSInt32)
2445 m_jit.move(payloadGPR, resultGpr);
2446 else {
2447 GPRReg tagGPR = op1.tagGPR();
2448 FPRTemporary tempFpr(this);
2449 FPRReg fpr = tempFpr.fpr();
2450 FPRTemporary scratch(this);
2451
2452 JITCompiler::Jump isInteger = m_jit.branchIfInt32(tagGPR);
2453
2454 if (node->child1().useKind() == NumberUse) {
2455 DFG_TYPE_CHECK(
2456 op1.jsValueRegs(), node->child1(), SpecBytecodeNumber,
2457 m_jit.branch32(
2458 MacroAssembler::AboveOrEqual, tagGPR,
2459 TrustedImm32(JSValue::LowestTag)));
2460 } else {
2461 JITCompiler::Jump isNumber = m_jit.branch32(MacroAssembler::Below, tagGPR, TrustedImm32(JSValue::LowestTag));
2462
2463 DFG_TYPE_CHECK(
2464 op1.jsValueRegs(), node->child1(), ~SpecCell,
2465 m_jit.branchIfCell(op1.jsValueRegs()));
2466
2467 // It's not a cell: so true turns into 1 and all else turns into 0.
2468 JITCompiler::Jump isBoolean = m_jit.branchIfBoolean(tagGPR, InvalidGPRReg);
2469 m_jit.move(TrustedImm32(0), resultGpr);
2470 converted.append(m_jit.jump());
2471
2472 isBoolean.link(&m_jit);
2473 m_jit.move(payloadGPR, resultGpr);
2474 converted.append(m_jit.jump());
2475
2476 isNumber.link(&m_jit);
2477 }
2478
2479 unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr());
2480
2481 silentSpillAllRegisters(resultGpr);
2482 callOperation(operationToInt32, resultGpr, fpr);
2483 silentFillAllRegisters();
2484
2485 converted.append(m_jit.jump());
2486
2487 isInteger.link(&m_jit);
2488 m_jit.move(payloadGPR, resultGpr);
2489
2490 converted.link(&m_jit);
2491 }
2492#endif
2493 int32Result(resultGpr, node);
2494 return;
2495 }
2496 case GeneratedOperandTypeUnknown:
2497 RELEASE_ASSERT(!m_compileOkay);
2498 return;
2499 }
2500 RELEASE_ASSERT_NOT_REACHED();
2501 return;
2502 }
2503
2504 default:
2505 ASSERT(!m_compileOkay);
2506 return;
2507 }
2508}
2509
2510void SpeculativeJIT::compileUInt32ToNumber(Node* node)
2511{
2512 if (doesOverflow(node->arithMode())) {
2513 if (enableInt52()) {
2514 SpeculateInt32Operand op1(this, node->child1());
2515 GPRTemporary result(this, Reuse, op1);
2516 m_jit.zeroExtend32ToPtr(op1.gpr(), result.gpr());
2517 strictInt52Result(result.gpr(), node);
2518 return;
2519 }
2520 SpeculateInt32Operand op1(this, node->child1());
2521 FPRTemporary result(this);
2522
2523 GPRReg inputGPR = op1.gpr();
2524 FPRReg outputFPR = result.fpr();
2525
2526 m_jit.convertInt32ToDouble(inputGPR, outputFPR);
2527
2528 JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, inputGPR, TrustedImm32(0));
2529 m_jit.addDouble(JITCompiler::AbsoluteAddress(&AssemblyHelpers::twoToThe32), outputFPR);
2530 positive.link(&m_jit);
2531
2532 doubleResult(outputFPR, node);
2533 return;
2534 }
2535
2536 RELEASE_ASSERT(node->arithMode() == Arith::CheckOverflow);
2537
2538 SpeculateInt32Operand op1(this, node->child1());
2539 GPRTemporary result(this);
2540
2541 m_jit.move(op1.gpr(), result.gpr());
2542
2543 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, result.gpr(), TrustedImm32(0)));
2544
2545 int32Result(result.gpr(), node, op1.format());
2546}
2547
2548void SpeculativeJIT::compileDoubleAsInt32(Node* node)
2549{
2550 SpeculateDoubleOperand op1(this, node->child1());
2551 FPRTemporary scratch(this);
2552 GPRTemporary result(this);
2553
2554 FPRReg valueFPR = op1.fpr();
2555 FPRReg scratchFPR = scratch.fpr();
2556 GPRReg resultGPR = result.gpr();
2557
2558 JITCompiler::JumpList failureCases;
2559 RELEASE_ASSERT(shouldCheckOverflow(node->arithMode()));
2560 m_jit.branchConvertDoubleToInt32(
2561 valueFPR, resultGPR, failureCases, scratchFPR,
2562 shouldCheckNegativeZero(node->arithMode()));
2563 speculationCheck(Overflow, JSValueRegs(), 0, failureCases);
2564
2565 int32Result(resultGPR, node);
2566}
2567
2568void SpeculativeJIT::compileDoubleRep(Node* node)
2569{
2570 switch (node->child1().useKind()) {
2571 case RealNumberUse: {
2572 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
2573 FPRTemporary result(this);
2574
2575 JSValueRegs op1Regs = op1.jsValueRegs();
2576 FPRReg resultFPR = result.fpr();
2577
2578#if USE(JSVALUE64)
2579 GPRTemporary temp(this);
2580 GPRReg tempGPR = temp.gpr();
2581 m_jit.unboxDoubleWithoutAssertions(op1Regs.gpr(), tempGPR, resultFPR);
2582#else
2583 FPRTemporary temp(this);
2584 FPRReg tempFPR = temp.fpr();
2585 unboxDouble(op1Regs.tagGPR(), op1Regs.payloadGPR(), resultFPR, tempFPR);
2586#endif
2587
2588 JITCompiler::Jump done = m_jit.branchIfNotNaN(resultFPR);
2589
2590 DFG_TYPE_CHECK(
2591 op1Regs, node->child1(), SpecBytecodeRealNumber, m_jit.branchIfNotInt32(op1Regs));
2592 m_jit.convertInt32ToDouble(op1Regs.payloadGPR(), resultFPR);
2593
2594 done.link(&m_jit);
2595
2596 doubleResult(resultFPR, node);
2597 return;
2598 }
2599
2600 case NotCellUse:
2601 case NumberUse: {
2602 SpeculatedType possibleTypes = m_state.forNode(node->child1()).m_type;
2603 if (isInt32Speculation(possibleTypes)) {
2604 SpeculateInt32Operand op1(this, node->child1(), ManualOperandSpeculation);
2605 FPRTemporary result(this);
2606 m_jit.convertInt32ToDouble(op1.gpr(), result.fpr());
2607 doubleResult(result.fpr(), node);
2608 return;
2609 }
2610
2611 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
2612 FPRTemporary result(this);
2613
2614#if USE(JSVALUE64)
2615 GPRTemporary temp(this);
2616
2617 GPRReg op1GPR = op1.gpr();
2618 GPRReg tempGPR = temp.gpr();
2619 FPRReg resultFPR = result.fpr();
2620 JITCompiler::JumpList done;
2621
2622 JITCompiler::Jump isInteger = m_jit.branchIfInt32(op1GPR);
2623
2624 if (node->child1().useKind() == NotCellUse) {
2625 JITCompiler::Jump isNumber = m_jit.branchIfNumber(op1GPR);
2626 JITCompiler::Jump isUndefined = m_jit.branchIfUndefined(op1GPR);
2627
2628 static constexpr double zero = 0;
2629 m_jit.loadDouble(TrustedImmPtr(&zero), resultFPR);
2630
2631 JITCompiler::Jump isNull = m_jit.branchIfNull(op1GPR);
2632 done.append(isNull);
2633
2634 DFG_TYPE_CHECK(JSValueRegs(op1GPR), node->child1(), ~SpecCellCheck,
2635 m_jit.branchTest64(JITCompiler::Zero, op1GPR, TrustedImm32(JSValue::BoolTag)));
2636
2637 JITCompiler::Jump isFalse = m_jit.branch64(JITCompiler::Equal, op1GPR, TrustedImm64(JSValue::ValueFalse));
2638 static constexpr double one = 1;
2639 m_jit.loadDouble(TrustedImmPtr(&one), resultFPR);
2640 done.append(m_jit.jump());
2641 done.append(isFalse);
2642
2643 isUndefined.link(&m_jit);
2644 static const double NaN = PNaN;
2645 m_jit.loadDouble(TrustedImmPtr(&NaN), resultFPR);
2646 done.append(m_jit.jump());
2647
2648 isNumber.link(&m_jit);
2649 } else if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) {
2650 typeCheck(
2651 JSValueRegs(op1GPR), node->child1(), SpecBytecodeNumber,
2652 m_jit.branchIfNotNumber(op1GPR));
2653 }
2654
2655 unboxDouble(op1GPR, tempGPR, resultFPR);
2656 done.append(m_jit.jump());
2657
2658 isInteger.link(&m_jit);
2659 m_jit.convertInt32ToDouble(op1GPR, resultFPR);
2660 done.link(&m_jit);
2661#else // USE(JSVALUE64) -> this is the 32_64 case
2662 FPRTemporary temp(this);
2663
2664 GPRReg op1TagGPR = op1.tagGPR();
2665 GPRReg op1PayloadGPR = op1.payloadGPR();
2666 FPRReg tempFPR = temp.fpr();
2667 FPRReg resultFPR = result.fpr();
2668 JITCompiler::JumpList done;
2669
2670 JITCompiler::Jump isInteger = m_jit.branchIfInt32(op1TagGPR);
2671
2672 if (node->child1().useKind() == NotCellUse) {
2673 JITCompiler::Jump isNumber = m_jit.branch32(JITCompiler::Below, op1TagGPR, JITCompiler::TrustedImm32(JSValue::LowestTag + 1));
2674 JITCompiler::Jump isUndefined = m_jit.branchIfUndefined(op1TagGPR);
2675
2676 static constexpr double zero = 0;
2677 m_jit.loadDouble(TrustedImmPtr(&zero), resultFPR);
2678
2679 JITCompiler::Jump isNull = m_jit.branchIfNull(op1TagGPR);
2680 done.append(isNull);
2681
2682 DFG_TYPE_CHECK(JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), ~SpecCell, m_jit.branchIfNotBoolean(op1TagGPR, InvalidGPRReg));
2683
2684 JITCompiler::Jump isFalse = m_jit.branchTest32(JITCompiler::Zero, op1PayloadGPR, TrustedImm32(1));
2685 static constexpr double one = 1;
2686 m_jit.loadDouble(TrustedImmPtr(&one), resultFPR);
2687 done.append(m_jit.jump());
2688 done.append(isFalse);
2689
2690 isUndefined.link(&m_jit);
2691 static const double NaN = PNaN;
2692 m_jit.loadDouble(TrustedImmPtr(&NaN), resultFPR);
2693 done.append(m_jit.jump());
2694
2695 isNumber.link(&m_jit);
2696 } else if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) {
2697 // This check fails with Int32Tag, but it is OK since Int32 case is already excluded.
2698 typeCheck(
2699 JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecBytecodeNumber,
2700 m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)));
2701 }
2702
2703 unboxDouble(op1TagGPR, op1PayloadGPR, resultFPR, tempFPR);
2704 done.append(m_jit.jump());
2705
2706 isInteger.link(&m_jit);
2707 m_jit.convertInt32ToDouble(op1PayloadGPR, resultFPR);
2708 done.link(&m_jit);
2709#endif // USE(JSVALUE64)
2710
2711 doubleResult(resultFPR, node);
2712 return;
2713 }
2714
2715#if USE(JSVALUE64)
2716 case Int52RepUse: {
2717 SpeculateStrictInt52Operand value(this, node->child1());
2718 FPRTemporary result(this);
2719
2720 GPRReg valueGPR = value.gpr();
2721 FPRReg resultFPR = result.fpr();
2722
2723 m_jit.convertInt64ToDouble(valueGPR, resultFPR);
2724
2725 doubleResult(resultFPR, node);
2726 return;
2727 }
2728#endif // USE(JSVALUE64)
2729
2730 default:
2731 RELEASE_ASSERT_NOT_REACHED();
2732 return;
2733 }
2734}
2735
2736void SpeculativeJIT::compileValueRep(Node* node)
2737{
2738 switch (node->child1().useKind()) {
2739 case DoubleRepUse: {
2740 SpeculateDoubleOperand value(this, node->child1());
2741 JSValueRegsTemporary result(this);
2742
2743 FPRReg valueFPR = value.fpr();
2744 JSValueRegs resultRegs = result.regs();
2745
2746 // It's very tempting to in-place filter the value to indicate that it's not impure NaN
2747 // anymore. Unfortunately, this would be unsound. If it's a GetLocal or if the value was
2748 // subject to a prior SetLocal, filtering the value would imply that the corresponding
2749 // local was purified.
2750 if (needsTypeCheck(node->child1(), ~SpecDoubleImpureNaN))
2751 m_jit.purifyNaN(valueFPR);
2752
2753 boxDouble(valueFPR, resultRegs);
2754
2755 jsValueResult(resultRegs, node);
2756 return;
2757 }
2758
2759#if USE(JSVALUE64)
2760 case Int52RepUse: {
2761 SpeculateStrictInt52Operand value(this, node->child1());
2762 GPRTemporary result(this);
2763
2764 GPRReg valueGPR = value.gpr();
2765 GPRReg resultGPR = result.gpr();
2766
2767 boxInt52(valueGPR, resultGPR, DataFormatStrictInt52);
2768
2769 jsValueResult(resultGPR, node);
2770 return;
2771 }
2772#endif // USE(JSVALUE64)
2773
2774 default:
2775 RELEASE_ASSERT_NOT_REACHED();
2776 return;
2777 }
2778}
2779
2780static double clampDoubleToByte(double d)
2781{
2782 d += 0.5;
2783 if (!(d > 0))
2784 d = 0;
2785 else if (d > 255)
2786 d = 255;
2787 return d;
2788}
2789
2790static void compileClampIntegerToByte(JITCompiler& jit, GPRReg result)
2791{
2792 MacroAssembler::Jump inBounds = jit.branch32(MacroAssembler::BelowOrEqual, result, JITCompiler::TrustedImm32(0xff));
2793 MacroAssembler::Jump tooBig = jit.branch32(MacroAssembler::GreaterThan, result, JITCompiler::TrustedImm32(0xff));
2794 jit.xorPtr(result, result);
2795 MacroAssembler::Jump clamped = jit.jump();
2796 tooBig.link(&jit);
2797 jit.move(JITCompiler::TrustedImm32(255), result);
2798 clamped.link(&jit);
2799 inBounds.link(&jit);
2800}
2801
2802static void compileClampDoubleToByte(JITCompiler& jit, GPRReg result, FPRReg source, FPRReg scratch)
2803{
2804 // Unordered compare so we pick up NaN
2805 static constexpr double zero = 0;
2806 static constexpr double byteMax = 255;
2807 static constexpr double half = 0.5;
2808 jit.loadDouble(JITCompiler::TrustedImmPtr(&zero), scratch);
2809 MacroAssembler::Jump tooSmall = jit.branchDouble(MacroAssembler::DoubleLessThanOrEqualOrUnordered, source, scratch);
2810 jit.loadDouble(JITCompiler::TrustedImmPtr(&byteMax), scratch);
2811 MacroAssembler::Jump tooBig = jit.branchDouble(MacroAssembler::DoubleGreaterThan, source, scratch);
2812
2813 jit.loadDouble(JITCompiler::TrustedImmPtr(&half), scratch);
2814 // FIXME: This should probably just use a floating point round!
2815 // https://bugs.webkit.org/show_bug.cgi?id=72054
2816 jit.addDouble(source, scratch);
2817 jit.truncateDoubleToInt32(scratch, result);
2818 MacroAssembler::Jump truncatedInt = jit.jump();
2819
2820 tooSmall.link(&jit);
2821 jit.xorPtr(result, result);
2822 MacroAssembler::Jump zeroed = jit.jump();
2823
2824 tooBig.link(&jit);
2825 jit.move(JITCompiler::TrustedImm32(255), result);
2826
2827 truncatedInt.link(&jit);
2828 zeroed.link(&jit);
2829
2830}
2831
2832JITCompiler::Jump SpeculativeJIT::jumpForTypedArrayOutOfBounds(Node* node, GPRReg baseGPR, GPRReg indexGPR)
2833{
2834 if (node->op() == PutByValAlias)
2835 return JITCompiler::Jump();
2836 JSArrayBufferView* view = m_jit.graph().tryGetFoldableView(
2837 m_state.forNode(m_jit.graph().child(node, 0)).m_value, node->arrayMode());
2838 if (view) {
2839 uint32_t length = view->length();
2840 Node* indexNode = m_jit.graph().child(node, 1).node();
2841 if (indexNode->isInt32Constant() && indexNode->asUInt32() < length)
2842 return JITCompiler::Jump();
2843 return m_jit.branch32(
2844 MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Imm32(length));
2845 }
2846 return m_jit.branch32(
2847 MacroAssembler::AboveOrEqual, indexGPR,
2848 MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfLength()));
2849}
2850
2851void SpeculativeJIT::emitTypedArrayBoundsCheck(Node* node, GPRReg baseGPR, GPRReg indexGPR)
2852{
2853 JITCompiler::Jump jump = jumpForTypedArrayOutOfBounds(node, baseGPR, indexGPR);
2854 if (!jump.isSet())
2855 return;
2856 speculationCheck(OutOfBounds, JSValueRegs(), 0, jump);
2857}
2858
2859JITCompiler::Jump SpeculativeJIT::jumpForTypedArrayIsNeuteredIfOutOfBounds(Node* node, GPRReg base, JITCompiler::Jump outOfBounds)
2860{
2861 JITCompiler::Jump done;
2862 if (outOfBounds.isSet()) {
2863 done = m_jit.jump();
2864 if (node->arrayMode().isInBounds())
2865 speculationCheck(OutOfBounds, JSValueSource(), 0, outOfBounds);
2866 else {
2867 outOfBounds.link(&m_jit);
2868
2869 JITCompiler::Jump notWasteful = m_jit.branch32(
2870 MacroAssembler::NotEqual,
2871 MacroAssembler::Address(base, JSArrayBufferView::offsetOfMode()),
2872 TrustedImm32(WastefulTypedArray));
2873
2874 JITCompiler::Jump hasNullVector;
2875#if CPU(ARM64E)
2876 {
2877 GPRReg scratch = m_jit.scratchRegister();
2878 DisallowMacroScratchRegisterUsage disallowScratch(m_jit);
2879
2880 m_jit.loadPtr(MacroAssembler::Address(base, JSArrayBufferView::offsetOfVector()), scratch);
2881 m_jit.removeArrayPtrTag(scratch);
2882 hasNullVector = m_jit.branchTestPtr(MacroAssembler::Zero, scratch);
2883 }
2884#else // CPU(ARM64E)
2885 hasNullVector = m_jit.branchTestPtr(
2886 MacroAssembler::Zero,
2887 MacroAssembler::Address(base, JSArrayBufferView::offsetOfVector()));
2888#endif
2889 speculationCheck(Uncountable, JSValueSource(), node, hasNullVector);
2890 notWasteful.link(&m_jit);
2891 }
2892 }
2893 return done;
2894}
2895
2896void SpeculativeJIT::loadFromIntTypedArray(GPRReg storageReg, GPRReg propertyReg, GPRReg resultReg, TypedArrayType type)
2897{
2898 switch (elementSize(type)) {
2899 case 1:
2900 if (isSigned(type))
2901 m_jit.load8SignedExtendTo32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne), resultReg);
2902 else
2903 m_jit.load8(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne), resultReg);
2904 break;
2905 case 2:
2906 if (isSigned(type))
2907 m_jit.load16SignedExtendTo32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo), resultReg);
2908 else
2909 m_jit.load16(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo), resultReg);
2910 break;
2911 case 4:
2912 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesFour), resultReg);
2913 break;
2914 default:
2915 CRASH();
2916 }
2917}
2918
2919void SpeculativeJIT::setIntTypedArrayLoadResult(Node* node, GPRReg resultReg, TypedArrayType type, bool canSpeculate)
2920{
2921 if (elementSize(type) < 4 || isSigned(type)) {
2922 int32Result(resultReg, node);
2923 return;
2924 }
2925
2926 ASSERT(elementSize(type) == 4 && !isSigned(type));
2927 if (node->shouldSpeculateInt32() && canSpeculate) {
2928 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, resultReg, TrustedImm32(0)));
2929 int32Result(resultReg, node);
2930 return;
2931 }
2932
2933#if USE(JSVALUE64)
2934 if (node->shouldSpeculateInt52()) {
2935 ASSERT(enableInt52());
2936 m_jit.zeroExtend32ToPtr(resultReg, resultReg);
2937 strictInt52Result(resultReg, node);
2938 return;
2939 }
2940#endif
2941
2942 FPRTemporary fresult(this);
2943 m_jit.convertInt32ToDouble(resultReg, fresult.fpr());
2944 JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, resultReg, TrustedImm32(0));
2945 m_jit.addDouble(JITCompiler::AbsoluteAddress(&AssemblyHelpers::twoToThe32), fresult.fpr());
2946 positive.link(&m_jit);
2947 doubleResult(fresult.fpr(), node);
2948}
2949
2950void SpeculativeJIT::compileGetByValOnIntTypedArray(Node* node, TypedArrayType type)
2951{
2952 ASSERT(isInt(type));
2953
2954 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
2955 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
2956 StorageOperand storage(this, m_graph.varArgChild(node, 2));
2957
2958 GPRReg baseReg = base.gpr();
2959 GPRReg propertyReg = property.gpr();
2960 GPRReg storageReg = storage.gpr();
2961
2962 GPRTemporary result(this);
2963 GPRReg resultReg = result.gpr();
2964
2965 emitTypedArrayBoundsCheck(node, baseReg, propertyReg);
2966 loadFromIntTypedArray(storageReg, propertyReg, resultReg, type);
2967 bool canSpeculate = true;
2968 setIntTypedArrayLoadResult(node, resultReg, type, canSpeculate);
2969}
2970
2971bool SpeculativeJIT::getIntTypedArrayStoreOperand(
2972 GPRTemporary& value,
2973 GPRReg property,
2974#if USE(JSVALUE32_64)
2975 GPRTemporary& propertyTag,
2976 GPRTemporary& valueTag,
2977#endif
2978 Edge valueUse, JITCompiler::JumpList& slowPathCases, bool isClamped)
2979{
2980 bool isAppropriateConstant = false;
2981 if (valueUse->isConstant()) {
2982 JSValue jsValue = valueUse->asJSValue();
2983 SpeculatedType expectedType = typeFilterFor(valueUse.useKind());
2984 SpeculatedType actualType = speculationFromValue(jsValue);
2985 isAppropriateConstant = (expectedType | actualType) == expectedType;
2986 }
2987
2988 if (isAppropriateConstant) {
2989 JSValue jsValue = valueUse->asJSValue();
2990 if (!jsValue.isNumber()) {
2991 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
2992 return false;
2993 }
2994 double d = jsValue.asNumber();
2995 if (isClamped)
2996 d = clampDoubleToByte(d);
2997 GPRTemporary scratch(this);
2998 GPRReg scratchReg = scratch.gpr();
2999 m_jit.move(Imm32(toInt32(d)), scratchReg);
3000 value.adopt(scratch);
3001 } else {
3002 switch (valueUse.useKind()) {
3003 case Int32Use: {
3004 SpeculateInt32Operand valueOp(this, valueUse);
3005 GPRTemporary scratch(this);
3006 GPRReg scratchReg = scratch.gpr();
3007 m_jit.move(valueOp.gpr(), scratchReg);
3008 if (isClamped)
3009 compileClampIntegerToByte(m_jit, scratchReg);
3010 value.adopt(scratch);
3011 break;
3012 }
3013
3014#if USE(JSVALUE64)
3015 case Int52RepUse: {
3016 SpeculateStrictInt52Operand valueOp(this, valueUse);
3017 GPRTemporary scratch(this);
3018 GPRReg scratchReg = scratch.gpr();
3019 m_jit.move(valueOp.gpr(), scratchReg);
3020 if (isClamped) {
3021 MacroAssembler::Jump inBounds = m_jit.branch64(
3022 MacroAssembler::BelowOrEqual, scratchReg, JITCompiler::TrustedImm64(0xff));
3023 MacroAssembler::Jump tooBig = m_jit.branch64(
3024 MacroAssembler::GreaterThan, scratchReg, JITCompiler::TrustedImm64(0xff));
3025 m_jit.move(TrustedImm32(0), scratchReg);
3026 MacroAssembler::Jump clamped = m_jit.jump();
3027 tooBig.link(&m_jit);
3028 m_jit.move(JITCompiler::TrustedImm32(255), scratchReg);
3029 clamped.link(&m_jit);
3030 inBounds.link(&m_jit);
3031 }
3032 value.adopt(scratch);
3033 break;
3034 }
3035#endif // USE(JSVALUE64)
3036
3037 case DoubleRepUse: {
3038 RELEASE_ASSERT(!isAtomicsIntrinsic(m_currentNode->op()));
3039 if (isClamped) {
3040 SpeculateDoubleOperand valueOp(this, valueUse);
3041 GPRTemporary result(this);
3042 FPRTemporary floatScratch(this);
3043 FPRReg fpr = valueOp.fpr();
3044 GPRReg gpr = result.gpr();
3045 compileClampDoubleToByte(m_jit, gpr, fpr, floatScratch.fpr());
3046 value.adopt(result);
3047 } else {
3048#if USE(JSVALUE32_64)
3049 GPRTemporary realPropertyTag(this);
3050 propertyTag.adopt(realPropertyTag);
3051 GPRReg propertyTagGPR = propertyTag.gpr();
3052
3053 GPRTemporary realValueTag(this);
3054 valueTag.adopt(realValueTag);
3055 GPRReg valueTagGPR = valueTag.gpr();
3056#endif
3057 SpeculateDoubleOperand valueOp(this, valueUse);
3058 GPRTemporary result(this);
3059 FPRReg fpr = valueOp.fpr();
3060 GPRReg gpr = result.gpr();
3061 MacroAssembler::Jump notNaN = m_jit.branchIfNotNaN(fpr);
3062 m_jit.xorPtr(gpr, gpr);
3063 MacroAssembler::JumpList fixed(m_jit.jump());
3064 notNaN.link(&m_jit);
3065
3066 fixed.append(m_jit.branchTruncateDoubleToInt32(
3067 fpr, gpr, MacroAssembler::BranchIfTruncateSuccessful));
3068
3069#if USE(JSVALUE64)
3070 m_jit.or64(GPRInfo::numberTagRegister, property);
3071 boxDouble(fpr, gpr);
3072#else
3073 UNUSED_PARAM(property);
3074 m_jit.move(TrustedImm32(JSValue::Int32Tag), propertyTagGPR);
3075 boxDouble(fpr, valueTagGPR, gpr);
3076#endif
3077 slowPathCases.append(m_jit.jump());
3078
3079 fixed.link(&m_jit);
3080 value.adopt(result);
3081 }
3082 break;
3083 }
3084
3085 default:
3086 RELEASE_ASSERT_NOT_REACHED();
3087 break;
3088 }
3089 }
3090 return true;
3091}
3092
3093void SpeculativeJIT::compilePutByValForIntTypedArray(GPRReg base, GPRReg property, Node* node, TypedArrayType type)
3094{
3095 ASSERT(isInt(type));
3096
3097 StorageOperand storage(this, m_jit.graph().varArgChild(node, 3));
3098 GPRReg storageReg = storage.gpr();
3099
3100 Edge valueUse = m_jit.graph().varArgChild(node, 2);
3101
3102 GPRTemporary value;
3103#if USE(JSVALUE32_64)
3104 GPRTemporary propertyTag;
3105 GPRTemporary valueTag;
3106#endif
3107
3108 JITCompiler::JumpList slowPathCases;
3109
3110 bool result = getIntTypedArrayStoreOperand(
3111 value, property,
3112#if USE(JSVALUE32_64)
3113 propertyTag, valueTag,
3114#endif
3115 valueUse, slowPathCases, isClamped(type));
3116 if (!result) {
3117 noResult(node);
3118 return;
3119 }
3120
3121 GPRReg valueGPR = value.gpr();
3122#if USE(JSVALUE32_64)
3123 GPRReg propertyTagGPR = propertyTag.gpr();
3124 GPRReg valueTagGPR = valueTag.gpr();
3125#endif
3126
3127 ASSERT_UNUSED(valueGPR, valueGPR != property);
3128 ASSERT(valueGPR != base);
3129 ASSERT(valueGPR != storageReg);
3130 JITCompiler::Jump outOfBounds = jumpForTypedArrayOutOfBounds(node, base, property);
3131
3132 switch (elementSize(type)) {
3133 case 1:
3134 m_jit.store8(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesOne));
3135 break;
3136 case 2:
3137 m_jit.store16(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesTwo));
3138 break;
3139 case 4:
3140 m_jit.store32(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesFour));
3141 break;
3142 default:
3143 CRASH();
3144 }
3145
3146 JITCompiler::Jump done = jumpForTypedArrayIsNeuteredIfOutOfBounds(node, base, outOfBounds);
3147 if (done.isSet())
3148 done.link(&m_jit);
3149
3150 if (!slowPathCases.empty()) {
3151#if USE(JSVALUE64)
3152 if (node->op() == PutByValDirect) {
3153 addSlowPathGenerator(slowPathCall(
3154 slowPathCases, this,
3155 m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValDirectStrict : operationPutByValDirectNonStrict,
3156 NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), base, property, valueGPR));
3157 } else {
3158 addSlowPathGenerator(slowPathCall(
3159 slowPathCases, this,
3160 m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValStrict : operationPutByValNonStrict,
3161 NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), base, property, valueGPR));
3162 }
3163#else // not USE(JSVALUE64)
3164 if (node->op() == PutByValDirect) {
3165 addSlowPathGenerator(slowPathCall(
3166 slowPathCases, this,
3167 m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValDirectCellStrict : operationPutByValDirectCellNonStrict,
3168 NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), base, JSValueRegs(propertyTagGPR, property), JSValueRegs(valueTagGPR, valueGPR)));
3169 } else {
3170 addSlowPathGenerator(slowPathCall(
3171 slowPathCases, this,
3172 m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValCellStrict : operationPutByValCellNonStrict,
3173 NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), base, JSValueRegs(propertyTagGPR, property), JSValueRegs(valueTagGPR, valueGPR)));
3174 }
3175#endif
3176 }
3177
3178 noResult(node);
3179}
3180
3181void SpeculativeJIT::compileGetByValOnFloatTypedArray(Node* node, TypedArrayType type)
3182{
3183 ASSERT(isFloat(type));
3184
3185 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
3186 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
3187 StorageOperand storage(this, m_graph.varArgChild(node, 2));
3188
3189 GPRReg baseReg = base.gpr();
3190 GPRReg propertyReg = property.gpr();
3191 GPRReg storageReg = storage.gpr();
3192
3193 FPRTemporary result(this);
3194 FPRReg resultReg = result.fpr();
3195 emitTypedArrayBoundsCheck(node, baseReg, propertyReg);
3196 switch (elementSize(type)) {
3197 case 4:
3198 m_jit.loadFloat(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesFour), resultReg);
3199 m_jit.convertFloatToDouble(resultReg, resultReg);
3200 break;
3201 case 8: {
3202 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg);
3203 break;
3204 }
3205 default:
3206 RELEASE_ASSERT_NOT_REACHED();
3207 }
3208
3209 doubleResult(resultReg, node);
3210}
3211
3212void SpeculativeJIT::compilePutByValForFloatTypedArray(GPRReg base, GPRReg property, Node* node, TypedArrayType type)
3213{
3214 ASSERT(isFloat(type));
3215
3216 StorageOperand storage(this, m_jit.graph().varArgChild(node, 3));
3217 GPRReg storageReg = storage.gpr();
3218
3219 Edge baseUse = m_jit.graph().varArgChild(node, 0);
3220 Edge valueUse = m_jit.graph().varArgChild(node, 2);
3221
3222 SpeculateDoubleOperand valueOp(this, valueUse);
3223 FPRTemporary scratch(this);
3224 FPRReg valueFPR = valueOp.fpr();
3225 FPRReg scratchFPR = scratch.fpr();
3226
3227 ASSERT_UNUSED(baseUse, node->arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(baseUse)));
3228
3229 MacroAssembler::Jump outOfBounds = jumpForTypedArrayOutOfBounds(node, base, property);
3230
3231 switch (elementSize(type)) {
3232 case 4: {
3233 m_jit.moveDouble(valueFPR, scratchFPR);
3234 m_jit.convertDoubleToFloat(valueFPR, scratchFPR);
3235 m_jit.storeFloat(scratchFPR, MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesFour));
3236 break;
3237 }
3238 case 8:
3239 m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesEight));
3240 break;
3241 default:
3242 RELEASE_ASSERT_NOT_REACHED();
3243 }
3244
3245 JITCompiler::Jump done = jumpForTypedArrayIsNeuteredIfOutOfBounds(node, base, outOfBounds);
3246 if (done.isSet())
3247 done.link(&m_jit);
3248 noResult(node);
3249}
3250
3251void SpeculativeJIT::compileGetByValForObjectWithString(Node* node)
3252{
3253 SpeculateCellOperand arg1(this, m_graph.varArgChild(node, 0));
3254 SpeculateCellOperand arg2(this, m_graph.varArgChild(node, 1));
3255
3256 GPRReg arg1GPR = arg1.gpr();
3257 GPRReg arg2GPR = arg2.gpr();
3258
3259 speculateObject(m_graph.varArgChild(node, 0), arg1GPR);
3260 speculateString(m_graph.varArgChild(node, 1), arg2GPR);
3261
3262 flushRegisters();
3263 JSValueRegsFlushedCallResult result(this);
3264 JSValueRegs resultRegs = result.regs();
3265 callOperation(operationGetByValObjectString, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1GPR, arg2GPR);
3266 m_jit.exceptionCheck();
3267
3268 jsValueResult(resultRegs, node);
3269}
3270
3271void SpeculativeJIT::compileGetByValForObjectWithSymbol(Node* node)
3272{
3273 SpeculateCellOperand arg1(this, m_graph.varArgChild(node, 0));
3274 SpeculateCellOperand arg2(this, m_graph.varArgChild(node, 1));
3275
3276 GPRReg arg1GPR = arg1.gpr();
3277 GPRReg arg2GPR = arg2.gpr();
3278
3279 speculateObject(m_graph.varArgChild(node, 0), arg1GPR);
3280 speculateSymbol(m_graph.varArgChild(node, 1), arg2GPR);
3281
3282 flushRegisters();
3283 JSValueRegsFlushedCallResult result(this);
3284 JSValueRegs resultRegs = result.regs();
3285 callOperation(operationGetByValObjectSymbol, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1GPR, arg2GPR);
3286 m_jit.exceptionCheck();
3287
3288 jsValueResult(resultRegs, node);
3289}
3290
3291void SpeculativeJIT::compilePutByValForCellWithString(Node* node, Edge& child1, Edge& child2, Edge& child3)
3292{
3293 SpeculateCellOperand arg1(this, child1);
3294 SpeculateCellOperand arg2(this, child2);
3295 JSValueOperand arg3(this, child3);
3296
3297 GPRReg arg1GPR = arg1.gpr();
3298 GPRReg arg2GPR = arg2.gpr();
3299 JSValueRegs arg3Regs = arg3.jsValueRegs();
3300
3301 speculateString(child2, arg2GPR);
3302
3303 flushRegisters();
3304 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValCellStringStrict : operationPutByValCellStringNonStrict, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1GPR, arg2GPR, arg3Regs);
3305 m_jit.exceptionCheck();
3306
3307 noResult(node);
3308}
3309
3310void SpeculativeJIT::compilePutByValForCellWithSymbol(Node* node, Edge& child1, Edge& child2, Edge& child3)
3311{
3312 SpeculateCellOperand arg1(this, child1);
3313 SpeculateCellOperand arg2(this, child2);
3314 JSValueOperand arg3(this, child3);
3315
3316 GPRReg arg1GPR = arg1.gpr();
3317 GPRReg arg2GPR = arg2.gpr();
3318 JSValueRegs arg3Regs = arg3.jsValueRegs();
3319
3320 speculateSymbol(child2, arg2GPR);
3321
3322 flushRegisters();
3323 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValCellSymbolStrict : operationPutByValCellSymbolNonStrict, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1GPR, arg2GPR, arg3Regs);
3324 m_jit.exceptionCheck();
3325
3326 noResult(node);
3327}
3328
3329void SpeculativeJIT::compileGetByValWithThis(Node* node)
3330{
3331 JSValueOperand base(this, node->child1());
3332 JSValueRegs baseRegs = base.jsValueRegs();
3333 JSValueOperand thisValue(this, node->child2());
3334 JSValueRegs thisValueRegs = thisValue.jsValueRegs();
3335 JSValueOperand subscript(this, node->child3());
3336 JSValueRegs subscriptRegs = subscript.jsValueRegs();
3337
3338 flushRegisters();
3339 JSValueRegsFlushedCallResult result(this);
3340 JSValueRegs resultRegs = result.regs();
3341 callOperation(operationGetByValWithThis, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseRegs, thisValueRegs, subscriptRegs);
3342 m_jit.exceptionCheck();
3343
3344 jsValueResult(resultRegs, node);
3345}
3346
3347void SpeculativeJIT::compileCheckTypeInfoFlags(Node* node)
3348{
3349 SpeculateCellOperand base(this, node->child1());
3350
3351 GPRReg baseGPR = base.gpr();
3352
3353 // FIXME: This only works for checking if a single bit is set. If we want to check more
3354 // than one bit at once, we'll need to fix this:
3355 // https://bugs.webkit.org/show_bug.cgi?id=185705
3356 speculationCheck(BadTypeInfoFlags, JSValueRegs(), 0, m_jit.branchTest8(MacroAssembler::Zero, MacroAssembler::Address(baseGPR, JSCell::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(node->typeInfoOperand())));
3357
3358 noResult(node);
3359}
3360
3361void SpeculativeJIT::compileParseInt(Node* node)
3362{
3363 RELEASE_ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == StringUse);
3364 if (node->child2()) {
3365 SpeculateInt32Operand radix(this, node->child2());
3366 GPRReg radixGPR = radix.gpr();
3367 if (node->child1().useKind() == UntypedUse) {
3368 JSValueOperand value(this, node->child1());
3369 JSValueRegs valueRegs = value.jsValueRegs();
3370
3371 flushRegisters();
3372 JSValueRegsFlushedCallResult result(this);
3373 JSValueRegs resultRegs = result.regs();
3374 callOperation(operationParseIntGeneric, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueRegs, radixGPR);
3375 m_jit.exceptionCheck();
3376 jsValueResult(resultRegs, node);
3377 return;
3378 }
3379
3380 SpeculateCellOperand value(this, node->child1());
3381 GPRReg valueGPR = value.gpr();
3382 speculateString(node->child1(), valueGPR);
3383
3384 flushRegisters();
3385 JSValueRegsFlushedCallResult result(this);
3386 JSValueRegs resultRegs = result.regs();
3387 callOperation(operationParseIntString, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueGPR, radixGPR);
3388 m_jit.exceptionCheck();
3389 jsValueResult(resultRegs, node);
3390 return;
3391 }
3392
3393 if (node->child1().useKind() == UntypedUse) {
3394 JSValueOperand value(this, node->child1());
3395 JSValueRegs valueRegs = value.jsValueRegs();
3396
3397 flushRegisters();
3398 JSValueRegsFlushedCallResult result(this);
3399 JSValueRegs resultRegs = result.regs();
3400 callOperation(operationParseIntNoRadixGeneric, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueRegs);
3401 m_jit.exceptionCheck();
3402 jsValueResult(resultRegs, node);
3403 return;
3404 }
3405
3406 SpeculateCellOperand value(this, node->child1());
3407 GPRReg valueGPR = value.gpr();
3408 speculateString(node->child1(), valueGPR);
3409
3410 flushRegisters();
3411 JSValueRegsFlushedCallResult result(this);
3412 JSValueRegs resultRegs = result.regs();
3413 callOperation(operationParseIntStringNoRadix, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueGPR);
3414 m_jit.exceptionCheck();
3415 jsValueResult(resultRegs, node);
3416}
3417
3418void SpeculativeJIT::compileOverridesHasInstance(Node* node)
3419{
3420 Node* hasInstanceValueNode = node->child2().node();
3421 JSFunction* defaultHasInstanceFunction = jsCast<JSFunction*>(node->cellOperand()->value());
3422
3423 MacroAssembler::JumpList notDefault;
3424 SpeculateCellOperand base(this, node->child1());
3425 JSValueOperand hasInstanceValue(this, node->child2());
3426 GPRTemporary result(this);
3427
3428 GPRReg baseGPR = base.gpr();
3429 GPRReg resultGPR = result.gpr();
3430
3431 // It would be great if constant folding handled automatically the case where we knew the hasInstance function
3432 // was a constant. Unfortunately, the folding rule for OverridesHasInstance is in the strength reduction phase
3433 // since it relies on OSR information. https://bugs.webkit.org/show_bug.cgi?id=154832
3434 if (!hasInstanceValueNode->isCellConstant() || defaultHasInstanceFunction != hasInstanceValueNode->asCell()) {
3435 JSValueRegs hasInstanceValueRegs = hasInstanceValue.jsValueRegs();
3436#if USE(JSVALUE64)
3437 notDefault.append(m_jit.branchPtr(MacroAssembler::NotEqual, hasInstanceValueRegs.gpr(), TrustedImmPtr(node->cellOperand())));
3438#else
3439 notDefault.append(m_jit.branchIfNotCell(hasInstanceValueRegs));
3440 notDefault.append(m_jit.branchPtr(MacroAssembler::NotEqual, hasInstanceValueRegs.payloadGPR(), TrustedImmPtr(node->cellOperand())));
3441#endif
3442 }
3443
3444 // Check that base 'ImplementsDefaultHasInstance'.
3445 m_jit.test8(MacroAssembler::Zero, MacroAssembler::Address(baseGPR, JSCell::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(ImplementsDefaultHasInstance), resultGPR);
3446 MacroAssembler::Jump done = m_jit.jump();
3447
3448 if (!notDefault.empty()) {
3449 notDefault.link(&m_jit);
3450 m_jit.move(TrustedImm32(1), resultGPR);
3451 }
3452
3453 done.link(&m_jit);
3454 unblessedBooleanResult(resultGPR, node);
3455}
3456
3457void SpeculativeJIT::compileInstanceOfForCells(Node* node, JSValueRegs valueRegs, JSValueRegs prototypeRegs, GPRReg resultGPR, GPRReg scratchGPR, GPRReg scratch2GPR, JITCompiler::Jump slowCase)
3458{
3459 CallSiteIndex callSiteIndex = m_jit.addCallSite(node->origin.semantic);
3460
3461 JITInstanceOfGenerator gen(
3462 m_jit.codeBlock(), node->origin.semantic, callSiteIndex, usedRegisters(), resultGPR,
3463 valueRegs.payloadGPR(), prototypeRegs.payloadGPR(), scratchGPR, scratch2GPR,
3464 m_state.forNode(node->child2()).isType(SpecObject | ~SpecCell));
3465 gen.generateFastPath(m_jit);
3466
3467 JITCompiler::JumpList slowCases;
3468 slowCases.append(slowCase);
3469
3470 std::unique_ptr<SlowPathGenerator> slowPath = slowPathCall(
3471 slowCases, this, operationInstanceOfOptimize, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), gen.stubInfo(), valueRegs,
3472 prototypeRegs);
3473
3474 m_jit.addInstanceOf(gen, slowPath.get());
3475 addSlowPathGenerator(WTFMove(slowPath));
3476}
3477
3478void SpeculativeJIT::compileInstanceOf(Node* node)
3479{
3480#if USE(JSVALUE64)
3481 if (node->child1().useKind() == CellUse
3482 && node->child2().useKind() == CellUse) {
3483 SpeculateCellOperand value(this, node->child1());
3484 SpeculateCellOperand prototype(this, node->child2());
3485
3486 GPRTemporary result(this);
3487 GPRTemporary scratch(this);
3488 GPRTemporary scratch2(this);
3489
3490 GPRReg valueGPR = value.gpr();
3491 GPRReg prototypeGPR = prototype.gpr();
3492 GPRReg resultGPR = result.gpr();
3493 GPRReg scratchGPR = scratch.gpr();
3494 GPRReg scratch2GPR = scratch2.gpr();
3495
3496 compileInstanceOfForCells(node, JSValueRegs(valueGPR), JSValueRegs(prototypeGPR), resultGPR, scratchGPR, scratch2GPR);
3497
3498 blessedBooleanResult(resultGPR, node);
3499 return;
3500 }
3501#endif
3502
3503 DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse);
3504 DFG_ASSERT(m_jit.graph(), node, node->child2().useKind() == UntypedUse);
3505
3506 JSValueOperand value(this, node->child1());
3507 JSValueOperand prototype(this, node->child2());
3508
3509 GPRTemporary result(this);
3510 GPRTemporary scratch(this);
3511
3512 JSValueRegs valueRegs = value.jsValueRegs();
3513 JSValueRegs prototypeRegs = prototype.jsValueRegs();
3514
3515 GPRReg resultGPR = result.gpr();
3516 GPRReg scratchGPR = scratch.gpr();
3517
3518 JITCompiler::Jump isCell = m_jit.branchIfCell(valueRegs);
3519 moveFalseTo(resultGPR);
3520
3521 JITCompiler::Jump done = m_jit.jump();
3522
3523 isCell.link(&m_jit);
3524
3525 JITCompiler::Jump slowCase = m_jit.branchIfNotCell(prototypeRegs);
3526
3527 compileInstanceOfForCells(node, valueRegs, prototypeRegs, resultGPR, scratchGPR, InvalidGPRReg, slowCase);
3528
3529 done.link(&m_jit);
3530 blessedBooleanResult(resultGPR, node);
3531 return;
3532}
3533
3534void SpeculativeJIT::compileValueBitNot(Node* node)
3535{
3536 Edge& child1 = node->child1();
3537
3538 if (child1.useKind() == BigIntUse) {
3539 SpeculateCellOperand operand(this, child1);
3540 GPRReg operandGPR = operand.gpr();
3541
3542 speculateBigInt(child1, operandGPR);
3543
3544 flushRegisters();
3545 GPRFlushedCallResult result(this);
3546 GPRReg resultGPR = result.gpr();
3547
3548 callOperation(operationBitNotBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), operandGPR);
3549 m_jit.exceptionCheck();
3550 cellResult(resultGPR, node);
3551
3552 return;
3553 }
3554
3555 JSValueOperand operand(this, child1);
3556 JSValueRegs operandRegs = operand.jsValueRegs();
3557
3558 flushRegisters();
3559 JSValueRegsFlushedCallResult result(this);
3560 JSValueRegs resultRegs = result.regs();
3561 callOperation(operationValueBitNot, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), operandRegs);
3562 m_jit.exceptionCheck();
3563
3564 jsValueResult(resultRegs, node);
3565}
3566
3567void SpeculativeJIT::compileBitwiseNot(Node* node)
3568{
3569 Edge& child1 = node->child1();
3570
3571 SpeculateInt32Operand operand(this, child1);
3572 GPRTemporary result(this);
3573 GPRReg resultGPR = result.gpr();
3574
3575 m_jit.move(operand.gpr(), resultGPR);
3576
3577 m_jit.not32(resultGPR);
3578
3579 int32Result(resultGPR, node);
3580}
3581
3582template<typename SnippetGenerator, J_JITOperation_GJJ snippetSlowPathFunction>
3583void SpeculativeJIT::emitUntypedBitOp(Node* node)
3584{
3585 Edge& leftChild = node->child1();
3586 Edge& rightChild = node->child2();
3587
3588 if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
3589 JSValueOperand left(this, leftChild);
3590 JSValueOperand right(this, rightChild);
3591 JSValueRegs leftRegs = left.jsValueRegs();
3592 JSValueRegs rightRegs = right.jsValueRegs();
3593
3594 flushRegisters();
3595 JSValueRegsFlushedCallResult result(this);
3596 JSValueRegs resultRegs = result.regs();
3597 callOperation(snippetSlowPathFunction, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftRegs, rightRegs);
3598 m_jit.exceptionCheck();
3599
3600 jsValueResult(resultRegs, node);
3601 return;
3602 }
3603
3604 Optional<JSValueOperand> left;
3605 Optional<JSValueOperand> right;
3606
3607 JSValueRegs leftRegs;
3608 JSValueRegs rightRegs;
3609
3610#if USE(JSVALUE64)
3611 GPRTemporary result(this);
3612 JSValueRegs resultRegs = JSValueRegs(result.gpr());
3613 GPRTemporary scratch(this);
3614 GPRReg scratchGPR = scratch.gpr();
3615#else
3616 GPRTemporary resultTag(this);
3617 GPRTemporary resultPayload(this);
3618 JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
3619 GPRReg scratchGPR = resultTag.gpr();
3620#endif
3621
3622 SnippetOperand leftOperand;
3623 SnippetOperand rightOperand;
3624
3625 // The snippet generator does not support both operands being constant. If the left
3626 // operand is already const, we'll ignore the right operand's constness.
3627 if (leftChild->isInt32Constant())
3628 leftOperand.setConstInt32(leftChild->asInt32());
3629 else if (rightChild->isInt32Constant())
3630 rightOperand.setConstInt32(rightChild->asInt32());
3631
3632 RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
3633
3634 if (!leftOperand.isConst()) {
3635 left.emplace(this, leftChild);
3636 leftRegs = left->jsValueRegs();
3637 }
3638 if (!rightOperand.isConst()) {
3639 right.emplace(this, rightChild);
3640 rightRegs = right->jsValueRegs();
3641 }
3642
3643 SnippetGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs, scratchGPR);
3644 gen.generateFastPath(m_jit);
3645
3646 ASSERT(gen.didEmitFastPath());
3647 gen.endJumpList().append(m_jit.jump());
3648
3649 gen.slowPathJumpList().link(&m_jit);
3650 silentSpillAllRegisters(resultRegs);
3651
3652 if (leftOperand.isConst()) {
3653 leftRegs = resultRegs;
3654 m_jit.moveValue(leftChild->asJSValue(), leftRegs);
3655 } else if (rightOperand.isConst()) {
3656 rightRegs = resultRegs;
3657 m_jit.moveValue(rightChild->asJSValue(), rightRegs);
3658 }
3659
3660 callOperation(snippetSlowPathFunction, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftRegs, rightRegs);
3661
3662 silentFillAllRegisters();
3663 m_jit.exceptionCheck();
3664
3665 gen.endJumpList().link(&m_jit);
3666 jsValueResult(resultRegs, node);
3667}
3668
3669void SpeculativeJIT::compileValueBitwiseOp(Node* node)
3670{
3671 NodeType op = node->op();
3672 Edge& leftChild = node->child1();
3673 Edge& rightChild = node->child2();
3674
3675 if (leftChild.useKind() == UntypedUse || rightChild.useKind() == UntypedUse) {
3676 switch (op) {
3677 case ValueBitAnd:
3678 emitUntypedBitOp<JITBitAndGenerator, operationValueBitAnd>(node);
3679 return;
3680 case ValueBitXor:
3681 emitUntypedBitOp<JITBitXorGenerator, operationValueBitXor>(node);
3682 return;
3683 case ValueBitOr:
3684 emitUntypedBitOp<JITBitOrGenerator, operationValueBitOr>(node);
3685 return;
3686 default:
3687 RELEASE_ASSERT_NOT_REACHED();
3688 }
3689 }
3690
3691 ASSERT(leftChild.useKind() == BigIntUse && rightChild.useKind() == BigIntUse);
3692
3693 SpeculateCellOperand left(this, node->child1());
3694 SpeculateCellOperand right(this, node->child2());
3695 GPRReg leftGPR = left.gpr();
3696 GPRReg rightGPR = right.gpr();
3697
3698 speculateBigInt(leftChild, leftGPR);
3699 speculateBigInt(rightChild, rightGPR);
3700
3701 flushRegisters();
3702 GPRFlushedCallResult result(this);
3703 GPRReg resultGPR = result.gpr();
3704
3705 switch (op) {
3706 case ValueBitAnd:
3707 callOperation(operationBitAndBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
3708 break;
3709 case ValueBitXor:
3710 callOperation(operationBitXorBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
3711 break;
3712 case ValueBitOr:
3713 callOperation(operationBitOrBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
3714 break;
3715 default:
3716 RELEASE_ASSERT_NOT_REACHED();
3717 }
3718
3719 m_jit.exceptionCheck();
3720 cellResult(resultGPR, node);
3721}
3722
3723void SpeculativeJIT::compileBitwiseOp(Node* node)
3724{
3725 NodeType op = node->op();
3726 Edge& leftChild = node->child1();
3727 Edge& rightChild = node->child2();
3728
3729 if (leftChild->isInt32Constant()) {
3730 SpeculateInt32Operand op2(this, rightChild);
3731 GPRTemporary result(this, Reuse, op2);
3732
3733 bitOp(op, leftChild->asInt32(), op2.gpr(), result.gpr());
3734
3735 int32Result(result.gpr(), node);
3736 return;
3737 }
3738
3739 if (rightChild->isInt32Constant()) {
3740 SpeculateInt32Operand op1(this, leftChild);
3741 GPRTemporary result(this, Reuse, op1);
3742
3743 bitOp(op, rightChild->asInt32(), op1.gpr(), result.gpr());
3744
3745 int32Result(result.gpr(), node);
3746 return;
3747 }
3748
3749 SpeculateInt32Operand op1(this, leftChild);
3750 SpeculateInt32Operand op2(this, rightChild);
3751 GPRTemporary result(this, Reuse, op1, op2);
3752
3753 GPRReg reg1 = op1.gpr();
3754 GPRReg reg2 = op2.gpr();
3755 bitOp(op, reg1, reg2, result.gpr());
3756
3757 int32Result(result.gpr(), node);
3758}
3759
3760void SpeculativeJIT::emitUntypedRightShiftBitOp(Node* node)
3761{
3762 J_JITOperation_GJJ snippetSlowPathFunction = node->op() == ValueBitRShift
3763 ? operationValueBitRShift : operationValueBitURShift;
3764 JITRightShiftGenerator::ShiftType shiftType = node->op() == ValueBitRShift
3765 ? JITRightShiftGenerator::SignedShift : JITRightShiftGenerator::UnsignedShift;
3766
3767 Edge& leftChild = node->child1();
3768 Edge& rightChild = node->child2();
3769
3770 if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
3771 JSValueOperand left(this, leftChild);
3772 JSValueOperand right(this, rightChild);
3773 JSValueRegs leftRegs = left.jsValueRegs();
3774 JSValueRegs rightRegs = right.jsValueRegs();
3775
3776 flushRegisters();
3777 JSValueRegsFlushedCallResult result(this);
3778 JSValueRegs resultRegs = result.regs();
3779 callOperation(snippetSlowPathFunction, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftRegs, rightRegs);
3780 m_jit.exceptionCheck();
3781
3782 jsValueResult(resultRegs, node);
3783 return;
3784 }
3785
3786 Optional<JSValueOperand> left;
3787 Optional<JSValueOperand> right;
3788
3789 JSValueRegs leftRegs;
3790 JSValueRegs rightRegs;
3791
3792 FPRTemporary leftNumber(this);
3793 FPRReg leftFPR = leftNumber.fpr();
3794
3795#if USE(JSVALUE64)
3796 GPRTemporary result(this);
3797 JSValueRegs resultRegs = JSValueRegs(result.gpr());
3798 GPRTemporary scratch(this);
3799 GPRReg scratchGPR = scratch.gpr();
3800 FPRReg scratchFPR = InvalidFPRReg;
3801#else
3802 GPRTemporary resultTag(this);
3803 GPRTemporary resultPayload(this);
3804 JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
3805 GPRReg scratchGPR = resultTag.gpr();
3806 FPRTemporary fprScratch(this);
3807 FPRReg scratchFPR = fprScratch.fpr();
3808#endif
3809
3810 SnippetOperand leftOperand;
3811 SnippetOperand rightOperand;
3812
3813 // The snippet generator does not support both operands being constant. If the left
3814 // operand is already const, we'll ignore the right operand's constness.
3815 if (leftChild->isInt32Constant())
3816 leftOperand.setConstInt32(leftChild->asInt32());
3817 else if (rightChild->isInt32Constant())
3818 rightOperand.setConstInt32(rightChild->asInt32());
3819
3820 RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
3821
3822 if (!leftOperand.isConst()) {
3823 left.emplace(this, leftChild);
3824 leftRegs = left->jsValueRegs();
3825 }
3826 if (!rightOperand.isConst()) {
3827 right.emplace(this, rightChild);
3828 rightRegs = right->jsValueRegs();
3829 }
3830
3831 JITRightShiftGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs,
3832 leftFPR, scratchGPR, scratchFPR, shiftType);
3833 gen.generateFastPath(m_jit);
3834
3835 ASSERT(gen.didEmitFastPath());
3836 gen.endJumpList().append(m_jit.jump());
3837
3838 gen.slowPathJumpList().link(&m_jit);
3839 silentSpillAllRegisters(resultRegs);
3840
3841 if (leftOperand.isConst()) {
3842 leftRegs = resultRegs;
3843 m_jit.moveValue(leftChild->asJSValue(), leftRegs);
3844 } else if (rightOperand.isConst()) {
3845 rightRegs = resultRegs;
3846 m_jit.moveValue(rightChild->asJSValue(), rightRegs);
3847 }
3848
3849 callOperation(snippetSlowPathFunction, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftRegs, rightRegs);
3850
3851 silentFillAllRegisters();
3852 m_jit.exceptionCheck();
3853
3854 gen.endJumpList().link(&m_jit);
3855 jsValueResult(resultRegs, node);
3856 return;
3857}
3858
3859void SpeculativeJIT::compileValueLShiftOp(Node* node)
3860{
3861 Edge& leftChild = node->child1();
3862 Edge& rightChild = node->child2();
3863
3864 if (node->binaryUseKind() == BigIntUse) {
3865 SpeculateCellOperand left(this, leftChild);
3866 SpeculateCellOperand right(this, rightChild);
3867 GPRReg leftGPR = left.gpr();
3868 GPRReg rightGPR = right.gpr();
3869
3870 speculateBigInt(leftChild, leftGPR);
3871 speculateBigInt(rightChild, rightGPR);
3872
3873 flushRegisters();
3874 GPRFlushedCallResult result(this);
3875 GPRReg resultGPR = result.gpr();
3876
3877 callOperation(operationBitLShiftBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
3878 m_jit.exceptionCheck();
3879 cellResult(resultGPR, node);
3880 return;
3881 }
3882
3883 ASSERT(leftChild.useKind() == UntypedUse && rightChild.useKind() == UntypedUse);
3884 emitUntypedBitOp<JITLeftShiftGenerator, operationValueBitLShift>(node);
3885}
3886
3887void SpeculativeJIT::compileValueBitRShift(Node* node)
3888{
3889 Edge& leftChild = node->child1();
3890 Edge& rightChild = node->child2();
3891
3892 if (node->isBinaryUseKind(BigIntUse)) {
3893 SpeculateCellOperand left(this, leftChild);
3894 SpeculateCellOperand right(this, rightChild);
3895 GPRReg leftGPR = left.gpr();
3896 GPRReg rightGPR = right.gpr();
3897
3898 speculateBigInt(leftChild, leftGPR);
3899 speculateBigInt(rightChild, rightGPR);
3900
3901 flushRegisters();
3902 GPRFlushedCallResult result(this);
3903 GPRReg resultGPR = result.gpr();
3904 callOperation(operationBitRShiftBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
3905 m_jit.exceptionCheck();
3906
3907 cellResult(resultGPR, node);
3908 return;
3909 }
3910
3911 ASSERT(leftChild.useKind() == UntypedUse && rightChild.useKind() == UntypedUse);
3912 emitUntypedRightShiftBitOp(node);
3913}
3914
3915void SpeculativeJIT::compileShiftOp(Node* node)
3916{
3917 NodeType op = node->op();
3918 Edge& leftChild = node->child1();
3919 Edge& rightChild = node->child2();
3920
3921 if (leftChild.useKind() == UntypedUse || rightChild.useKind() == UntypedUse) {
3922 RELEASE_ASSERT(op == BitURShift);
3923 emitUntypedRightShiftBitOp(node);
3924 return;
3925 }
3926
3927 if (rightChild->isInt32Constant()) {
3928 SpeculateInt32Operand op1(this, leftChild);
3929 GPRTemporary result(this, Reuse, op1);
3930
3931 shiftOp(op, op1.gpr(), rightChild->asInt32() & 0x1f, result.gpr());
3932
3933 int32Result(result.gpr(), node);
3934 } else {
3935 // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.
3936 SpeculateInt32Operand op1(this, leftChild);
3937 SpeculateInt32Operand op2(this, rightChild);
3938 GPRTemporary result(this, Reuse, op1);
3939
3940 GPRReg reg1 = op1.gpr();
3941 GPRReg reg2 = op2.gpr();
3942 shiftOp(op, reg1, reg2, result.gpr());
3943
3944 int32Result(result.gpr(), node);
3945 }
3946}
3947
3948void SpeculativeJIT::compileValueAdd(Node* node)
3949{
3950 Edge& leftChild = node->child1();
3951 Edge& rightChild = node->child2();
3952
3953 if (node->isBinaryUseKind(BigIntUse)) {
3954 SpeculateCellOperand left(this, node->child1());
3955 SpeculateCellOperand right(this, node->child2());
3956 GPRReg leftGPR = left.gpr();
3957 GPRReg rightGPR = right.gpr();
3958
3959 speculateBigInt(leftChild, leftGPR);
3960 speculateBigInt(rightChild, rightGPR);
3961
3962 flushRegisters();
3963 GPRFlushedCallResult result(this);
3964 GPRReg resultGPR = result.gpr();
3965 callOperation(operationAddBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
3966 m_jit.exceptionCheck();
3967
3968 cellResult(resultGPR, node);
3969 return;
3970 }
3971
3972 if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
3973 JSValueOperand left(this, leftChild);
3974 JSValueOperand right(this, rightChild);
3975 JSValueRegs leftRegs = left.jsValueRegs();
3976 JSValueRegs rightRegs = right.jsValueRegs();
3977
3978 flushRegisters();
3979 JSValueRegsFlushedCallResult result(this);
3980 JSValueRegs resultRegs = result.regs();
3981 callOperation(operationValueAddNotNumber, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftRegs, rightRegs);
3982 m_jit.exceptionCheck();
3983
3984 jsValueResult(resultRegs, node);
3985 return;
3986 }
3987
3988#if USE(JSVALUE64)
3989 bool needsScratchGPRReg = true;
3990 bool needsScratchFPRReg = false;
3991#else
3992 bool needsScratchGPRReg = true;
3993 bool needsScratchFPRReg = true;
3994#endif
3995
3996 CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
3997 BytecodeIndex bytecodeIndex = node->origin.semantic.bytecodeIndex();
3998 BinaryArithProfile* arithProfile = baselineCodeBlock->binaryArithProfileForBytecodeIndex(bytecodeIndex);
3999 JITAddIC* addIC = m_jit.codeBlock()->addJITAddIC(arithProfile);
4000 auto repatchingFunction = operationValueAddOptimize;
4001 auto nonRepatchingFunction = operationValueAdd;
4002
4003 compileMathIC(node, addIC, needsScratchGPRReg, needsScratchFPRReg, repatchingFunction, nonRepatchingFunction);
4004}
4005
4006void SpeculativeJIT::compileValueSub(Node* node)
4007{
4008 Edge& leftChild = node->child1();
4009 Edge& rightChild = node->child2();
4010
4011 if (node->binaryUseKind() == UntypedUse) {
4012#if USE(JSVALUE64)
4013 bool needsScratchGPRReg = true;
4014 bool needsScratchFPRReg = false;
4015#else
4016 bool needsScratchGPRReg = true;
4017 bool needsScratchFPRReg = true;
4018#endif
4019
4020 CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
4021 BytecodeIndex bytecodeIndex = node->origin.semantic.bytecodeIndex();
4022 BinaryArithProfile* arithProfile = baselineCodeBlock->binaryArithProfileForBytecodeIndex(bytecodeIndex);
4023 JITSubIC* subIC = m_jit.codeBlock()->addJITSubIC(arithProfile);
4024 auto repatchingFunction = operationValueSubOptimize;
4025 auto nonRepatchingFunction = operationValueSub;
4026
4027 compileMathIC(node, subIC, needsScratchGPRReg, needsScratchFPRReg, repatchingFunction, nonRepatchingFunction);
4028 return;
4029 }
4030
4031 ASSERT(leftChild.useKind() == BigIntUse && rightChild.useKind() == BigIntUse);
4032
4033 SpeculateCellOperand left(this, node->child1());
4034 SpeculateCellOperand right(this, node->child2());
4035 GPRReg leftGPR = left.gpr();
4036 GPRReg rightGPR = right.gpr();
4037
4038 speculateBigInt(leftChild, leftGPR);
4039 speculateBigInt(rightChild, rightGPR);
4040
4041 flushRegisters();
4042 GPRFlushedCallResult result(this);
4043 GPRReg resultGPR = result.gpr();
4044
4045 callOperation(operationSubBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
4046
4047 m_jit.exceptionCheck();
4048 cellResult(resultGPR, node);
4049}
4050
4051template <typename Generator, typename RepatchingFunction, typename NonRepatchingFunction>
4052void SpeculativeJIT::compileMathIC(Node* node, JITBinaryMathIC<Generator>* mathIC, bool needsScratchGPRReg, bool needsScratchFPRReg, RepatchingFunction repatchingFunction, NonRepatchingFunction nonRepatchingFunction)
4053{
4054 Edge& leftChild = node->child1();
4055 Edge& rightChild = node->child2();
4056
4057 Optional<JSValueOperand> left;
4058 Optional<JSValueOperand> right;
4059
4060 JSValueRegs leftRegs;
4061 JSValueRegs rightRegs;
4062
4063 FPRTemporary leftNumber(this);
4064 FPRTemporary rightNumber(this);
4065 FPRReg leftFPR = leftNumber.fpr();
4066 FPRReg rightFPR = rightNumber.fpr();
4067
4068 GPRReg scratchGPR = InvalidGPRReg;
4069 FPRReg scratchFPR = InvalidFPRReg;
4070
4071 Optional<FPRTemporary> fprScratch;
4072 if (needsScratchFPRReg) {
4073 fprScratch.emplace(this);
4074 scratchFPR = fprScratch->fpr();
4075 }
4076
4077#if USE(JSVALUE64)
4078 Optional<GPRTemporary> gprScratch;
4079 if (needsScratchGPRReg) {
4080 gprScratch.emplace(this);
4081 scratchGPR = gprScratch->gpr();
4082 }
4083 GPRTemporary result(this);
4084 JSValueRegs resultRegs = JSValueRegs(result.gpr());
4085#else
4086 GPRTemporary resultTag(this);
4087 GPRTemporary resultPayload(this);
4088 JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
4089 if (needsScratchGPRReg)
4090 scratchGPR = resultRegs.tagGPR();
4091#endif
4092
4093 SnippetOperand leftOperand(m_state.forNode(leftChild).resultType());
4094 SnippetOperand rightOperand(m_state.forNode(rightChild).resultType());
4095
4096 // The snippet generator does not support both operands being constant. If the left
4097 // operand is already const, we'll ignore the right operand's constness.
4098 if (leftChild->isInt32Constant())
4099 leftOperand.setConstInt32(leftChild->asInt32());
4100 else if (rightChild->isInt32Constant())
4101 rightOperand.setConstInt32(rightChild->asInt32());
4102
4103 ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
4104 ASSERT(!(Generator::isLeftOperandValidConstant(leftOperand) && Generator::isRightOperandValidConstant(rightOperand)));
4105
4106 if (!Generator::isLeftOperandValidConstant(leftOperand)) {
4107 left.emplace(this, leftChild);
4108 leftRegs = left->jsValueRegs();
4109 }
4110 if (!Generator::isRightOperandValidConstant(rightOperand)) {
4111 right.emplace(this, rightChild);
4112 rightRegs = right->jsValueRegs();
4113 }
4114
4115#if ENABLE(MATH_IC_STATS)
4116 auto inlineStart = m_jit.label();
4117#endif
4118
4119 Box<MathICGenerationState> addICGenerationState = Box<MathICGenerationState>::create();
4120 mathIC->m_generator = Generator(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs, leftFPR, rightFPR, scratchGPR, scratchFPR);
4121
4122 bool shouldEmitProfiling = false;
4123 bool generatedInline = mathIC->generateInline(m_jit, *addICGenerationState, shouldEmitProfiling);
4124 if (generatedInline) {
4125 ASSERT(!addICGenerationState->slowPathJumps.empty());
4126
4127 Vector<SilentRegisterSavePlan> savePlans;
4128 silentSpillAllRegistersImpl(false, savePlans, resultRegs);
4129
4130 auto done = m_jit.label();
4131
4132 addSlowPathGeneratorLambda([=, savePlans = WTFMove(savePlans)] () {
4133 addICGenerationState->slowPathJumps.link(&m_jit);
4134 addICGenerationState->slowPathStart = m_jit.label();
4135#if ENABLE(MATH_IC_STATS)
4136 auto slowPathStart = m_jit.label();
4137#endif
4138
4139 silentSpill(savePlans);
4140
4141 auto innerLeftRegs = leftRegs;
4142 auto innerRightRegs = rightRegs;
4143 if (Generator::isLeftOperandValidConstant(leftOperand)) {
4144 innerLeftRegs = resultRegs;
4145 m_jit.moveValue(leftChild->asJSValue(), innerLeftRegs);
4146 } else if (Generator::isRightOperandValidConstant(rightOperand)) {
4147 innerRightRegs = resultRegs;
4148 m_jit.moveValue(rightChild->asJSValue(), innerRightRegs);
4149 }
4150
4151 if (addICGenerationState->shouldSlowPathRepatch)
4152 addICGenerationState->slowPathCall = callOperation(bitwise_cast<J_JITOperation_GJJMic>(repatchingFunction), resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), innerLeftRegs, innerRightRegs, TrustedImmPtr(mathIC));
4153 else
4154 addICGenerationState->slowPathCall = callOperation(nonRepatchingFunction, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), innerLeftRegs, innerRightRegs);
4155
4156 silentFill(savePlans);
4157 m_jit.exceptionCheck();
4158 m_jit.jump().linkTo(done, &m_jit);
4159
4160 m_jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
4161 mathIC->finalizeInlineCode(*addICGenerationState, linkBuffer);
4162 });
4163
4164#if ENABLE(MATH_IC_STATS)
4165 auto slowPathEnd = m_jit.label();
4166 m_jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
4167 size_t size = static_cast<char*>(linkBuffer.locationOf(slowPathEnd).executableAddress()) - static_cast<char*>(linkBuffer.locationOf(slowPathStart).executableAddress());
4168 mathIC->m_generatedCodeSize += size;
4169 });
4170#endif
4171
4172 });
4173 } else {
4174 if (Generator::isLeftOperandValidConstant(leftOperand)) {
4175 left.emplace(this, leftChild);
4176 leftRegs = left->jsValueRegs();
4177 } else if (Generator::isRightOperandValidConstant(rightOperand)) {
4178 right.emplace(this, rightChild);
4179 rightRegs = right->jsValueRegs();
4180 }
4181
4182 flushRegisters();
4183 callOperation(nonRepatchingFunction, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftRegs, rightRegs);
4184 m_jit.exceptionCheck();
4185 }
4186
4187#if ENABLE(MATH_IC_STATS)
4188 auto inlineEnd = m_jit.label();
4189 m_jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
4190 size_t size = static_cast<char*>(linkBuffer.locationOf(inlineEnd).executableAddress()) - static_cast<char*>(linkBuffer.locationOf(inlineStart).executableAddress());
4191 mathIC->m_generatedCodeSize += size;
4192 });
4193#endif
4194
4195 jsValueResult(resultRegs, node);
4196 return;
4197}
4198
4199void SpeculativeJIT::compileInstanceOfCustom(Node* node)
4200{
4201 // We could do something smarter here but this case is currently super rare and unless
4202 // Symbol.hasInstance becomes popular will likely remain that way.
4203
4204 JSValueOperand value(this, node->child1());
4205 SpeculateCellOperand constructor(this, node->child2());
4206 JSValueOperand hasInstanceValue(this, node->child3());
4207 GPRTemporary result(this);
4208
4209 JSValueRegs valueRegs = value.jsValueRegs();
4210 GPRReg constructorGPR = constructor.gpr();
4211 JSValueRegs hasInstanceRegs = hasInstanceValue.jsValueRegs();
4212 GPRReg resultGPR = result.gpr();
4213
4214 MacroAssembler::Jump slowCase = m_jit.jump();
4215
4216 addSlowPathGenerator(slowPathCall(slowCase, this, operationInstanceOfCustom, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueRegs, constructorGPR, hasInstanceRegs));
4217
4218 unblessedBooleanResult(resultGPR, node);
4219}
4220
4221void SpeculativeJIT::compileIsCellWithType(Node* node)
4222{
4223 switch (node->child1().useKind()) {
4224 case UntypedUse: {
4225 JSValueOperand value(this, node->child1());
4226 GPRTemporary result(this, Reuse, value, PayloadWord);
4227
4228 JSValueRegs valueRegs = value.jsValueRegs();
4229 GPRReg resultGPR = result.gpr();
4230
4231 JITCompiler::Jump isNotCell = m_jit.branchIfNotCell(valueRegs);
4232
4233 m_jit.compare8(JITCompiler::Equal,
4234 JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoTypeOffset()),
4235 TrustedImm32(node->queriedType()),
4236 resultGPR);
4237 blessBoolean(resultGPR);
4238 JITCompiler::Jump done = m_jit.jump();
4239
4240 isNotCell.link(&m_jit);
4241 moveFalseTo(resultGPR);
4242
4243 done.link(&m_jit);
4244 blessedBooleanResult(resultGPR, node);
4245 return;
4246 }
4247
4248 case CellUse: {
4249 SpeculateCellOperand cell(this, node->child1());
4250 GPRTemporary result(this, Reuse, cell);
4251
4252 GPRReg cellGPR = cell.gpr();
4253 GPRReg resultGPR = result.gpr();
4254
4255 m_jit.compare8(JITCompiler::Equal,
4256 JITCompiler::Address(cellGPR, JSCell::typeInfoTypeOffset()),
4257 TrustedImm32(node->queriedType()),
4258 resultGPR);
4259 blessBoolean(resultGPR);
4260 blessedBooleanResult(resultGPR, node);
4261 return;
4262 }
4263
4264 default:
4265 RELEASE_ASSERT_NOT_REACHED();
4266 break;
4267 }
4268}
4269
4270void SpeculativeJIT::compileIsTypedArrayView(Node* node)
4271{
4272 JSValueOperand value(this, node->child1());
4273 GPRTemporary result(this, Reuse, value, PayloadWord);
4274
4275 JSValueRegs valueRegs = value.jsValueRegs();
4276 GPRReg resultGPR = result.gpr();
4277
4278 JITCompiler::Jump isNotCell = m_jit.branchIfNotCell(valueRegs);
4279
4280 m_jit.load8(JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoTypeOffset()), resultGPR);
4281 m_jit.sub32(TrustedImm32(FirstTypedArrayType), resultGPR);
4282 m_jit.compare32(JITCompiler::Below,
4283 resultGPR,
4284 TrustedImm32(NumberOfTypedArrayTypesExcludingDataView),
4285 resultGPR);
4286 blessBoolean(resultGPR);
4287 JITCompiler::Jump done = m_jit.jump();
4288
4289 isNotCell.link(&m_jit);
4290 moveFalseTo(resultGPR);
4291
4292 done.link(&m_jit);
4293 blessedBooleanResult(resultGPR, node);
4294}
4295
4296void SpeculativeJIT::compileToObjectOrCallObjectConstructor(Node* node)
4297{
4298 RELEASE_ASSERT(node->child1().useKind() == UntypedUse);
4299
4300 JSValueOperand value(this, node->child1());
4301 GPRTemporary result(this, Reuse, value, PayloadWord);
4302
4303 JSValueRegs valueRegs = value.jsValueRegs();
4304 GPRReg resultGPR = result.gpr();
4305
4306 MacroAssembler::JumpList slowCases;
4307 slowCases.append(m_jit.branchIfNotCell(valueRegs));
4308 slowCases.append(m_jit.branchIfNotObject(valueRegs.payloadGPR()));
4309 m_jit.move(valueRegs.payloadGPR(), resultGPR);
4310
4311 if (node->op() == ToObject)
4312 addSlowPathGenerator(slowPathCall(slowCases, this, operationToObject, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueRegs, identifierUID(node->identifierNumber())));
4313 else
4314 addSlowPathGenerator(slowPathCall(slowCases, this, operationCallObjectConstructor, resultGPR, TrustedImmPtr(node->cellOperand()), valueRegs));
4315
4316 cellResult(resultGPR, node);
4317}
4318
4319void SpeculativeJIT::compileArithAdd(Node* node)
4320{
4321 switch (node->binaryUseKind()) {
4322 case Int32Use: {
4323 ASSERT(!shouldCheckNegativeZero(node->arithMode()));
4324
4325 if (node->child2()->isInt32Constant()) {
4326 SpeculateInt32Operand op1(this, node->child1());
4327 GPRTemporary result(this, Reuse, op1);
4328
4329 GPRReg gpr1 = op1.gpr();
4330 int32_t imm2 = node->child2()->asInt32();
4331 GPRReg gprResult = result.gpr();
4332
4333 if (!shouldCheckOverflow(node->arithMode())) {
4334 m_jit.add32(Imm32(imm2), gpr1, gprResult);
4335 int32Result(gprResult, node);
4336 return;
4337 }
4338
4339 MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, Imm32(imm2), gprResult);
4340 if (gpr1 == gprResult) {
4341 speculationCheck(Overflow, JSValueRegs(), 0, check,
4342 SpeculationRecovery(SpeculativeAddImmediate, gpr1, imm2));
4343 } else
4344 speculationCheck(Overflow, JSValueRegs(), 0, check);
4345
4346 int32Result(gprResult, node);
4347 return;
4348 }
4349
4350 SpeculateInt32Operand op1(this, node->child1());
4351 SpeculateInt32Operand op2(this, node->child2());
4352 GPRTemporary result(this, Reuse, op1, op2);
4353
4354 GPRReg gpr1 = op1.gpr();
4355 GPRReg gpr2 = op2.gpr();
4356 GPRReg gprResult = result.gpr();
4357
4358 if (!shouldCheckOverflow(node->arithMode()))
4359 m_jit.add32(gpr1, gpr2, gprResult);
4360 else {
4361 MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult);
4362
4363 if (gpr1 == gprResult && gpr2 == gprResult)
4364 speculationCheck(Overflow, JSValueRegs(), 0, check, SpeculationRecovery(SpeculativeAddSelf, gprResult, gpr2));
4365 else if (gpr1 == gprResult)
4366 speculationCheck(Overflow, JSValueRegs(), 0, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2));
4367 else if (gpr2 == gprResult)
4368 speculationCheck(Overflow, JSValueRegs(), 0, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1));
4369 else
4370 speculationCheck(Overflow, JSValueRegs(), 0, check);
4371 }
4372
4373 int32Result(gprResult, node);
4374 return;
4375 }
4376
4377#if USE(JSVALUE64)
4378 case Int52RepUse: {
4379 ASSERT(shouldCheckOverflow(node->arithMode()));
4380 ASSERT(!shouldCheckNegativeZero(node->arithMode()));
4381
4382 // Will we need an overflow check? If we can prove that neither input can be
4383 // Int52 then the overflow check will not be necessary.
4384 if (!m_state.forNode(node->child1()).couldBeType(SpecNonInt32AsInt52)
4385 && !m_state.forNode(node->child2()).couldBeType(SpecNonInt32AsInt52)) {
4386 SpeculateWhicheverInt52Operand op1(this, node->child1());
4387 SpeculateWhicheverInt52Operand op2(this, node->child2(), op1);
4388 GPRTemporary result(this, Reuse, op1);
4389 m_jit.add64(op1.gpr(), op2.gpr(), result.gpr());
4390 int52Result(result.gpr(), node, op1.format());
4391 return;
4392 }
4393
4394 SpeculateInt52Operand op1(this, node->child1());
4395 SpeculateInt52Operand op2(this, node->child2());
4396 GPRTemporary result(this);
4397 m_jit.move(op1.gpr(), result.gpr());
4398 speculationCheck(
4399 Int52Overflow, JSValueRegs(), 0,
4400 m_jit.branchAdd64(MacroAssembler::Overflow, op2.gpr(), result.gpr()));
4401 int52Result(result.gpr(), node);
4402 return;
4403 }
4404#endif // USE(JSVALUE64)
4405
4406 case DoubleRepUse: {
4407 SpeculateDoubleOperand op1(this, node->child1());
4408 SpeculateDoubleOperand op2(this, node->child2());
4409 FPRTemporary result(this, op1, op2);
4410
4411 FPRReg reg1 = op1.fpr();
4412 FPRReg reg2 = op2.fpr();
4413 m_jit.addDouble(reg1, reg2, result.fpr());
4414
4415 doubleResult(result.fpr(), node);
4416 return;
4417 }
4418
4419 default:
4420 RELEASE_ASSERT_NOT_REACHED();
4421 break;
4422 }
4423}
4424
4425void SpeculativeJIT::compileArithAbs(Node* node)
4426{
4427 switch (node->child1().useKind()) {
4428 case Int32Use: {
4429 SpeculateStrictInt32Operand op1(this, node->child1());
4430 GPRTemporary result(this, Reuse, op1);
4431 GPRTemporary scratch(this);
4432
4433 m_jit.move(op1.gpr(), result.gpr());
4434 m_jit.rshift32(result.gpr(), MacroAssembler::TrustedImm32(31), scratch.gpr());
4435 m_jit.add32(scratch.gpr(), result.gpr());
4436 m_jit.xor32(scratch.gpr(), result.gpr());
4437 if (shouldCheckOverflow(node->arithMode()))
4438 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Signed, result.gpr()));
4439 int32Result(result.gpr(), node);
4440 break;
4441 }
4442
4443 case DoubleRepUse: {
4444 SpeculateDoubleOperand op1(this, node->child1());
4445 FPRTemporary result(this);
4446
4447 m_jit.absDouble(op1.fpr(), result.fpr());
4448 doubleResult(result.fpr(), node);
4449 break;
4450 }
4451
4452 default: {
4453 DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse, node->child1().useKind());
4454 JSValueOperand op1(this, node->child1());
4455 JSValueRegs op1Regs = op1.jsValueRegs();
4456 flushRegisters();
4457 FPRResult result(this);
4458 callOperation(operationArithAbs, result.fpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs);
4459 m_jit.exceptionCheck();
4460 doubleResult(result.fpr(), node);
4461 break;
4462 }
4463 }
4464}
4465
4466void SpeculativeJIT::compileArithClz32(Node* node)
4467{
4468 if (node->child1().useKind() == Int32Use || node->child1().useKind() == KnownInt32Use) {
4469 SpeculateInt32Operand value(this, node->child1());
4470 GPRTemporary result(this, Reuse, value);
4471 GPRReg valueReg = value.gpr();
4472 GPRReg resultReg = result.gpr();
4473 m_jit.countLeadingZeros32(valueReg, resultReg);
4474 int32Result(resultReg, node);
4475 return;
4476 }
4477 JSValueOperand op1(this, node->child1());
4478 JSValueRegs op1Regs = op1.jsValueRegs();
4479 GPRTemporary result(this);
4480 GPRReg resultReg = result.gpr();
4481 flushRegisters();
4482 callOperation(operationArithClz32, resultReg, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs);
4483 m_jit.exceptionCheck();
4484 int32Result(resultReg, node);
4485}
4486
4487void SpeculativeJIT::compileArithDoubleUnaryOp(Node* node, double (*doubleFunction)(double), double (*operation)(JSGlobalObject*, EncodedJSValue))
4488{
4489 if (node->child1().useKind() == DoubleRepUse) {
4490 SpeculateDoubleOperand op1(this, node->child1());
4491 FPRReg op1FPR = op1.fpr();
4492
4493 flushRegisters();
4494
4495 FPRResult result(this);
4496 callOperation(doubleFunction, result.fpr(), op1FPR);
4497
4498 doubleResult(result.fpr(), node);
4499 return;
4500 }
4501
4502 JSValueOperand op1(this, node->child1());
4503 JSValueRegs op1Regs = op1.jsValueRegs();
4504 flushRegisters();
4505 FPRResult result(this);
4506 callOperation(operation, result.fpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs);
4507 m_jit.exceptionCheck();
4508 doubleResult(result.fpr(), node);
4509}
4510
4511void SpeculativeJIT::compileArithSub(Node* node)
4512{
4513 switch (node->binaryUseKind()) {
4514 case Int32Use: {
4515 ASSERT(!shouldCheckNegativeZero(node->arithMode()));
4516
4517 if (node->child2()->isInt32Constant()) {
4518 SpeculateInt32Operand op1(this, node->child1());
4519 int32_t imm2 = node->child2()->asInt32();
4520 GPRTemporary result(this);
4521
4522 if (!shouldCheckOverflow(node->arithMode())) {
4523 m_jit.move(op1.gpr(), result.gpr());
4524 m_jit.sub32(Imm32(imm2), result.gpr());
4525 } else {
4526 GPRTemporary scratch(this);
4527 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr(), scratch.gpr()));
4528 }
4529
4530 int32Result(result.gpr(), node);
4531 return;
4532 }
4533
4534 if (node->child1()->isInt32Constant()) {
4535 int32_t imm1 = node->child1()->asInt32();
4536 SpeculateInt32Operand op2(this, node->child2());
4537 GPRTemporary result(this);
4538
4539 m_jit.move(Imm32(imm1), result.gpr());
4540 if (!shouldCheckOverflow(node->arithMode()))
4541 m_jit.sub32(op2.gpr(), result.gpr());
4542 else
4543 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchSub32(MacroAssembler::Overflow, op2.gpr(), result.gpr()));
4544
4545 int32Result(result.gpr(), node);
4546 return;
4547 }
4548
4549 SpeculateInt32Operand op1(this, node->child1());
4550 SpeculateInt32Operand op2(this, node->child2());
4551 GPRTemporary result(this);
4552
4553 if (!shouldCheckOverflow(node->arithMode())) {
4554 m_jit.move(op1.gpr(), result.gpr());
4555 m_jit.sub32(op2.gpr(), result.gpr());
4556 } else
4557 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr()));
4558
4559 int32Result(result.gpr(), node);
4560 return;
4561 }
4562
4563#if USE(JSVALUE64)
4564 case Int52RepUse: {
4565 ASSERT(shouldCheckOverflow(node->arithMode()));
4566 ASSERT(!shouldCheckNegativeZero(node->arithMode()));
4567
4568 // Will we need an overflow check? If we can prove that neither input can be
4569 // Int52 then the overflow check will not be necessary.
4570 if (!m_state.forNode(node->child1()).couldBeType(SpecNonInt32AsInt52)
4571 && !m_state.forNode(node->child2()).couldBeType(SpecNonInt32AsInt52)) {
4572 SpeculateWhicheverInt52Operand op1(this, node->child1());
4573 SpeculateWhicheverInt52Operand op2(this, node->child2(), op1);
4574 GPRTemporary result(this, Reuse, op1);
4575 m_jit.move(op1.gpr(), result.gpr());
4576 m_jit.sub64(op2.gpr(), result.gpr());
4577 int52Result(result.gpr(), node, op1.format());
4578 return;
4579 }
4580
4581 SpeculateInt52Operand op1(this, node->child1());
4582 SpeculateInt52Operand op2(this, node->child2());
4583 GPRTemporary result(this);
4584 m_jit.move(op1.gpr(), result.gpr());
4585 speculationCheck(
4586 Int52Overflow, JSValueRegs(), 0,
4587 m_jit.branchSub64(MacroAssembler::Overflow, op2.gpr(), result.gpr()));
4588 int52Result(result.gpr(), node);
4589 return;
4590 }
4591#endif // USE(JSVALUE64)
4592
4593 case DoubleRepUse: {
4594 SpeculateDoubleOperand op1(this, node->child1());
4595 SpeculateDoubleOperand op2(this, node->child2());
4596 FPRTemporary result(this, op1);
4597
4598 FPRReg reg1 = op1.fpr();
4599 FPRReg reg2 = op2.fpr();
4600 m_jit.subDouble(reg1, reg2, result.fpr());
4601
4602 doubleResult(result.fpr(), node);
4603 return;
4604 }
4605
4606 default:
4607 RELEASE_ASSERT_NOT_REACHED();
4608 return;
4609 }
4610}
4611
4612void SpeculativeJIT::compileIncOrDec(Node* node)
4613{
4614 // In all other cases the node should have been transformed into an add or a sub by FixupPhase
4615 ASSERT(node->child1().useKind() == UntypedUse);
4616
4617 JSValueOperand op1(this, node->child1());
4618 JSValueRegs op1Regs = op1.jsValueRegs();
4619 flushRegisters();
4620 JSValueRegsFlushedCallResult result(this);
4621 JSValueRegs resultRegs = result.regs();
4622 auto operation = node->op() == Inc ? operationInc : operationDec;
4623 callOperation(operation, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs);
4624 m_jit.exceptionCheck();
4625 jsValueResult(resultRegs, node);
4626}
4627
4628void SpeculativeJIT::compileValueNegate(Node* node)
4629{
4630 CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
4631 BytecodeIndex bytecodeIndex = node->origin.semantic.bytecodeIndex();
4632 UnaryArithProfile* arithProfile = baselineCodeBlock->unaryArithProfileForBytecodeIndex(bytecodeIndex);
4633 JITNegIC* negIC = m_jit.codeBlock()->addJITNegIC(arithProfile);
4634 auto repatchingFunction = operationArithNegateOptimize;
4635 auto nonRepatchingFunction = operationArithNegate;
4636 bool needsScratchGPRReg = true;
4637 compileMathIC(node, negIC, needsScratchGPRReg, repatchingFunction, nonRepatchingFunction);
4638}
4639
4640void SpeculativeJIT::compileArithNegate(Node* node)
4641{
4642 switch (node->child1().useKind()) {
4643 case Int32Use: {
4644 SpeculateInt32Operand op1(this, node->child1());
4645 GPRTemporary result(this);
4646
4647 m_jit.move(op1.gpr(), result.gpr());
4648
4649 // Note: there is no notion of being not used as a number, but someone
4650 // caring about negative zero.
4651
4652 if (!shouldCheckOverflow(node->arithMode()))
4653 m_jit.neg32(result.gpr());
4654 else if (!shouldCheckNegativeZero(node->arithMode()))
4655 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchNeg32(MacroAssembler::Overflow, result.gpr()));
4656 else {
4657 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Zero, result.gpr(), TrustedImm32(0x7fffffff)));
4658 m_jit.neg32(result.gpr());
4659 }
4660
4661 int32Result(result.gpr(), node);
4662 return;
4663 }
4664
4665#if USE(JSVALUE64)
4666 case Int52RepUse: {
4667 ASSERT(shouldCheckOverflow(node->arithMode()));
4668
4669 if (!m_state.forNode(node->child1()).couldBeType(SpecNonInt32AsInt52)) {
4670 SpeculateWhicheverInt52Operand op1(this, node->child1());
4671 GPRTemporary result(this);
4672 GPRReg op1GPR = op1.gpr();
4673 GPRReg resultGPR = result.gpr();
4674 m_jit.move(op1GPR, resultGPR);
4675 m_jit.neg64(resultGPR);
4676 if (shouldCheckNegativeZero(node->arithMode())) {
4677 speculationCheck(
4678 NegativeZero, JSValueRegs(), 0,
4679 m_jit.branchTest64(MacroAssembler::Zero, resultGPR));
4680 }
4681 int52Result(resultGPR, node, op1.format());
4682 return;
4683 }
4684
4685 SpeculateInt52Operand op1(this, node->child1());
4686 GPRTemporary result(this);
4687 GPRReg op1GPR = op1.gpr();
4688 GPRReg resultGPR = result.gpr();
4689 m_jit.move(op1GPR, resultGPR);
4690 speculationCheck(
4691 Int52Overflow, JSValueRegs(), 0,
4692 m_jit.branchNeg64(MacroAssembler::Overflow, resultGPR));
4693 if (shouldCheckNegativeZero(node->arithMode())) {
4694 speculationCheck(
4695 NegativeZero, JSValueRegs(), 0,
4696 m_jit.branchTest64(MacroAssembler::Zero, resultGPR));
4697 }
4698 int52Result(resultGPR, node);
4699 return;
4700 }
4701#endif // USE(JSVALUE64)
4702
4703 case DoubleRepUse: {
4704 SpeculateDoubleOperand op1(this, node->child1());
4705 FPRTemporary result(this);
4706
4707 m_jit.negateDouble(op1.fpr(), result.fpr());
4708
4709 doubleResult(result.fpr(), node);
4710 return;
4711 }
4712
4713 default: {
4714 RELEASE_ASSERT_NOT_REACHED();
4715 }
4716 }
4717}
4718
4719template <typename Generator, typename RepatchingFunction, typename NonRepatchingFunction>
4720void SpeculativeJIT::compileMathIC(Node* node, JITUnaryMathIC<Generator>* mathIC, bool needsScratchGPRReg, RepatchingFunction repatchingFunction, NonRepatchingFunction nonRepatchingFunction)
4721{
4722 GPRReg scratchGPR = InvalidGPRReg;
4723 Optional<GPRTemporary> gprScratch;
4724 if (needsScratchGPRReg) {
4725 gprScratch.emplace(this);
4726 scratchGPR = gprScratch->gpr();
4727 }
4728 JSValueOperand childOperand(this, node->child1());
4729 JSValueRegs childRegs = childOperand.jsValueRegs();
4730#if USE(JSVALUE64)
4731 GPRTemporary result(this, Reuse, childOperand);
4732 JSValueRegs resultRegs(result.gpr());
4733#else
4734 GPRTemporary resultTag(this);
4735 GPRTemporary resultPayload(this);
4736 JSValueRegs resultRegs(resultPayload.gpr(), resultTag.gpr());
4737#endif
4738
4739#if ENABLE(MATH_IC_STATS)
4740 auto inlineStart = m_jit.label();
4741#endif
4742
4743 Box<MathICGenerationState> icGenerationState = Box<MathICGenerationState>::create();
4744 mathIC->m_generator = Generator(resultRegs, childRegs, scratchGPR);
4745
4746 bool shouldEmitProfiling = false;
4747 bool generatedInline = mathIC->generateInline(m_jit, *icGenerationState, shouldEmitProfiling);
4748 if (generatedInline) {
4749 ASSERT(!icGenerationState->slowPathJumps.empty());
4750
4751 Vector<SilentRegisterSavePlan> savePlans;
4752 silentSpillAllRegistersImpl(false, savePlans, resultRegs);
4753
4754 auto done = m_jit.label();
4755
4756 addSlowPathGeneratorLambda([=, savePlans = WTFMove(savePlans)] () {
4757 icGenerationState->slowPathJumps.link(&m_jit);
4758 icGenerationState->slowPathStart = m_jit.label();
4759#if ENABLE(MATH_IC_STATS)
4760 auto slowPathStart = m_jit.label();
4761#endif
4762
4763 silentSpill(savePlans);
4764
4765 if (icGenerationState->shouldSlowPathRepatch)
4766 icGenerationState->slowPathCall = callOperation(bitwise_cast<J_JITOperation_GJMic>(repatchingFunction), resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), childRegs, TrustedImmPtr(mathIC));
4767 else
4768 icGenerationState->slowPathCall = callOperation(nonRepatchingFunction, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), childRegs);
4769
4770 silentFill(savePlans);
4771 m_jit.exceptionCheck();
4772 m_jit.jump().linkTo(done, &m_jit);
4773
4774 m_jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
4775 mathIC->finalizeInlineCode(*icGenerationState, linkBuffer);
4776 });
4777
4778#if ENABLE(MATH_IC_STATS)
4779 auto slowPathEnd = m_jit.label();
4780 m_jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
4781 size_t size = static_cast<char*>(linkBuffer.locationOf(slowPathEnd).executableAddress()) - static_cast<char*>(linkBuffer.locationOf(slowPathStart).executableAddress());
4782 mathIC->m_generatedCodeSize += size;
4783 });
4784#endif
4785
4786 });
4787 } else {
4788 flushRegisters();
4789 callOperation(nonRepatchingFunction, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), childRegs);
4790 m_jit.exceptionCheck();
4791 }
4792
4793#if ENABLE(MATH_IC_STATS)
4794 auto inlineEnd = m_jit.label();
4795 m_jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
4796 size_t size = static_cast<char*>(linkBuffer.locationOf(inlineEnd).executableAddress()) - static_cast<char*>(linkBuffer.locationOf(inlineStart).executableAddress());
4797 mathIC->m_generatedCodeSize += size;
4798 });
4799#endif
4800
4801 jsValueResult(resultRegs, node);
4802 return;
4803}
4804
4805void SpeculativeJIT::compileValueMul(Node* node)
4806{
4807 Edge& leftChild = node->child1();
4808 Edge& rightChild = node->child2();
4809
4810 if (leftChild.useKind() == BigIntUse && rightChild.useKind() == BigIntUse) {
4811 SpeculateCellOperand left(this, leftChild);
4812 SpeculateCellOperand right(this, rightChild);
4813 GPRReg leftGPR = left.gpr();
4814 GPRReg rightGPR = right.gpr();
4815
4816 speculateBigInt(leftChild, leftGPR);
4817 speculateBigInt(rightChild, rightGPR);
4818
4819 flushRegisters();
4820 GPRFlushedCallResult result(this);
4821 GPRReg resultGPR = result.gpr();
4822
4823 callOperation(operationMulBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
4824
4825 m_jit.exceptionCheck();
4826 cellResult(resultGPR, node);
4827 return;
4828 }
4829
4830 if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
4831 JSValueOperand left(this, leftChild);
4832 JSValueOperand right(this, rightChild);
4833 JSValueRegs leftRegs = left.jsValueRegs();
4834 JSValueRegs rightRegs = right.jsValueRegs();
4835
4836 flushRegisters();
4837 JSValueRegsFlushedCallResult result(this);
4838 JSValueRegs resultRegs = result.regs();
4839 callOperation(operationValueMul, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftRegs, rightRegs);
4840 m_jit.exceptionCheck();
4841
4842 jsValueResult(resultRegs, node);
4843 return;
4844 }
4845
4846 bool needsScratchGPRReg = true;
4847#if USE(JSVALUE64)
4848 bool needsScratchFPRReg = false;
4849#else
4850 bool needsScratchFPRReg = true;
4851#endif
4852
4853 CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
4854 BytecodeIndex bytecodeIndex = node->origin.semantic.bytecodeIndex();
4855 BinaryArithProfile* arithProfile = baselineCodeBlock->binaryArithProfileForBytecodeIndex(bytecodeIndex);
4856 JITMulIC* mulIC = m_jit.codeBlock()->addJITMulIC(arithProfile);
4857 auto repatchingFunction = operationValueMulOptimize;
4858 auto nonRepatchingFunction = operationValueMul;
4859
4860 compileMathIC(node, mulIC, needsScratchGPRReg, needsScratchFPRReg, repatchingFunction, nonRepatchingFunction);
4861}
4862
4863void SpeculativeJIT::compileArithMul(Node* node)
4864{
4865 switch (node->binaryUseKind()) {
4866 case Int32Use: {
4867 if (node->child2()->isInt32Constant()) {
4868 SpeculateInt32Operand op1(this, node->child1());
4869 GPRTemporary result(this);
4870
4871 int32_t imm = node->child2()->asInt32();
4872 GPRReg op1GPR = op1.gpr();
4873 GPRReg resultGPR = result.gpr();
4874
4875 if (!shouldCheckOverflow(node->arithMode()))
4876 m_jit.mul32(Imm32(imm), op1GPR, resultGPR);
4877 else {
4878 speculationCheck(Overflow, JSValueRegs(), 0,
4879 m_jit.branchMul32(MacroAssembler::Overflow, op1GPR, Imm32(imm), resultGPR));
4880 }
4881
4882 // The only way to create negative zero with a constant is:
4883 // -negative-op1 * 0.
4884 // -zero-op1 * negative constant.
4885 if (shouldCheckNegativeZero(node->arithMode())) {
4886 if (!imm)
4887 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Signed, op1GPR));
4888 else if (imm < 0) {
4889 if (shouldCheckOverflow(node->arithMode()))
4890 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Zero, resultGPR));
4891 else
4892 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Zero, op1GPR));
4893 }
4894 }
4895
4896 int32Result(resultGPR, node);
4897 return;
4898 }
4899 SpeculateInt32Operand op1(this, node->child1());
4900 SpeculateInt32Operand op2(this, node->child2());
4901 GPRTemporary result(this);
4902
4903 GPRReg reg1 = op1.gpr();
4904 GPRReg reg2 = op2.gpr();
4905
4906 // We can perform truncated multiplications if we get to this point, because if the
4907 // fixup phase could not prove that it would be safe, it would have turned us into
4908 // a double multiplication.
4909 if (!shouldCheckOverflow(node->arithMode()))
4910 m_jit.mul32(reg1, reg2, result.gpr());
4911 else {
4912 speculationCheck(
4913 Overflow, JSValueRegs(), 0,
4914 m_jit.branchMul32(MacroAssembler::Overflow, reg1, reg2, result.gpr()));
4915 }
4916
4917 // Check for negative zero, if the users of this node care about such things.
4918 if (shouldCheckNegativeZero(node->arithMode())) {
4919 MacroAssembler::Jump resultNonZero = m_jit.branchTest32(MacroAssembler::NonZero, result.gpr());
4920 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Signed, reg1));
4921 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Signed, reg2));
4922 resultNonZero.link(&m_jit);
4923 }
4924
4925 int32Result(result.gpr(), node);
4926 return;
4927 }
4928
4929#if USE(JSVALUE64)
4930 case Int52RepUse: {
4931 ASSERT(shouldCheckOverflow(node->arithMode()));
4932
4933 // This is super clever. We want to do an int52 multiplication and check the
4934 // int52 overflow bit. There is no direct hardware support for this, but we do
4935 // have the ability to do an int64 multiplication and check the int64 overflow
4936 // bit. We leverage that. Consider that a, b are int52 numbers inside int64
4937 // registers, with the high 12 bits being sign-extended. We can do:
4938 //
4939 // (a * (b << 12))
4940 //
4941 // This will give us a left-shifted int52 (value is in high 52 bits, low 16
4942 // bits are zero) plus the int52 overflow bit. I.e. whether this 64-bit
4943 // multiplication overflows is identical to whether the 'a * b' 52-bit
4944 // multiplication overflows.
4945 //
4946 // In our nomenclature, this is:
4947 //
4948 // strictInt52(a) * int52(b) => int52
4949 //
4950 // That is "strictInt52" means unshifted and "int52" means left-shifted by 16
4951 // bits.
4952 //
4953 // We don't care which of op1 or op2 serves as the left-shifted operand, so
4954 // we just do whatever is more convenient for op1 and have op2 do the
4955 // opposite. This ensures that we do at most one shift.
4956
4957 SpeculateWhicheverInt52Operand op1(this, node->child1());
4958 SpeculateWhicheverInt52Operand op2(this, node->child2(), OppositeShift, op1);
4959 GPRTemporary result(this);
4960
4961 GPRReg op1GPR = op1.gpr();
4962 GPRReg op2GPR = op2.gpr();
4963 GPRReg resultGPR = result.gpr();
4964
4965 m_jit.move(op1GPR, resultGPR);
4966 speculationCheck(
4967 Int52Overflow, JSValueRegs(), 0,
4968 m_jit.branchMul64(MacroAssembler::Overflow, op2GPR, resultGPR));
4969
4970 if (shouldCheckNegativeZero(node->arithMode())) {
4971 MacroAssembler::Jump resultNonZero = m_jit.branchTest64(
4972 MacroAssembler::NonZero, resultGPR);
4973 speculationCheck(
4974 NegativeZero, JSValueRegs(), 0,
4975 m_jit.branch64(MacroAssembler::LessThan, op1GPR, TrustedImm32(0)));
4976 speculationCheck(
4977 NegativeZero, JSValueRegs(), 0,
4978 m_jit.branch64(MacroAssembler::LessThan, op2GPR, TrustedImm32(0)));
4979 resultNonZero.link(&m_jit);
4980 }
4981
4982 int52Result(resultGPR, node);
4983 return;
4984 }
4985#endif // USE(JSVALUE64)
4986
4987 case DoubleRepUse: {
4988 SpeculateDoubleOperand op1(this, node->child1());
4989 SpeculateDoubleOperand op2(this, node->child2());
4990 FPRTemporary result(this, op1, op2);
4991
4992 FPRReg reg1 = op1.fpr();
4993 FPRReg reg2 = op2.fpr();
4994
4995 m_jit.mulDouble(reg1, reg2, result.fpr());
4996
4997 doubleResult(result.fpr(), node);
4998 return;
4999 }
5000
5001 default:
5002 RELEASE_ASSERT_NOT_REACHED();
5003 return;
5004 }
5005}
5006
5007void SpeculativeJIT::compileValueDiv(Node* node)
5008{
5009 Edge& leftChild = node->child1();
5010 Edge& rightChild = node->child2();
5011
5012 if (leftChild.useKind() == BigIntUse && rightChild.useKind() == BigIntUse) {
5013 SpeculateCellOperand left(this, leftChild);
5014 SpeculateCellOperand right(this, rightChild);
5015 GPRReg leftGPR = left.gpr();
5016 GPRReg rightGPR = right.gpr();
5017
5018 speculateBigInt(leftChild, leftGPR);
5019 speculateBigInt(rightChild, rightGPR);
5020
5021 flushRegisters();
5022 GPRFlushedCallResult result(this);
5023 GPRReg resultGPR = result.gpr();
5024
5025 callOperation(operationDivBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
5026
5027 m_jit.exceptionCheck();
5028 cellResult(resultGPR, node);
5029 return;
5030 }
5031
5032 if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
5033 JSValueOperand left(this, leftChild);
5034 JSValueOperand right(this, rightChild);
5035 JSValueRegs leftRegs = left.jsValueRegs();
5036 JSValueRegs rightRegs = right.jsValueRegs();
5037
5038 flushRegisters();
5039 JSValueRegsFlushedCallResult result(this);
5040 JSValueRegs resultRegs = result.regs();
5041 callOperation(operationValueDiv, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftRegs, rightRegs);
5042 m_jit.exceptionCheck();
5043
5044 jsValueResult(resultRegs, node);
5045 return;
5046 }
5047
5048 Optional<JSValueOperand> left;
5049 Optional<JSValueOperand> right;
5050
5051 JSValueRegs leftRegs;
5052 JSValueRegs rightRegs;
5053
5054 FPRTemporary leftNumber(this);
5055 FPRTemporary rightNumber(this);
5056 FPRReg leftFPR = leftNumber.fpr();
5057 FPRReg rightFPR = rightNumber.fpr();
5058 FPRTemporary fprScratch(this);
5059 FPRReg scratchFPR = fprScratch.fpr();
5060
5061#if USE(JSVALUE64)
5062 GPRTemporary result(this);
5063 JSValueRegs resultRegs = JSValueRegs(result.gpr());
5064 GPRTemporary scratch(this);
5065 GPRReg scratchGPR = scratch.gpr();
5066#else
5067 GPRTemporary resultTag(this);
5068 GPRTemporary resultPayload(this);
5069 JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
5070 GPRReg scratchGPR = resultTag.gpr();
5071#endif
5072
5073 SnippetOperand leftOperand(m_state.forNode(leftChild).resultType());
5074 SnippetOperand rightOperand(m_state.forNode(rightChild).resultType());
5075
5076 if (leftChild->isInt32Constant())
5077 leftOperand.setConstInt32(leftChild->asInt32());
5078#if USE(JSVALUE64)
5079 else if (leftChild->isDoubleConstant())
5080 leftOperand.setConstDouble(leftChild->asNumber());
5081#endif
5082
5083 if (leftOperand.isConst()) {
5084 // The snippet generator only supports 1 argument as a constant.
5085 // Ignore the rightChild's const-ness.
5086 } else if (rightChild->isInt32Constant())
5087 rightOperand.setConstInt32(rightChild->asInt32());
5088#if USE(JSVALUE64)
5089 else if (rightChild->isDoubleConstant())
5090 rightOperand.setConstDouble(rightChild->asNumber());
5091#endif
5092
5093 RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
5094
5095 if (!leftOperand.isConst()) {
5096 left.emplace(this, leftChild);
5097 leftRegs = left->jsValueRegs();
5098 }
5099 if (!rightOperand.isConst()) {
5100 right.emplace(this, rightChild);
5101 rightRegs = right->jsValueRegs();
5102 }
5103
5104 JITDivGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs,
5105 leftFPR, rightFPR, scratchGPR, scratchFPR);
5106 gen.generateFastPath(m_jit);
5107
5108 ASSERT(gen.didEmitFastPath());
5109 gen.endJumpList().append(m_jit.jump());
5110
5111 gen.slowPathJumpList().link(&m_jit);
5112 silentSpillAllRegisters(resultRegs);
5113
5114 if (leftOperand.isConst()) {
5115 leftRegs = resultRegs;
5116 m_jit.moveValue(leftChild->asJSValue(), leftRegs);
5117 }
5118 if (rightOperand.isConst()) {
5119 rightRegs = resultRegs;
5120 m_jit.moveValue(rightChild->asJSValue(), rightRegs);
5121 }
5122
5123 callOperation(operationValueDiv, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftRegs, rightRegs);
5124
5125 silentFillAllRegisters();
5126 m_jit.exceptionCheck();
5127
5128 gen.endJumpList().link(&m_jit);
5129 jsValueResult(resultRegs, node);
5130}
5131
5132void SpeculativeJIT::compileArithDiv(Node* node)
5133{
5134 switch (node->binaryUseKind()) {
5135 case Int32Use: {
5136#if CPU(X86_64)
5137 SpeculateInt32Operand op1(this, node->child1());
5138 SpeculateInt32Operand op2(this, node->child2());
5139 GPRTemporary eax(this, X86Registers::eax);
5140 GPRTemporary edx(this, X86Registers::edx);
5141 GPRReg op1GPR = op1.gpr();
5142 GPRReg op2GPR = op2.gpr();
5143
5144 GPRReg op2TempGPR;
5145 GPRReg temp;
5146 if (op2GPR == X86Registers::eax || op2GPR == X86Registers::edx) {
5147 op2TempGPR = allocate();
5148 temp = op2TempGPR;
5149 } else {
5150 op2TempGPR = InvalidGPRReg;
5151 if (op1GPR == X86Registers::eax)
5152 temp = X86Registers::edx;
5153 else
5154 temp = X86Registers::eax;
5155 }
5156
5157 ASSERT(temp != op1GPR);
5158 ASSERT(temp != op2GPR);
5159
5160 m_jit.add32(JITCompiler::TrustedImm32(1), op2GPR, temp);
5161
5162 JITCompiler::Jump safeDenominator = m_jit.branch32(JITCompiler::Above, temp, JITCompiler::TrustedImm32(1));
5163
5164 JITCompiler::JumpList done;
5165 if (shouldCheckOverflow(node->arithMode())) {
5166 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, op2GPR));
5167 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(JITCompiler::Equal, op1GPR, TrustedImm32(-2147483647-1)));
5168 } else {
5169 // This is the case where we convert the result to an int after we're done, and we
5170 // already know that the denominator is either -1 or 0. So, if the denominator is
5171 // zero, then the result should be zero. If the denominator is not zero (i.e. it's
5172 // -1) and the numerator is -2^31 then the result should be -2^31. Otherwise we
5173 // are happy to fall through to a normal division, since we're just dividing
5174 // something by negative 1.
5175
5176 JITCompiler::Jump notZero = m_jit.branchTest32(JITCompiler::NonZero, op2GPR);
5177 m_jit.move(TrustedImm32(0), eax.gpr());
5178 done.append(m_jit.jump());
5179
5180 notZero.link(&m_jit);
5181 JITCompiler::Jump notNeg2ToThe31 =
5182 m_jit.branch32(JITCompiler::NotEqual, op1GPR, TrustedImm32(-2147483647-1));
5183 m_jit.zeroExtend32ToPtr(op1GPR, eax.gpr());
5184 done.append(m_jit.jump());
5185
5186 notNeg2ToThe31.link(&m_jit);
5187 }
5188
5189 safeDenominator.link(&m_jit);
5190
5191 // If the user cares about negative zero, then speculate that we're not about
5192 // to produce negative zero.
5193 if (shouldCheckNegativeZero(node->arithMode())) {
5194 MacroAssembler::Jump numeratorNonZero = m_jit.branchTest32(MacroAssembler::NonZero, op1GPR);
5195 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, op2GPR, TrustedImm32(0)));
5196 numeratorNonZero.link(&m_jit);
5197 }
5198
5199 if (op2TempGPR != InvalidGPRReg) {
5200 m_jit.move(op2GPR, op2TempGPR);
5201 op2GPR = op2TempGPR;
5202 }
5203
5204 m_jit.move(op1GPR, eax.gpr());
5205 m_jit.x86ConvertToDoubleWord32();
5206 m_jit.x86Div32(op2GPR);
5207
5208 if (op2TempGPR != InvalidGPRReg)
5209 unlock(op2TempGPR);
5210
5211 // Check that there was no remainder. If there had been, then we'd be obligated to
5212 // produce a double result instead.
5213 if (shouldCheckOverflow(node->arithMode()))
5214 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::NonZero, edx.gpr()));
5215
5216 done.link(&m_jit);
5217 int32Result(eax.gpr(), node);
5218#elif HAVE(ARM_IDIV_INSTRUCTIONS) || CPU(ARM64)
5219 SpeculateInt32Operand op1(this, node->child1());
5220 SpeculateInt32Operand op2(this, node->child2());
5221 GPRReg op1GPR = op1.gpr();
5222 GPRReg op2GPR = op2.gpr();
5223 GPRTemporary quotient(this);
5224 GPRTemporary multiplyAnswer(this);
5225
5226 // If the user cares about negative zero, then speculate that we're not about
5227 // to produce negative zero.
5228 if (shouldCheckNegativeZero(node->arithMode())) {
5229 MacroAssembler::Jump numeratorNonZero = m_jit.branchTest32(MacroAssembler::NonZero, op1GPR);
5230 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, op2GPR, TrustedImm32(0)));
5231 numeratorNonZero.link(&m_jit);
5232 }
5233
5234 if (shouldCheckOverflow(node->arithMode()))
5235 speculationCheck(Overflow, JSValueRegs(), nullptr, m_jit.branchTest32(MacroAssembler::Zero, op2GPR));
5236
5237 m_jit.assembler().sdiv<32>(quotient.gpr(), op1GPR, op2GPR);
5238
5239 // Check that there was no remainder. If there had been, then we'd be obligated to
5240 // produce a double result instead.
5241 if (shouldCheckOverflow(node->arithMode())) {
5242 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchMul32(JITCompiler::Overflow, quotient.gpr(), op2GPR, multiplyAnswer.gpr()));
5243 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(JITCompiler::NotEqual, multiplyAnswer.gpr(), op1GPR));
5244 }
5245
5246 int32Result(quotient.gpr(), node);
5247#else
5248 RELEASE_ASSERT_NOT_REACHED();
5249#endif
5250 break;
5251 }
5252
5253 case DoubleRepUse: {
5254 SpeculateDoubleOperand op1(this, node->child1());
5255 SpeculateDoubleOperand op2(this, node->child2());
5256 FPRTemporary result(this, op1);
5257
5258 FPRReg reg1 = op1.fpr();
5259 FPRReg reg2 = op2.fpr();
5260 m_jit.divDouble(reg1, reg2, result.fpr());
5261
5262 doubleResult(result.fpr(), node);
5263 break;
5264 }
5265
5266 default:
5267 RELEASE_ASSERT_NOT_REACHED();
5268 break;
5269 }
5270}
5271
5272void SpeculativeJIT::compileArithFRound(Node* node)
5273{
5274 if (node->child1().useKind() == DoubleRepUse) {
5275 SpeculateDoubleOperand op1(this, node->child1());
5276 FPRTemporary result(this, op1);
5277 m_jit.convertDoubleToFloat(op1.fpr(), result.fpr());
5278 m_jit.convertFloatToDouble(result.fpr(), result.fpr());
5279 doubleResult(result.fpr(), node);
5280 return;
5281 }
5282
5283 JSValueOperand op1(this, node->child1());
5284 JSValueRegs op1Regs = op1.jsValueRegs();
5285 flushRegisters();
5286 FPRResult result(this);
5287 callOperation(operationArithFRound, result.fpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs);
5288 m_jit.exceptionCheck();
5289 doubleResult(result.fpr(), node);
5290}
5291
5292void SpeculativeJIT::compileValueMod(Node* node)
5293{
5294 Edge& leftChild = node->child1();
5295 Edge& rightChild = node->child2();
5296
5297 if (node->binaryUseKind() == BigIntUse) {
5298 SpeculateCellOperand left(this, leftChild);
5299 SpeculateCellOperand right(this, rightChild);
5300 GPRReg leftGPR = left.gpr();
5301 GPRReg rightGPR = right.gpr();
5302
5303 speculateBigInt(leftChild, leftGPR);
5304 speculateBigInt(rightChild, rightGPR);
5305
5306 flushRegisters();
5307 GPRFlushedCallResult result(this);
5308 GPRReg resultGPR = result.gpr();
5309
5310 callOperation(operationModBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
5311
5312 m_jit.exceptionCheck();
5313 cellResult(resultGPR, node);
5314 return;
5315 }
5316
5317 DFG_ASSERT(m_jit.graph(), node, node->binaryUseKind() == UntypedUse, node->binaryUseKind());
5318 JSValueOperand op1(this, leftChild);
5319 JSValueOperand op2(this, rightChild);
5320 JSValueRegs op1Regs = op1.jsValueRegs();
5321 JSValueRegs op2Regs = op2.jsValueRegs();
5322 flushRegisters();
5323 JSValueRegsFlushedCallResult result(this);
5324 JSValueRegs resultRegs = result.regs();
5325 callOperation(operationValueMod, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs, op2Regs);
5326 m_jit.exceptionCheck();
5327 jsValueResult(resultRegs, node);
5328}
5329
5330void SpeculativeJIT::compileArithMod(Node* node)
5331{
5332 switch (node->binaryUseKind()) {
5333 case Int32Use: {
5334 // In the fast path, the dividend value could be the final result
5335 // (in case of |dividend| < |divisor|), so we speculate it as strict int32.
5336 SpeculateStrictInt32Operand op1(this, node->child1());
5337
5338 if (node->child2()->isInt32Constant()) {
5339 int32_t divisor = node->child2()->asInt32();
5340 if (divisor > 1 && hasOneBitSet(divisor)) {
5341 unsigned logarithm = WTF::fastLog2(static_cast<uint32_t>(divisor));
5342 GPRReg dividendGPR = op1.gpr();
5343 GPRTemporary result(this);
5344 GPRReg resultGPR = result.gpr();
5345
5346 // This is what LLVM generates. It's pretty crazy. Here's my
5347 // attempt at understanding it.
5348
5349 // First, compute either divisor - 1, or 0, depending on whether
5350 // the dividend is negative:
5351 //
5352 // If dividend < 0: resultGPR = divisor - 1
5353 // If dividend >= 0: resultGPR = 0
5354 m_jit.move(dividendGPR, resultGPR);
5355 m_jit.rshift32(TrustedImm32(31), resultGPR);
5356 m_jit.urshift32(TrustedImm32(32 - logarithm), resultGPR);
5357
5358 // Add in the dividend, so that:
5359 //
5360 // If dividend < 0: resultGPR = dividend + divisor - 1
5361 // If dividend >= 0: resultGPR = dividend
5362 m_jit.add32(dividendGPR, resultGPR);
5363
5364 // Mask so as to only get the *high* bits. This rounds down
5365 // (towards negative infinity) resultGPR to the nearest multiple
5366 // of divisor, so that:
5367 //
5368 // If dividend < 0: resultGPR = floor((dividend + divisor - 1) / divisor)
5369 // If dividend >= 0: resultGPR = floor(dividend / divisor)
5370 //
5371 // Note that this can be simplified to:
5372 //
5373 // If dividend < 0: resultGPR = ceil(dividend / divisor)
5374 // If dividend >= 0: resultGPR = floor(dividend / divisor)
5375 //
5376 // Note that if the dividend is negative, resultGPR will also be negative.
5377 // Regardless of the sign of dividend, resultGPR will be rounded towards
5378 // zero, because of how things are conditionalized.
5379 m_jit.and32(TrustedImm32(-divisor), resultGPR);
5380
5381 // Subtract resultGPR from dividendGPR, which yields the remainder:
5382 //
5383 // resultGPR = dividendGPR - resultGPR
5384 m_jit.neg32(resultGPR);
5385 m_jit.add32(dividendGPR, resultGPR);
5386
5387 if (shouldCheckNegativeZero(node->arithMode())) {
5388 // Check that we're not about to create negative zero.
5389 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, dividendGPR, TrustedImm32(0));
5390 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, resultGPR));
5391 numeratorPositive.link(&m_jit);
5392 }
5393
5394 int32Result(resultGPR, node);
5395 return;
5396 }
5397 }
5398
5399#if CPU(X86_64)
5400 if (node->child2()->isInt32Constant()) {
5401 int32_t divisor = node->child2()->asInt32();
5402 if (divisor && divisor != -1) {
5403 GPRReg op1Gpr = op1.gpr();
5404
5405 GPRTemporary eax(this, X86Registers::eax);
5406 GPRTemporary edx(this, X86Registers::edx);
5407 GPRTemporary scratch(this);
5408 GPRReg scratchGPR = scratch.gpr();
5409
5410 GPRReg op1SaveGPR;
5411 if (op1Gpr == X86Registers::eax || op1Gpr == X86Registers::edx) {
5412 op1SaveGPR = allocate();
5413 ASSERT(op1Gpr != op1SaveGPR);
5414 m_jit.move(op1Gpr, op1SaveGPR);
5415 } else
5416 op1SaveGPR = op1Gpr;
5417 ASSERT(op1SaveGPR != X86Registers::eax);
5418 ASSERT(op1SaveGPR != X86Registers::edx);
5419
5420 m_jit.move(op1Gpr, eax.gpr());
5421 m_jit.move(TrustedImm32(divisor), scratchGPR);
5422 m_jit.x86ConvertToDoubleWord32();
5423 m_jit.x86Div32(scratchGPR);
5424 if (shouldCheckNegativeZero(node->arithMode())) {
5425 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, op1SaveGPR, TrustedImm32(0));
5426 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, edx.gpr()));
5427 numeratorPositive.link(&m_jit);
5428 }
5429
5430 if (op1SaveGPR != op1Gpr)
5431 unlock(op1SaveGPR);
5432
5433 int32Result(edx.gpr(), node);
5434 return;
5435 }
5436 }
5437#endif
5438
5439 SpeculateInt32Operand op2(this, node->child2());
5440#if CPU(X86_64)
5441 GPRTemporary eax(this, X86Registers::eax);
5442 GPRTemporary edx(this, X86Registers::edx);
5443 GPRReg op1GPR = op1.gpr();
5444 GPRReg op2GPR = op2.gpr();
5445
5446 GPRReg op2TempGPR;
5447 GPRReg temp;
5448 GPRReg op1SaveGPR;
5449
5450 if (op2GPR == X86Registers::eax || op2GPR == X86Registers::edx) {
5451 op2TempGPR = allocate();
5452 temp = op2TempGPR;
5453 } else {
5454 op2TempGPR = InvalidGPRReg;
5455 if (op1GPR == X86Registers::eax)
5456 temp = X86Registers::edx;
5457 else
5458 temp = X86Registers::eax;
5459 }
5460
5461 if (op1GPR == X86Registers::eax || op1GPR == X86Registers::edx) {
5462 op1SaveGPR = allocate();
5463 ASSERT(op1GPR != op1SaveGPR);
5464 m_jit.move(op1GPR, op1SaveGPR);
5465 } else
5466 op1SaveGPR = op1GPR;
5467
5468 ASSERT(temp != op1GPR);
5469 ASSERT(temp != op2GPR);
5470 ASSERT(op1SaveGPR != X86Registers::eax);
5471 ASSERT(op1SaveGPR != X86Registers::edx);
5472
5473 m_jit.add32(JITCompiler::TrustedImm32(1), op2GPR, temp);
5474
5475 JITCompiler::Jump safeDenominator = m_jit.branch32(JITCompiler::Above, temp, JITCompiler::TrustedImm32(1));
5476
5477 JITCompiler::JumpList done;
5478
5479 // FIXME: -2^31 / -1 will actually yield negative zero, so we could have a
5480 // separate case for that. But it probably doesn't matter so much.
5481 if (shouldCheckOverflow(node->arithMode())) {
5482 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, op2GPR));
5483 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(JITCompiler::Equal, op1GPR, TrustedImm32(-2147483647-1)));
5484 } else {
5485 // This is the case where we convert the result to an int after we're done, and we
5486 // already know that the denominator is either -1 or 0. So, if the denominator is
5487 // zero, then the result should be zero. If the denominator is not zero (i.e. it's
5488 // -1) and the numerator is -2^31 then the result should be 0. Otherwise we are
5489 // happy to fall through to a normal division, since we're just dividing something
5490 // by negative 1.
5491
5492 JITCompiler::Jump notZero = m_jit.branchTest32(JITCompiler::NonZero, op2GPR);
5493 m_jit.move(TrustedImm32(0), edx.gpr());
5494 done.append(m_jit.jump());
5495
5496 notZero.link(&m_jit);
5497 JITCompiler::Jump notNeg2ToThe31 =
5498 m_jit.branch32(JITCompiler::NotEqual, op1GPR, TrustedImm32(-2147483647-1));
5499 m_jit.move(TrustedImm32(0), edx.gpr());
5500 done.append(m_jit.jump());
5501
5502 notNeg2ToThe31.link(&m_jit);
5503 }
5504
5505 safeDenominator.link(&m_jit);
5506
5507 if (op2TempGPR != InvalidGPRReg) {
5508 m_jit.move(op2GPR, op2TempGPR);
5509 op2GPR = op2TempGPR;
5510 }
5511
5512 m_jit.move(op1GPR, eax.gpr());
5513 m_jit.x86ConvertToDoubleWord32();
5514 m_jit.x86Div32(op2GPR);
5515
5516 if (op2TempGPR != InvalidGPRReg)
5517 unlock(op2TempGPR);
5518
5519 // Check that we're not about to create negative zero.
5520 if (shouldCheckNegativeZero(node->arithMode())) {
5521 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, op1SaveGPR, TrustedImm32(0));
5522 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, edx.gpr()));
5523 numeratorPositive.link(&m_jit);
5524 }
5525
5526 if (op1SaveGPR != op1GPR)
5527 unlock(op1SaveGPR);
5528
5529 done.link(&m_jit);
5530 int32Result(edx.gpr(), node);
5531
5532#elif HAVE(ARM_IDIV_INSTRUCTIONS) || CPU(ARM64)
5533 GPRTemporary temp(this);
5534 GPRTemporary quotientThenRemainder(this);
5535 GPRTemporary multiplyAnswer(this);
5536 GPRReg dividendGPR = op1.gpr();
5537 GPRReg divisorGPR = op2.gpr();
5538 GPRReg quotientThenRemainderGPR = quotientThenRemainder.gpr();
5539 GPRReg multiplyAnswerGPR = multiplyAnswer.gpr();
5540
5541 JITCompiler::JumpList done;
5542
5543 if (shouldCheckOverflow(node->arithMode()))
5544 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, divisorGPR));
5545 else {
5546 JITCompiler::Jump denominatorNotZero = m_jit.branchTest32(JITCompiler::NonZero, divisorGPR);
5547 // We know that the low 32-bit of divisorGPR is 0, but we don't know if the high bits are.
5548 // So, use TrustedImm32(0) on ARM instead because done expects the result to be in DataFormatInt32.
5549 // Using an immediate 0 doesn't cost anything extra on ARM.
5550 m_jit.move(TrustedImm32(0), quotientThenRemainderGPR);
5551 done.append(m_jit.jump());
5552 denominatorNotZero.link(&m_jit);
5553 }
5554
5555 m_jit.assembler().sdiv<32>(quotientThenRemainderGPR, dividendGPR, divisorGPR);
5556 // FIXME: It seems like there are cases where we don't need this? What if we have
5557 // arithMode() == Arith::Unchecked?
5558 // https://bugs.webkit.org/show_bug.cgi?id=126444
5559 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchMul32(JITCompiler::Overflow, quotientThenRemainderGPR, divisorGPR, multiplyAnswerGPR));
5560#if HAVE(ARM_IDIV_INSTRUCTIONS)
5561 m_jit.assembler().sub(quotientThenRemainderGPR, dividendGPR, multiplyAnswerGPR);
5562#else
5563 m_jit.assembler().sub<32>(quotientThenRemainderGPR, dividendGPR, multiplyAnswerGPR);
5564#endif
5565
5566 // If the user cares about negative zero, then speculate that we're not about
5567 // to produce negative zero.
5568 if (shouldCheckNegativeZero(node->arithMode())) {
5569 // Check that we're not about to create negative zero.
5570 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, dividendGPR, TrustedImm32(0));
5571 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, quotientThenRemainderGPR));
5572 numeratorPositive.link(&m_jit);
5573 }
5574
5575 done.link(&m_jit);
5576
5577 int32Result(quotientThenRemainderGPR, node);
5578#else // not architecture that can do integer division
5579 RELEASE_ASSERT_NOT_REACHED();
5580#endif
5581 return;
5582 }
5583
5584 case DoubleRepUse: {
5585 SpeculateDoubleOperand op1(this, node->child1());
5586 SpeculateDoubleOperand op2(this, node->child2());
5587
5588 FPRReg op1FPR = op1.fpr();
5589 FPRReg op2FPR = op2.fpr();
5590
5591 flushRegisters();
5592
5593 FPRResult result(this);
5594
5595 using OperationType = D_JITOperation_DD;
5596 callOperation<OperationType>(jsMod, result.fpr(), op1FPR, op2FPR);
5597
5598 doubleResult(result.fpr(), node);
5599 return;
5600 }
5601
5602 default:
5603 RELEASE_ASSERT_NOT_REACHED();
5604 return;
5605 }
5606}
5607
5608void SpeculativeJIT::compileArithRounding(Node* node)
5609{
5610 if (node->child1().useKind() == DoubleRepUse) {
5611 SpeculateDoubleOperand value(this, node->child1());
5612 FPRReg valueFPR = value.fpr();
5613
5614 auto setResult = [&] (FPRReg resultFPR) {
5615 if (producesInteger(node->arithRoundingMode())) {
5616 GPRTemporary roundedResultAsInt32(this);
5617 FPRTemporary scratch(this);
5618 FPRReg scratchFPR = scratch.fpr();
5619 GPRReg resultGPR = roundedResultAsInt32.gpr();
5620 JITCompiler::JumpList failureCases;
5621 m_jit.branchConvertDoubleToInt32(resultFPR, resultGPR, failureCases, scratchFPR, shouldCheckNegativeZero(node->arithRoundingMode()));
5622 speculationCheck(Overflow, JSValueRegs(), node, failureCases);
5623
5624 int32Result(resultGPR, node);
5625 } else
5626 doubleResult(resultFPR, node);
5627 };
5628
5629 if (m_jit.supportsFloatingPointRounding()) {
5630 switch (node->op()) {
5631 case ArithRound: {
5632 FPRTemporary result(this);
5633 FPRReg resultFPR = result.fpr();
5634 if (producesInteger(node->arithRoundingMode()) && !shouldCheckNegativeZero(node->arithRoundingMode())) {
5635 static constexpr double halfConstant = 0.5;
5636 m_jit.loadDouble(TrustedImmPtr(&halfConstant), resultFPR);
5637 m_jit.addDouble(valueFPR, resultFPR);
5638 m_jit.floorDouble(resultFPR, resultFPR);
5639 } else {
5640 m_jit.ceilDouble(valueFPR, resultFPR);
5641
5642 FPRTemporary scratch(this);
5643 FPRReg scratchFPR = scratch.fpr();
5644 static constexpr double halfConstant = -0.5;
5645 m_jit.loadDouble(TrustedImmPtr(&halfConstant), scratchFPR);
5646 m_jit.addDouble(resultFPR, scratchFPR);
5647
5648 JITCompiler::Jump shouldUseCeiled = m_jit.branchDouble(JITCompiler::DoubleLessThanOrEqual, scratchFPR, valueFPR);
5649 static constexpr double oneConstant = -1.0;
5650 m_jit.loadDouble(TrustedImmPtr(&oneConstant), scratchFPR);
5651 m_jit.addDouble(scratchFPR, resultFPR);
5652 shouldUseCeiled.link(&m_jit);
5653 }
5654 setResult(resultFPR);
5655 return;
5656 }
5657
5658 case ArithFloor: {
5659 FPRTemporary rounded(this);
5660 FPRReg resultFPR = rounded.fpr();
5661 m_jit.floorDouble(valueFPR, resultFPR);
5662 setResult(resultFPR);
5663 return;
5664 }
5665
5666 case ArithCeil: {
5667 FPRTemporary rounded(this);
5668 FPRReg resultFPR = rounded.fpr();
5669 m_jit.ceilDouble(valueFPR, resultFPR);
5670 setResult(resultFPR);
5671 return;
5672 }
5673
5674 case ArithTrunc: {
5675 FPRTemporary rounded(this);
5676 FPRReg resultFPR = rounded.fpr();
5677 m_jit.roundTowardZeroDouble(valueFPR, resultFPR);
5678 setResult(resultFPR);
5679 return;
5680 }
5681
5682 default:
5683 RELEASE_ASSERT_NOT_REACHED();
5684 }
5685 } else {
5686 flushRegisters();
5687 FPRResult roundedResultAsDouble(this);
5688 FPRReg resultFPR = roundedResultAsDouble.fpr();
5689 using OperationType = D_JITOperation_D;
5690 if (node->op() == ArithRound)
5691 callOperation<OperationType>(jsRound, resultFPR, valueFPR);
5692 else if (node->op() == ArithFloor)
5693 callOperation<OperationType>(floor, resultFPR, valueFPR);
5694 else if (node->op() == ArithCeil)
5695 callOperation<OperationType>(ceil, resultFPR, valueFPR);
5696 else {
5697 ASSERT(node->op() == ArithTrunc);
5698 callOperation<OperationType>(trunc, resultFPR, valueFPR);
5699 }
5700 setResult(resultFPR);
5701 }
5702 return;
5703 }
5704
5705 DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse, node->child1().useKind());
5706
5707 JSValueOperand argument(this, node->child1());
5708 JSValueRegs argumentRegs = argument.jsValueRegs();
5709
5710 flushRegisters();
5711 JSValueRegsFlushedCallResult result(this);
5712 JSValueRegs resultRegs = result.regs();
5713 J_JITOperation_GJ operation = nullptr;
5714 if (node->op() == ArithRound)
5715 operation = operationArithRound;
5716 else if (node->op() == ArithFloor)
5717 operation = operationArithFloor;
5718 else if (node->op() == ArithCeil)
5719 operation = operationArithCeil;
5720 else {
5721 ASSERT(node->op() == ArithTrunc);
5722 operation = operationArithTrunc;
5723 }
5724 callOperation(operation, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), argumentRegs);
5725 m_jit.exceptionCheck();
5726 jsValueResult(resultRegs, node);
5727}
5728
5729void SpeculativeJIT::compileArithUnary(Node* node)
5730{
5731 compileArithDoubleUnaryOp(node, arithUnaryFunction(node->arithUnaryType()), arithUnaryOperation(node->arithUnaryType()));
5732}
5733
5734void SpeculativeJIT::compileArithSqrt(Node* node)
5735{
5736 if (node->child1().useKind() == DoubleRepUse) {
5737 SpeculateDoubleOperand op1(this, node->child1());
5738 FPRReg op1FPR = op1.fpr();
5739
5740 if (!MacroAssembler::supportsFloatingPointSqrt() || !Options::useArchitectureSpecificOptimizations()) {
5741 flushRegisters();
5742 FPRResult result(this);
5743 callOperation<D_JITOperation_D>(sqrt, result.fpr(), op1FPR);
5744 doubleResult(result.fpr(), node);
5745 } else {
5746 FPRTemporary result(this, op1);
5747 m_jit.sqrtDouble(op1.fpr(), result.fpr());
5748 doubleResult(result.fpr(), node);
5749 }
5750 return;
5751 }
5752
5753 JSValueOperand op1(this, node->child1());
5754 JSValueRegs op1Regs = op1.jsValueRegs();
5755 flushRegisters();
5756 FPRResult result(this);
5757 callOperation(operationArithSqrt, result.fpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs);
5758 m_jit.exceptionCheck();
5759 doubleResult(result.fpr(), node);
5760}
5761
5762void SpeculativeJIT::compileArithMinMax(Node* node)
5763{
5764 switch (node->binaryUseKind()) {
5765 case Int32Use: {
5766 SpeculateStrictInt32Operand op1(this, node->child1());
5767 SpeculateStrictInt32Operand op2(this, node->child2());
5768 GPRTemporary result(this, Reuse, op1);
5769
5770 GPRReg op1GPR = op1.gpr();
5771 GPRReg op2GPR = op2.gpr();
5772 GPRReg resultGPR = result.gpr();
5773
5774 MacroAssembler::Jump op1Less = m_jit.branch32(node->op() == ArithMin ? MacroAssembler::LessThan : MacroAssembler::GreaterThan, op1GPR, op2GPR);
5775 m_jit.move(op2GPR, resultGPR);
5776 if (op1GPR != resultGPR) {
5777 MacroAssembler::Jump done = m_jit.jump();
5778 op1Less.link(&m_jit);
5779 m_jit.move(op1GPR, resultGPR);
5780 done.link(&m_jit);
5781 } else
5782 op1Less.link(&m_jit);
5783
5784 int32Result(resultGPR, node);
5785 break;
5786 }
5787
5788 case DoubleRepUse: {
5789 SpeculateDoubleOperand op1(this, node->child1());
5790 SpeculateDoubleOperand op2(this, node->child2());
5791 FPRTemporary result(this, op1);
5792
5793 FPRReg op1FPR = op1.fpr();
5794 FPRReg op2FPR = op2.fpr();
5795 FPRReg resultFPR = result.fpr();
5796
5797 MacroAssembler::JumpList done;
5798
5799 MacroAssembler::Jump op1Less = m_jit.branchDouble(node->op() == ArithMin ? MacroAssembler::DoubleLessThan : MacroAssembler::DoubleGreaterThan, op1FPR, op2FPR);
5800
5801 // op2 is eather the lesser one or one of then is NaN
5802 MacroAssembler::Jump op2Less = m_jit.branchDouble(node->op() == ArithMin ? MacroAssembler::DoubleGreaterThanOrEqual : MacroAssembler::DoubleLessThanOrEqual, op1FPR, op2FPR);
5803
5804 // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding
5805 // op1 + op2 and putting it into result.
5806 m_jit.addDouble(op1FPR, op2FPR, resultFPR);
5807 done.append(m_jit.jump());
5808
5809 op2Less.link(&m_jit);
5810 m_jit.moveDouble(op2FPR, resultFPR);
5811
5812 if (op1FPR != resultFPR) {
5813 done.append(m_jit.jump());
5814
5815 op1Less.link(&m_jit);
5816 m_jit.moveDouble(op1FPR, resultFPR);
5817 } else
5818 op1Less.link(&m_jit);
5819
5820 done.link(&m_jit);
5821
5822 doubleResult(resultFPR, node);
5823 break;
5824 }
5825
5826 default:
5827 DFG_CRASH(m_jit.graph(), node, "Bad use kind");
5828 break;
5829 }
5830}
5831
5832// For small positive integers , it is worth doing a tiny inline loop to exponentiate the base.
5833// Every register is clobbered by this helper.
5834static MacroAssembler::Jump compileArithPowIntegerFastPath(JITCompiler& assembler, FPRReg xOperand, GPRReg yOperand, FPRReg result)
5835{
5836 MacroAssembler::JumpList skipFastPath;
5837 skipFastPath.append(assembler.branch32(MacroAssembler::Above, yOperand, MacroAssembler::TrustedImm32(maxExponentForIntegerMathPow)));
5838
5839 static constexpr double oneConstant = 1.0;
5840 assembler.loadDouble(MacroAssembler::TrustedImmPtr(&oneConstant), result);
5841
5842 MacroAssembler::Label startLoop(assembler.label());
5843 MacroAssembler::Jump exponentIsEven = assembler.branchTest32(MacroAssembler::Zero, yOperand, MacroAssembler::TrustedImm32(1));
5844 assembler.mulDouble(xOperand, result);
5845 exponentIsEven.link(&assembler);
5846 assembler.mulDouble(xOperand, xOperand);
5847 assembler.rshift32(MacroAssembler::TrustedImm32(1), yOperand);
5848 assembler.branchTest32(MacroAssembler::NonZero, yOperand).linkTo(startLoop, &assembler);
5849
5850 MacroAssembler::Jump skipSlowPath = assembler.jump();
5851 skipFastPath.link(&assembler);
5852
5853 return skipSlowPath;
5854}
5855
5856void SpeculativeJIT::compileValuePow(Node* node)
5857{
5858 Edge& leftChild = node->child1();
5859 Edge& rightChild = node->child2();
5860
5861 if (node->binaryUseKind() == BigIntUse) {
5862 SpeculateCellOperand left(this, leftChild);
5863 SpeculateCellOperand right(this, rightChild);
5864 GPRReg leftGPR = left.gpr();
5865 GPRReg rightGPR = right.gpr();
5866
5867 speculateBigInt(leftChild, leftGPR);
5868 speculateBigInt(rightChild, rightGPR);
5869
5870 flushRegisters();
5871 GPRFlushedCallResult result(this);
5872 GPRReg resultGPR = result.gpr();
5873
5874 callOperation(operationPowBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
5875
5876 m_jit.exceptionCheck();
5877 cellResult(resultGPR, node);
5878 return;
5879 }
5880
5881 DFG_ASSERT(m_jit.graph(), node, node->binaryUseKind() == UntypedUse, node->binaryUseKind());
5882
5883 JSValueOperand left(this, leftChild);
5884 JSValueOperand right(this, rightChild);
5885 JSValueRegs leftRegs = left.jsValueRegs();
5886 JSValueRegs rightRegs = right.jsValueRegs();
5887
5888 flushRegisters();
5889 JSValueRegsFlushedCallResult result(this);
5890 JSValueRegs resultRegs = result.regs();
5891 callOperation(operationValuePow, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftRegs, rightRegs);
5892 m_jit.exceptionCheck();
5893
5894 jsValueResult(resultRegs, node);
5895}
5896
5897void SpeculativeJIT::compileArithPow(Node* node)
5898{
5899 if (node->child2().useKind() == Int32Use) {
5900 SpeculateDoubleOperand xOperand(this, node->child1());
5901 SpeculateInt32Operand yOperand(this, node->child2());
5902 FPRReg xOperandfpr = xOperand.fpr();
5903 GPRReg yOperandGpr = yOperand.gpr();
5904 FPRTemporary yOperandfpr(this);
5905
5906 flushRegisters();
5907
5908 FPRResult result(this);
5909 FPRReg resultFpr = result.fpr();
5910
5911 FPRTemporary xOperandCopy(this);
5912 FPRReg xOperandCopyFpr = xOperandCopy.fpr();
5913 m_jit.moveDouble(xOperandfpr, xOperandCopyFpr);
5914
5915 GPRTemporary counter(this);
5916 GPRReg counterGpr = counter.gpr();
5917 m_jit.move(yOperandGpr, counterGpr);
5918
5919 MacroAssembler::Jump skipFallback = compileArithPowIntegerFastPath(m_jit, xOperandCopyFpr, counterGpr, resultFpr);
5920 m_jit.convertInt32ToDouble(yOperandGpr, yOperandfpr.fpr());
5921 callOperation(operationMathPow, resultFpr, xOperandfpr, yOperandfpr.fpr());
5922
5923 skipFallback.link(&m_jit);
5924 doubleResult(resultFpr, node);
5925 return;
5926 }
5927
5928 if (node->child2()->isDoubleConstant()) {
5929 double exponent = node->child2()->asNumber();
5930 static constexpr double infinityConstant = std::numeric_limits<double>::infinity();
5931 static constexpr double minusInfinityConstant = -std::numeric_limits<double>::infinity();
5932 if (exponent == 0.5) {
5933 SpeculateDoubleOperand xOperand(this, node->child1());
5934 FPRTemporary result(this);
5935 FPRReg xOperandFpr = xOperand.fpr();
5936 FPRReg resultFpr = result.fpr();
5937
5938 m_jit.moveZeroToDouble(resultFpr);
5939 MacroAssembler::Jump xIsZeroOrNegativeZero = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr);
5940
5941 m_jit.loadDouble(TrustedImmPtr(&minusInfinityConstant), resultFpr);
5942 MacroAssembler::Jump xIsMinusInfinity = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr);
5943 m_jit.sqrtDouble(xOperandFpr, resultFpr);
5944 MacroAssembler::Jump doneWithSqrt = m_jit.jump();
5945
5946 xIsMinusInfinity.link(&m_jit);
5947 if (isX86())
5948 m_jit.loadDouble(TrustedImmPtr(&infinityConstant), resultFpr);
5949 else
5950 m_jit.absDouble(resultFpr, resultFpr);
5951
5952 xIsZeroOrNegativeZero.link(&m_jit);
5953 doneWithSqrt.link(&m_jit);
5954 doubleResult(resultFpr, node);
5955 return;
5956 }
5957 if (exponent == -0.5) {
5958 SpeculateDoubleOperand xOperand(this, node->child1());
5959 FPRTemporary scratch(this);
5960 FPRTemporary result(this);
5961 FPRReg xOperandFpr = xOperand.fpr();
5962 FPRReg scratchFPR = scratch.fpr();
5963 FPRReg resultFpr = result.fpr();
5964
5965 m_jit.moveZeroToDouble(resultFpr);
5966 MacroAssembler::Jump xIsZeroOrNegativeZero = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr);
5967
5968 m_jit.loadDouble(TrustedImmPtr(&minusInfinityConstant), resultFpr);
5969 MacroAssembler::Jump xIsMinusInfinity = m_jit.branchDouble(MacroAssembler::DoubleEqual, xOperandFpr, resultFpr);
5970
5971 static constexpr double oneConstant = 1.;
5972 m_jit.loadDouble(TrustedImmPtr(&oneConstant), resultFpr);
5973 m_jit.sqrtDouble(xOperandFpr, scratchFPR);
5974 m_jit.divDouble(resultFpr, scratchFPR, resultFpr);
5975 MacroAssembler::Jump doneWithSqrt = m_jit.jump();
5976
5977 xIsZeroOrNegativeZero.link(&m_jit);
5978 m_jit.loadDouble(TrustedImmPtr(&infinityConstant), resultFpr);
5979 MacroAssembler::Jump doneWithBaseZero = m_jit.jump();
5980
5981 xIsMinusInfinity.link(&m_jit);
5982 m_jit.moveZeroToDouble(resultFpr);
5983
5984 doneWithBaseZero.link(&m_jit);
5985 doneWithSqrt.link(&m_jit);
5986 doubleResult(resultFpr, node);
5987 return;
5988 }
5989 }
5990
5991 SpeculateDoubleOperand xOperand(this, node->child1());
5992 SpeculateDoubleOperand yOperand(this, node->child2());
5993 FPRReg xOperandfpr = xOperand.fpr();
5994 FPRReg yOperandfpr = yOperand.fpr();
5995
5996 flushRegisters();
5997
5998 FPRResult result(this);
5999 FPRReg resultFpr = result.fpr();
6000
6001 FPRTemporary xOperandCopy(this);
6002 FPRReg xOperandCopyFpr = xOperandCopy.fpr();
6003
6004 FPRTemporary scratch(this);
6005 FPRReg scratchFpr = scratch.fpr();
6006
6007 GPRTemporary yOperandInteger(this);
6008 GPRReg yOperandIntegerGpr = yOperandInteger.gpr();
6009 MacroAssembler::JumpList failedExponentConversionToInteger;
6010 m_jit.branchConvertDoubleToInt32(yOperandfpr, yOperandIntegerGpr, failedExponentConversionToInteger, scratchFpr, false);
6011
6012 m_jit.moveDouble(xOperandfpr, xOperandCopyFpr);
6013 MacroAssembler::Jump skipFallback = compileArithPowIntegerFastPath(m_jit, xOperandCopyFpr, yOperandInteger.gpr(), resultFpr);
6014 failedExponentConversionToInteger.link(&m_jit);
6015
6016 callOperation(operationMathPow, resultFpr, xOperandfpr, yOperandfpr);
6017 skipFallback.link(&m_jit);
6018 doubleResult(resultFpr, node);
6019}
6020
6021// Returns true if the compare is fused with a subsequent branch.
6022bool SpeculativeJIT::compare(Node* node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_JITOperation_GJJ operation)
6023{
6024 if (compilePeepHoleBranch(node, condition, doubleCondition, operation))
6025 return true;
6026
6027 if (node->isBinaryUseKind(Int32Use)) {
6028 compileInt32Compare(node, condition);
6029 return false;
6030 }
6031
6032#if USE(JSVALUE64)
6033 if (node->isBinaryUseKind(Int52RepUse)) {
6034 compileInt52Compare(node, condition);
6035 return false;
6036 }
6037#endif // USE(JSVALUE64)
6038
6039 if (node->isBinaryUseKind(DoubleRepUse)) {
6040 compileDoubleCompare(node, doubleCondition);
6041 return false;
6042 }
6043
6044 if (node->isBinaryUseKind(StringUse)) {
6045 if (node->op() == CompareEq)
6046 compileStringEquality(node);
6047 else
6048 compileStringCompare(node, condition);
6049 return false;
6050 }
6051
6052 if (node->isBinaryUseKind(StringIdentUse)) {
6053 if (node->op() == CompareEq)
6054 compileStringIdentEquality(node);
6055 else
6056 compileStringIdentCompare(node, condition);
6057 return false;
6058 }
6059
6060 if (node->op() == CompareEq) {
6061 if (node->isBinaryUseKind(BooleanUse)) {
6062 compileBooleanCompare(node, condition);
6063 return false;
6064 }
6065
6066 if (node->isBinaryUseKind(SymbolUse)) {
6067 compileSymbolEquality(node);
6068 return false;
6069 }
6070
6071 if (node->isBinaryUseKind(ObjectUse)) {
6072 compileObjectEquality(node);
6073 return false;
6074 }
6075
6076 if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse)) {
6077 compileObjectToObjectOrOtherEquality(node->child1(), node->child2());
6078 return false;
6079 }
6080
6081 if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) {
6082 compileObjectToObjectOrOtherEquality(node->child2(), node->child1());
6083 return false;
6084 }
6085
6086 if (!needsTypeCheck(node->child1(), SpecOther)) {
6087 nonSpeculativeNonPeepholeCompareNullOrUndefined(node->child2());
6088 return false;
6089 }
6090
6091 if (!needsTypeCheck(node->child2(), SpecOther)) {
6092 nonSpeculativeNonPeepholeCompareNullOrUndefined(node->child1());
6093 return false;
6094 }
6095 }
6096
6097 nonSpeculativeNonPeepholeCompare(node, condition, operation);
6098 return false;
6099}
6100
6101void SpeculativeJIT::compileCompareUnsigned(Node* node, MacroAssembler::RelationalCondition condition)
6102{
6103 compileInt32Compare(node, condition);
6104}
6105
6106bool SpeculativeJIT::compileStrictEq(Node* node)
6107{
6108 if (node->isBinaryUseKind(BooleanUse)) {
6109 unsigned branchIndexInBlock = detectPeepHoleBranch();
6110 if (branchIndexInBlock != UINT_MAX) {
6111 Node* branchNode = m_block->at(branchIndexInBlock);
6112 compilePeepHoleBooleanBranch(node, branchNode, MacroAssembler::Equal);
6113 use(node->child1());
6114 use(node->child2());
6115 m_indexInBlock = branchIndexInBlock;
6116 m_currentNode = branchNode;
6117 return true;
6118 }
6119 compileBooleanCompare(node, MacroAssembler::Equal);
6120 return false;
6121 }
6122
6123 if (node->isBinaryUseKind(Int32Use)) {
6124 unsigned branchIndexInBlock = detectPeepHoleBranch();
6125 if (branchIndexInBlock != UINT_MAX) {
6126 Node* branchNode = m_block->at(branchIndexInBlock);
6127 compilePeepHoleInt32Branch(node, branchNode, MacroAssembler::Equal);
6128 use(node->child1());
6129 use(node->child2());
6130 m_indexInBlock = branchIndexInBlock;
6131 m_currentNode = branchNode;
6132 return true;
6133 }
6134 compileInt32Compare(node, MacroAssembler::Equal);
6135 return false;
6136 }
6137
6138#if USE(JSVALUE64)
6139 if (node->isBinaryUseKind(Int52RepUse)) {
6140 unsigned branchIndexInBlock = detectPeepHoleBranch();
6141 if (branchIndexInBlock != UINT_MAX) {
6142 Node* branchNode = m_block->at(branchIndexInBlock);
6143 compilePeepHoleInt52Branch(node, branchNode, MacroAssembler::Equal);
6144 use(node->child1());
6145 use(node->child2());
6146 m_indexInBlock = branchIndexInBlock;
6147 m_currentNode = branchNode;
6148 return true;
6149 }
6150 compileInt52Compare(node, MacroAssembler::Equal);
6151 return false;
6152 }
6153#endif // USE(JSVALUE64)
6154
6155 if (node->isBinaryUseKind(DoubleRepUse)) {
6156 unsigned branchIndexInBlock = detectPeepHoleBranch();
6157 if (branchIndexInBlock != UINT_MAX) {
6158 Node* branchNode = m_block->at(branchIndexInBlock);
6159 compilePeepHoleDoubleBranch(node, branchNode, MacroAssembler::DoubleEqual);
6160 use(node->child1());
6161 use(node->child2());
6162 m_indexInBlock = branchIndexInBlock;
6163 m_currentNode = branchNode;
6164 return true;
6165 }
6166 compileDoubleCompare(node, MacroAssembler::DoubleEqual);
6167 return false;
6168 }
6169
6170 if (node->isBinaryUseKind(SymbolUse)) {
6171 unsigned branchIndexInBlock = detectPeepHoleBranch();
6172 if (branchIndexInBlock != UINT_MAX) {
6173 Node* branchNode = m_block->at(branchIndexInBlock);
6174 compilePeepHoleSymbolEquality(node, branchNode);
6175 use(node->child1());
6176 use(node->child2());
6177 m_indexInBlock = branchIndexInBlock;
6178 m_currentNode = branchNode;
6179 return true;
6180 }
6181 compileSymbolEquality(node);
6182 return false;
6183 }
6184
6185 if (node->isBinaryUseKind(BigIntUse)) {
6186 compileBigIntEquality(node);
6187 return false;
6188 }
6189
6190 if (node->isBinaryUseKind(SymbolUse, UntypedUse)) {
6191 compileSymbolUntypedEquality(node, node->child1(), node->child2());
6192 return false;
6193 }
6194
6195 if (node->isBinaryUseKind(UntypedUse, SymbolUse)) {
6196 compileSymbolUntypedEquality(node, node->child2(), node->child1());
6197 return false;
6198 }
6199
6200 if (node->isBinaryUseKind(StringUse)) {
6201 compileStringEquality(node);
6202 return false;
6203 }
6204
6205 if (node->isBinaryUseKind(StringIdentUse)) {
6206 compileStringIdentEquality(node);
6207 return false;
6208 }
6209
6210 if (node->isBinaryUseKind(ObjectUse, UntypedUse)) {
6211 unsigned branchIndexInBlock = detectPeepHoleBranch();
6212 if (branchIndexInBlock != UINT_MAX) {
6213 Node* branchNode = m_block->at(branchIndexInBlock);
6214 compilePeepHoleObjectStrictEquality(node->child1(), node->child2(), branchNode);
6215 use(node->child1());
6216 use(node->child2());
6217 m_indexInBlock = branchIndexInBlock;
6218 m_currentNode = branchNode;
6219 return true;
6220 }
6221 compileObjectStrictEquality(node->child1(), node->child2());
6222 return false;
6223 }
6224
6225 if (node->isBinaryUseKind(UntypedUse, ObjectUse)) {
6226 unsigned branchIndexInBlock = detectPeepHoleBranch();
6227 if (branchIndexInBlock != UINT_MAX) {
6228 Node* branchNode = m_block->at(branchIndexInBlock);
6229 compilePeepHoleObjectStrictEquality(node->child2(), node->child1(), branchNode);
6230 use(node->child1());
6231 use(node->child2());
6232 m_indexInBlock = branchIndexInBlock;
6233 m_currentNode = branchNode;
6234 return true;
6235 }
6236 compileObjectStrictEquality(node->child2(), node->child1());
6237 return false;
6238 }
6239
6240 if (node->isBinaryUseKind(ObjectUse)) {
6241 unsigned branchIndexInBlock = detectPeepHoleBranch();
6242 if (branchIndexInBlock != UINT_MAX) {
6243 Node* branchNode = m_block->at(branchIndexInBlock);
6244 compilePeepHoleObjectEquality(node, branchNode);
6245 use(node->child1());
6246 use(node->child2());
6247 m_indexInBlock = branchIndexInBlock;
6248 m_currentNode = branchNode;
6249 return true;
6250 }
6251 compileObjectEquality(node);
6252 return false;
6253 }
6254
6255 if (node->isBinaryUseKind(MiscUse, UntypedUse)
6256 || node->isBinaryUseKind(UntypedUse, MiscUse)) {
6257 compileMiscStrictEq(node);
6258 return false;
6259 }
6260
6261 if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse)) {
6262 compileStringIdentToNotStringVarEquality(node, node->child1(), node->child2());
6263 return false;
6264 }
6265
6266 if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse)) {
6267 compileStringIdentToNotStringVarEquality(node, node->child2(), node->child1());
6268 return false;
6269 }
6270
6271 if (node->isBinaryUseKind(StringUse, UntypedUse)) {
6272 compileStringToUntypedEquality(node, node->child1(), node->child2());
6273 return false;
6274 }
6275
6276 if (node->isBinaryUseKind(UntypedUse, StringUse)) {
6277 compileStringToUntypedEquality(node, node->child2(), node->child1());
6278 return false;
6279 }
6280
6281 RELEASE_ASSERT(node->isBinaryUseKind(UntypedUse));
6282 return nonSpeculativeStrictEq(node);
6283}
6284
6285void SpeculativeJIT::compileBooleanCompare(Node* node, MacroAssembler::RelationalCondition condition)
6286{
6287 SpeculateBooleanOperand op1(this, node->child1());
6288 SpeculateBooleanOperand op2(this, node->child2());
6289 GPRTemporary result(this);
6290
6291 m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());
6292
6293 unblessedBooleanResult(result.gpr(), node);
6294}
6295
6296void SpeculativeJIT::compileInt32Compare(Node* node, MacroAssembler::RelationalCondition condition)
6297{
6298 if (node->child1()->isInt32Constant()) {
6299 SpeculateInt32Operand op2(this, node->child2());
6300 GPRTemporary result(this, Reuse, op2);
6301 int32_t imm = node->child1()->asInt32();
6302 m_jit.compare32(condition, JITCompiler::Imm32(imm), op2.gpr(), result.gpr());
6303
6304 unblessedBooleanResult(result.gpr(), node);
6305 } else if (node->child2()->isInt32Constant()) {
6306 SpeculateInt32Operand op1(this, node->child1());
6307 GPRTemporary result(this, Reuse, op1);
6308 int32_t imm = node->child2()->asInt32();
6309 m_jit.compare32(condition, op1.gpr(), JITCompiler::Imm32(imm), result.gpr());
6310
6311 unblessedBooleanResult(result.gpr(), node);
6312 } else {
6313 SpeculateInt32Operand op1(this, node->child1());
6314 SpeculateInt32Operand op2(this, node->child2());
6315 GPRTemporary result(this, Reuse, op1, op2);
6316 m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());
6317
6318 unblessedBooleanResult(result.gpr(), node);
6319 }
6320}
6321
6322void SpeculativeJIT::compileDoubleCompare(Node* node, MacroAssembler::DoubleCondition condition)
6323{
6324 SpeculateDoubleOperand op1(this, node->child1());
6325 SpeculateDoubleOperand op2(this, node->child2());
6326 GPRTemporary result(this);
6327
6328 FPRReg op1FPR = op1.fpr();
6329 FPRReg op2FPR = op2.fpr();
6330 GPRReg resultGPR = result.gpr();
6331
6332 m_jit.compareDouble(condition, op1FPR, op2FPR, resultGPR);
6333
6334 unblessedBooleanResult(resultGPR, node);
6335}
6336
6337void SpeculativeJIT::compileObjectEquality(Node* node)
6338{
6339 SpeculateCellOperand op1(this, node->child1());
6340 SpeculateCellOperand op2(this, node->child2());
6341 GPRTemporary result(this, Reuse, op1);
6342
6343 GPRReg op1GPR = op1.gpr();
6344 GPRReg op2GPR = op2.gpr();
6345 GPRReg resultGPR = result.gpr();
6346
6347 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
6348 DFG_TYPE_CHECK(
6349 JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchIfNotObject(op1GPR));
6350 DFG_TYPE_CHECK(
6351 JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchIfNotObject(op2GPR));
6352 } else {
6353 DFG_TYPE_CHECK(
6354 JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchIfNotObject(op1GPR));
6355 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
6356 m_jit.branchTest8(
6357 MacroAssembler::NonZero,
6358 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()),
6359 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
6360
6361 DFG_TYPE_CHECK(
6362 JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchIfNotObject(op2GPR));
6363 speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
6364 m_jit.branchTest8(
6365 MacroAssembler::NonZero,
6366 MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()),
6367 MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
6368 }
6369
6370 m_jit.comparePtr(MacroAssembler::Equal, op1GPR, op2GPR, resultGPR);
6371 unblessedBooleanResult(resultGPR, node);
6372}
6373
6374void SpeculativeJIT::compileSymbolEquality(Node* node)
6375{
6376 SpeculateCellOperand left(this, node->child1());
6377 SpeculateCellOperand right(this, node->child2());
6378 GPRTemporary result(this, Reuse, left, right);
6379
6380 GPRReg leftGPR = left.gpr();
6381 GPRReg rightGPR = right.gpr();
6382 GPRReg resultGPR = result.gpr();
6383
6384 speculateSymbol(node->child1(), leftGPR);
6385 speculateSymbol(node->child2(), rightGPR);
6386
6387 m_jit.comparePtr(JITCompiler::Equal, leftGPR, rightGPR, resultGPR);
6388 unblessedBooleanResult(resultGPR, node);
6389}
6390
6391void SpeculativeJIT::compilePeepHoleSymbolEquality(Node* node, Node* branchNode)
6392{
6393 SpeculateCellOperand left(this, node->child1());
6394 SpeculateCellOperand right(this, node->child2());
6395
6396 GPRReg leftGPR = left.gpr();
6397 GPRReg rightGPR = right.gpr();
6398
6399 speculateSymbol(node->child1(), leftGPR);
6400 speculateSymbol(node->child2(), rightGPR);
6401
6402 BasicBlock* taken = branchNode->branchData()->taken.block;
6403 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
6404
6405 if (taken == nextBlock()) {
6406 branchPtr(JITCompiler::NotEqual, leftGPR, rightGPR, notTaken);
6407 jump(taken);
6408 } else {
6409 branchPtr(JITCompiler::Equal, leftGPR, rightGPR, taken);
6410 jump(notTaken);
6411 }
6412}
6413
6414void SpeculativeJIT::compileStringEquality(
6415 Node* node, GPRReg leftGPR, GPRReg rightGPR, GPRReg lengthGPR, GPRReg leftTempGPR,
6416 GPRReg rightTempGPR, GPRReg leftTemp2GPR, GPRReg rightTemp2GPR,
6417 const JITCompiler::JumpList& fastTrue, const JITCompiler::JumpList& fastFalse)
6418{
6419 JITCompiler::JumpList trueCase;
6420 JITCompiler::JumpList falseCase;
6421 JITCompiler::JumpList slowCase;
6422
6423 trueCase.append(fastTrue);
6424 falseCase.append(fastFalse);
6425
6426 m_jit.loadPtr(MacroAssembler::Address(leftGPR, JSString::offsetOfValue()), leftTempGPR);
6427 m_jit.loadPtr(MacroAssembler::Address(rightGPR, JSString::offsetOfValue()), rightTempGPR);
6428
6429 slowCase.append(m_jit.branchIfRopeStringImpl(leftTempGPR));
6430 slowCase.append(m_jit.branchIfRopeStringImpl(rightTempGPR));
6431
6432 m_jit.load32(MacroAssembler::Address(leftTempGPR, StringImpl::lengthMemoryOffset()), lengthGPR);
6433
6434 falseCase.append(m_jit.branch32(
6435 MacroAssembler::NotEqual,
6436 MacroAssembler::Address(rightTempGPR, StringImpl::lengthMemoryOffset()),
6437 lengthGPR));
6438
6439 trueCase.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR));
6440
6441 slowCase.append(m_jit.branchTest32(
6442 MacroAssembler::Zero,
6443 MacroAssembler::Address(leftTempGPR, StringImpl::flagsOffset()),
6444 TrustedImm32(StringImpl::flagIs8Bit())));
6445 slowCase.append(m_jit.branchTest32(
6446 MacroAssembler::Zero,
6447 MacroAssembler::Address(rightTempGPR, StringImpl::flagsOffset()),
6448 TrustedImm32(StringImpl::flagIs8Bit())));
6449
6450 m_jit.loadPtr(MacroAssembler::Address(leftTempGPR, StringImpl::dataOffset()), leftTempGPR);
6451 m_jit.loadPtr(MacroAssembler::Address(rightTempGPR, StringImpl::dataOffset()), rightTempGPR);
6452
6453 MacroAssembler::Label loop = m_jit.label();
6454
6455 m_jit.sub32(TrustedImm32(1), lengthGPR);
6456
6457 // This isn't going to generate the best code on x86. But that's OK, it's still better
6458 // than not inlining.
6459 m_jit.load8(MacroAssembler::BaseIndex(leftTempGPR, lengthGPR, MacroAssembler::TimesOne), leftTemp2GPR);
6460 m_jit.load8(MacroAssembler::BaseIndex(rightTempGPR, lengthGPR, MacroAssembler::TimesOne), rightTemp2GPR);
6461 falseCase.append(m_jit.branch32(MacroAssembler::NotEqual, leftTemp2GPR, rightTemp2GPR));
6462
6463 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loop, &m_jit);
6464
6465 trueCase.link(&m_jit);
6466 moveTrueTo(leftTempGPR);
6467
6468 JITCompiler::Jump done = m_jit.jump();
6469
6470 falseCase.link(&m_jit);
6471 moveFalseTo(leftTempGPR);
6472
6473 done.link(&m_jit);
6474 addSlowPathGenerator(
6475 slowPathCall(
6476 slowCase, this, operationCompareStringEq, leftTempGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR));
6477
6478 blessedBooleanResult(leftTempGPR, node);
6479}
6480
6481void SpeculativeJIT::compileStringEquality(Node* node)
6482{
6483 SpeculateCellOperand left(this, node->child1());
6484 SpeculateCellOperand right(this, node->child2());
6485 GPRTemporary length(this);
6486 GPRTemporary leftTemp(this);
6487 GPRTemporary rightTemp(this);
6488 GPRTemporary leftTemp2(this, Reuse, left);
6489 GPRTemporary rightTemp2(this, Reuse, right);
6490
6491 GPRReg leftGPR = left.gpr();
6492 GPRReg rightGPR = right.gpr();
6493 GPRReg lengthGPR = length.gpr();
6494 GPRReg leftTempGPR = leftTemp.gpr();
6495 GPRReg rightTempGPR = rightTemp.gpr();
6496 GPRReg leftTemp2GPR = leftTemp2.gpr();
6497 GPRReg rightTemp2GPR = rightTemp2.gpr();
6498
6499 speculateString(node->child1(), leftGPR);
6500
6501 // It's safe to branch around the type check below, since proving that the values are
6502 // equal does indeed prove that the right value is a string.
6503 JITCompiler::Jump fastTrue = m_jit.branchPtr(MacroAssembler::Equal, leftGPR, rightGPR);
6504
6505 speculateString(node->child2(), rightGPR);
6506
6507 compileStringEquality(
6508 node, leftGPR, rightGPR, lengthGPR, leftTempGPR, rightTempGPR, leftTemp2GPR,
6509 rightTemp2GPR, fastTrue, JITCompiler::Jump());
6510}
6511
6512void SpeculativeJIT::compileStringToUntypedEquality(Node* node, Edge stringEdge, Edge untypedEdge)
6513{
6514 SpeculateCellOperand left(this, stringEdge);
6515 JSValueOperand right(this, untypedEdge, ManualOperandSpeculation);
6516 GPRTemporary length(this);
6517 GPRTemporary leftTemp(this);
6518 GPRTemporary rightTemp(this);
6519 GPRTemporary leftTemp2(this, Reuse, left);
6520 GPRTemporary rightTemp2(this);
6521
6522 GPRReg leftGPR = left.gpr();
6523 JSValueRegs rightRegs = right.jsValueRegs();
6524 GPRReg lengthGPR = length.gpr();
6525 GPRReg leftTempGPR = leftTemp.gpr();
6526 GPRReg rightTempGPR = rightTemp.gpr();
6527 GPRReg leftTemp2GPR = leftTemp2.gpr();
6528 GPRReg rightTemp2GPR = rightTemp2.gpr();
6529
6530 speculateString(stringEdge, leftGPR);
6531
6532 JITCompiler::JumpList fastTrue;
6533 JITCompiler::JumpList fastFalse;
6534
6535 fastFalse.append(m_jit.branchIfNotCell(rightRegs));
6536
6537 // It's safe to branch around the type check below, since proving that the values are
6538 // equal does indeed prove that the right value is a string.
6539 fastTrue.append(m_jit.branchPtr(
6540 MacroAssembler::Equal, leftGPR, rightRegs.payloadGPR()));
6541
6542 fastFalse.append(m_jit.branchIfNotString(rightRegs.payloadGPR()));
6543
6544 compileStringEquality(
6545 node, leftGPR, rightRegs.payloadGPR(), lengthGPR, leftTempGPR, rightTempGPR, leftTemp2GPR,
6546 rightTemp2GPR, fastTrue, fastFalse);
6547}
6548
6549void SpeculativeJIT::compileStringIdentEquality(Node* node)
6550{
6551 SpeculateCellOperand left(this, node->child1());
6552 SpeculateCellOperand right(this, node->child2());
6553 GPRTemporary leftTemp(this);
6554 GPRTemporary rightTemp(this);
6555
6556 GPRReg leftGPR = left.gpr();
6557 GPRReg rightGPR = right.gpr();
6558 GPRReg leftTempGPR = leftTemp.gpr();
6559 GPRReg rightTempGPR = rightTemp.gpr();
6560
6561 speculateString(node->child1(), leftGPR);
6562 speculateString(node->child2(), rightGPR);
6563
6564 speculateStringIdentAndLoadStorage(node->child1(), leftGPR, leftTempGPR);
6565 speculateStringIdentAndLoadStorage(node->child2(), rightGPR, rightTempGPR);
6566
6567 m_jit.comparePtr(MacroAssembler::Equal, leftTempGPR, rightTempGPR, leftTempGPR);
6568
6569 unblessedBooleanResult(leftTempGPR, node);
6570}
6571
6572void SpeculativeJIT::compileStringIdentToNotStringVarEquality(
6573 Node* node, Edge stringEdge, Edge notStringVarEdge)
6574{
6575 SpeculateCellOperand left(this, stringEdge);
6576 JSValueOperand right(this, notStringVarEdge, ManualOperandSpeculation);
6577 GPRTemporary leftTemp(this);
6578 GPRTemporary rightTemp(this);
6579 GPRReg leftTempGPR = leftTemp.gpr();
6580 GPRReg rightTempGPR = rightTemp.gpr();
6581 GPRReg leftGPR = left.gpr();
6582 JSValueRegs rightRegs = right.jsValueRegs();
6583
6584 speculateString(stringEdge, leftGPR);
6585 speculateStringIdentAndLoadStorage(stringEdge, leftGPR, leftTempGPR);
6586
6587 moveFalseTo(rightTempGPR);
6588 JITCompiler::JumpList notString;
6589 notString.append(m_jit.branchIfNotCell(rightRegs));
6590 notString.append(m_jit.branchIfNotString(rightRegs.payloadGPR()));
6591
6592 speculateStringIdentAndLoadStorage(notStringVarEdge, rightRegs.payloadGPR(), rightTempGPR);
6593
6594 m_jit.comparePtr(MacroAssembler::Equal, leftTempGPR, rightTempGPR, rightTempGPR);
6595 notString.link(&m_jit);
6596
6597 unblessedBooleanResult(rightTempGPR, node);
6598}
6599
6600void SpeculativeJIT::compileStringCompare(Node* node, MacroAssembler::RelationalCondition condition)
6601{
6602 SpeculateCellOperand left(this, node->child1());
6603 SpeculateCellOperand right(this, node->child2());
6604 GPRReg leftGPR = left.gpr();
6605 GPRReg rightGPR = right.gpr();
6606
6607 speculateString(node->child1(), leftGPR);
6608 speculateString(node->child2(), rightGPR);
6609
6610 C_JITOperation_B_GJssJss compareFunction = nullptr;
6611 if (condition == MacroAssembler::LessThan)
6612 compareFunction = operationCompareStringLess;
6613 else if (condition == MacroAssembler::LessThanOrEqual)
6614 compareFunction = operationCompareStringLessEq;
6615 else if (condition == MacroAssembler::GreaterThan)
6616 compareFunction = operationCompareStringGreater;
6617 else if (condition == MacroAssembler::GreaterThanOrEqual)
6618 compareFunction = operationCompareStringGreaterEq;
6619 else
6620 RELEASE_ASSERT_NOT_REACHED();
6621
6622 GPRFlushedCallResult result(this);
6623 GPRReg resultGPR = result.gpr();
6624
6625 flushRegisters();
6626 callOperation(compareFunction, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
6627 m_jit.exceptionCheck();
6628
6629 unblessedBooleanResult(resultGPR, node);
6630}
6631
6632void SpeculativeJIT::compileStringIdentCompare(Node* node, MacroAssembler::RelationalCondition condition)
6633{
6634 SpeculateCellOperand left(this, node->child1());
6635 SpeculateCellOperand right(this, node->child2());
6636 GPRFlushedCallResult result(this);
6637 GPRTemporary leftTemp(this);
6638 GPRTemporary rightTemp(this);
6639
6640 GPRReg leftGPR = left.gpr();
6641 GPRReg rightGPR = right.gpr();
6642 GPRReg resultGPR = result.gpr();
6643 GPRReg leftTempGPR = leftTemp.gpr();
6644 GPRReg rightTempGPR = rightTemp.gpr();
6645
6646 speculateString(node->child1(), leftGPR);
6647 speculateString(node->child2(), rightGPR);
6648
6649 C_JITOperation_TT compareFunction = nullptr;
6650 if (condition == MacroAssembler::LessThan)
6651 compareFunction = operationCompareStringImplLess;
6652 else if (condition == MacroAssembler::LessThanOrEqual)
6653 compareFunction = operationCompareStringImplLessEq;
6654 else if (condition == MacroAssembler::GreaterThan)
6655 compareFunction = operationCompareStringImplGreater;
6656 else if (condition == MacroAssembler::GreaterThanOrEqual)
6657 compareFunction = operationCompareStringImplGreaterEq;
6658 else
6659 RELEASE_ASSERT_NOT_REACHED();
6660
6661 speculateStringIdentAndLoadStorage(node->child1(), leftGPR, leftTempGPR);
6662 speculateStringIdentAndLoadStorage(node->child2(), rightGPR, rightTempGPR);
6663
6664 flushRegisters();
6665 callOperation(compareFunction, resultGPR, leftTempGPR, rightTempGPR);
6666
6667 unblessedBooleanResult(resultGPR, node);
6668}
6669
6670void SpeculativeJIT::compileSameValue(Node* node)
6671{
6672 if (node->isBinaryUseKind(DoubleRepUse)) {
6673 SpeculateDoubleOperand arg1(this, node->child1());
6674 SpeculateDoubleOperand arg2(this, node->child2());
6675 GPRTemporary result(this);
6676 GPRTemporary temp(this);
6677 GPRTemporary temp2(this);
6678
6679 FPRReg arg1FPR = arg1.fpr();
6680 FPRReg arg2FPR = arg2.fpr();
6681 GPRReg resultGPR = result.gpr();
6682 GPRReg tempGPR = temp.gpr();
6683 GPRReg temp2GPR = temp2.gpr();
6684
6685#if USE(JSVALUE64)
6686 m_jit.moveDoubleTo64(arg1FPR, tempGPR);
6687 m_jit.moveDoubleTo64(arg2FPR, temp2GPR);
6688 auto trueCase = m_jit.branch64(CCallHelpers::Equal, tempGPR, temp2GPR);
6689#else
6690 GPRTemporary temp3(this);
6691 GPRReg temp3GPR = temp3.gpr();
6692
6693 m_jit.moveDoubleToInts(arg1FPR, tempGPR, temp2GPR);
6694 m_jit.moveDoubleToInts(arg2FPR, temp3GPR, resultGPR);
6695 auto notEqual = m_jit.branch32(CCallHelpers::NotEqual, tempGPR, temp3GPR);
6696 auto trueCase = m_jit.branch32(CCallHelpers::Equal, temp2GPR, resultGPR);
6697 notEqual.link(&m_jit);
6698#endif
6699
6700 m_jit.compareDouble(CCallHelpers::DoubleNotEqualOrUnordered, arg1FPR, arg1FPR, tempGPR);
6701 m_jit.compareDouble(CCallHelpers::DoubleNotEqualOrUnordered, arg2FPR, arg2FPR, temp2GPR);
6702 m_jit.and32(tempGPR, temp2GPR, resultGPR);
6703 auto done = m_jit.jump();
6704
6705 trueCase.link(&m_jit);
6706 m_jit.move(CCallHelpers::TrustedImm32(1), resultGPR);
6707 done.link(&m_jit);
6708
6709 unblessedBooleanResult(resultGPR, node);
6710 return;
6711 }
6712
6713 ASSERT(node->isBinaryUseKind(UntypedUse));
6714
6715 JSValueOperand arg1(this, node->child1());
6716 JSValueOperand arg2(this, node->child2());
6717 JSValueRegs arg1Regs = arg1.jsValueRegs();
6718 JSValueRegs arg2Regs = arg2.jsValueRegs();
6719
6720 arg1.use();
6721 arg2.use();
6722
6723 flushRegisters();
6724
6725 GPRFlushedCallResult result(this);
6726 GPRReg resultGPR = result.gpr();
6727 callOperation(operationSameValue, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1Regs, arg2Regs);
6728 m_jit.exceptionCheck();
6729
6730 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
6731}
6732
6733void SpeculativeJIT::compileStringZeroLength(Node* node)
6734{
6735 SpeculateCellOperand str(this, node->child1());
6736 GPRReg strGPR = str.gpr();
6737
6738 // Make sure that this is a string.
6739 speculateString(node->child1(), strGPR);
6740
6741 GPRTemporary eq(this);
6742 GPRReg eqGPR = eq.gpr();
6743
6744 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(vm())), eqGPR);
6745 m_jit.comparePtr(CCallHelpers::Equal, strGPR, eqGPR, eqGPR);
6746 unblessedBooleanResult(eqGPR, node);
6747}
6748
6749void SpeculativeJIT::compileLogicalNotStringOrOther(Node* node)
6750{
6751 JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
6752 GPRTemporary temp(this);
6753 JSValueRegs valueRegs = value.jsValueRegs();
6754 GPRReg tempGPR = temp.gpr();
6755
6756 JITCompiler::Jump notCell = m_jit.branchIfNotCell(valueRegs);
6757 GPRReg cellGPR = valueRegs.payloadGPR();
6758 DFG_TYPE_CHECK(
6759 valueRegs, node->child1(), (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cellGPR));
6760
6761 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(vm())), tempGPR);
6762 m_jit.comparePtr(CCallHelpers::Equal, cellGPR, tempGPR, tempGPR);
6763 auto done = m_jit.jump();
6764
6765 notCell.link(&m_jit);
6766 DFG_TYPE_CHECK(
6767 valueRegs, node->child1(), SpecCellCheck | SpecOther, m_jit.branchIfNotOther(valueRegs, tempGPR));
6768 m_jit.move(TrustedImm32(1), tempGPR);
6769
6770 done.link(&m_jit);
6771 unblessedBooleanResult(tempGPR, node);
6772
6773}
6774
6775void SpeculativeJIT::emitStringBranch(Edge nodeUse, BasicBlock* taken, BasicBlock* notTaken)
6776{
6777 SpeculateCellOperand str(this, nodeUse);
6778
6779 GPRReg strGPR = str.gpr();
6780
6781 speculateString(nodeUse, strGPR);
6782
6783 branchPtr(CCallHelpers::Equal, strGPR, TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(vm())), notTaken);
6784 jump(taken);
6785
6786 noResult(m_currentNode);
6787}
6788
6789void SpeculativeJIT::emitStringOrOtherBranch(Edge nodeUse, BasicBlock* taken, BasicBlock* notTaken)
6790{
6791 JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
6792 GPRTemporary temp(this);
6793 JSValueRegs valueRegs = value.jsValueRegs();
6794 GPRReg tempGPR = temp.gpr();
6795
6796 JITCompiler::Jump notCell = m_jit.branchIfNotCell(valueRegs);
6797 GPRReg cellGPR = valueRegs.payloadGPR();
6798 DFG_TYPE_CHECK(valueRegs, nodeUse, (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cellGPR));
6799
6800 branchPtr(CCallHelpers::Equal, cellGPR, TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(vm())), notTaken);
6801 jump(taken, ForceJump);
6802
6803 notCell.link(&m_jit);
6804 DFG_TYPE_CHECK(
6805 valueRegs, nodeUse, SpecCellCheck | SpecOther, m_jit.branchIfNotOther(valueRegs, tempGPR));
6806 jump(notTaken);
6807 noResult(m_currentNode);
6808}
6809
6810void SpeculativeJIT::compileConstantStoragePointer(Node* node)
6811{
6812 GPRTemporary storage(this);
6813 GPRReg storageGPR = storage.gpr();
6814 m_jit.move(TrustedImmPtr(node->storagePointer()), storageGPR);
6815 storageResult(storageGPR, node);
6816}
6817
6818void SpeculativeJIT::cageTypedArrayStorage(GPRReg baseReg, GPRReg storageReg)
6819{
6820 auto untagArrayPtr = [&]() {
6821#if CPU(ARM64E)
6822 m_jit.untagArrayPtr(MacroAssembler::Address(baseReg, JSArrayBufferView::offsetOfLength()), storageReg);
6823#else
6824 UNUSED_PARAM(baseReg);
6825 UNUSED_PARAM(storageReg);
6826#endif
6827 };
6828
6829#if GIGACAGE_ENABLED
6830 UNUSED_PARAM(baseReg);
6831 if (!Gigacage::shouldBeEnabled()) {
6832 untagArrayPtr();
6833 return;
6834 }
6835
6836 if (Gigacage::canPrimitiveGigacageBeDisabled()) {
6837 VM& vm = this->vm();
6838 if (vm.primitiveGigacageEnabled().isStillValid())
6839 m_jit.graph().watchpoints().addLazily(vm.primitiveGigacageEnabled());
6840 else {
6841 untagArrayPtr();
6842 return;
6843 }
6844 }
6845
6846 m_jit.cageWithoutUntagging(Gigacage::Primitive, storageReg);
6847#endif
6848 untagArrayPtr();
6849}
6850
6851void SpeculativeJIT::compileGetIndexedPropertyStorage(Node* node)
6852{
6853 SpeculateCellOperand base(this, node->child1());
6854 GPRReg baseReg = base.gpr();
6855
6856 GPRTemporary storage(this);
6857 GPRReg storageReg = storage.gpr();
6858
6859 switch (node->arrayMode().type()) {
6860 case Array::String:
6861 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), storageReg);
6862
6863 addSlowPathGenerator(
6864 slowPathCall(
6865 m_jit.branchIfRopeStringImpl(storageReg),
6866 this, operationResolveRope, storageReg, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg));
6867
6868 m_jit.loadPtr(MacroAssembler::Address(storageReg, StringImpl::dataOffset()), storageReg);
6869 break;
6870
6871 default: {
6872 auto typedArrayType = node->arrayMode().typedArrayType();
6873 ASSERT_UNUSED(typedArrayType, isTypedView(typedArrayType));
6874
6875 m_jit.loadPtr(JITCompiler::Address(baseReg, JSArrayBufferView::offsetOfVector()), storageReg);
6876 cageTypedArrayStorage(baseReg, storageReg);
6877 break;
6878 }
6879 }
6880
6881 storageResult(storageReg, node);
6882}
6883
6884void SpeculativeJIT::compileGetTypedArrayByteOffset(Node* node)
6885{
6886 SpeculateCellOperand base(this, node->child1());
6887 GPRTemporary vector(this);
6888 GPRTemporary data(this);
6889
6890 GPRReg baseGPR = base.gpr();
6891 GPRReg vectorGPR = vector.gpr();
6892 GPRReg dataGPR = data.gpr();
6893 ASSERT(baseGPR != vectorGPR);
6894 ASSERT(baseGPR != dataGPR);
6895 ASSERT(vectorGPR != dataGPR);
6896
6897 GPRReg arrayBufferGPR = dataGPR;
6898
6899 JITCompiler::Jump emptyByteOffset = m_jit.branch32(
6900 MacroAssembler::NotEqual,
6901 MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfMode()),
6902 TrustedImm32(WastefulTypedArray));
6903
6904 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfVector()), vectorGPR);
6905
6906 // FIXME: This should mask the PAC bits
6907 // https://bugs.webkit.org/show_bug.cgi?id=197701
6908 JITCompiler::Jump nullVector = m_jit.branchTestPtr(JITCompiler::Zero, vectorGPR);
6909
6910 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), dataGPR);
6911 m_jit.cageWithoutUntagging(Gigacage::JSValue, dataGPR);
6912
6913 cageTypedArrayStorage(baseGPR, vectorGPR);
6914
6915 m_jit.loadPtr(MacroAssembler::Address(dataGPR, Butterfly::offsetOfArrayBuffer()), arrayBufferGPR);
6916 // FIXME: This needs caging.
6917 // https://bugs.webkit.org/show_bug.cgi?id=175515
6918 m_jit.loadPtr(MacroAssembler::Address(arrayBufferGPR, ArrayBuffer::offsetOfData()), dataGPR);
6919#if CPU(ARM64E)
6920 m_jit.removeArrayPtrTag(dataGPR);
6921#endif
6922
6923 m_jit.subPtr(dataGPR, vectorGPR);
6924
6925 JITCompiler::Jump done = m_jit.jump();
6926
6927 emptyByteOffset.link(&m_jit);
6928 m_jit.move(TrustedImmPtr(nullptr), vectorGPR);
6929
6930 done.link(&m_jit);
6931 nullVector.link(&m_jit);
6932
6933 int32Result(vectorGPR, node);
6934}
6935
6936void SpeculativeJIT::compileGetByValOnDirectArguments(Node* node)
6937{
6938 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
6939 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
6940 JSValueRegsTemporary result(this);
6941 GPRTemporary scratch(this);
6942
6943 GPRReg baseReg = base.gpr();
6944 GPRReg propertyReg = property.gpr();
6945 JSValueRegs resultRegs = result.regs();
6946 GPRReg scratchReg = scratch.gpr();
6947
6948 if (!m_compileOkay)
6949 return;
6950
6951 ASSERT(ArrayMode(Array::DirectArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.varArgChild(node, 0))));
6952
6953 speculationCheck(
6954 ExoticObjectMode, JSValueSource(), 0,
6955 m_jit.branchTestPtr(
6956 MacroAssembler::NonZero,
6957 MacroAssembler::Address(baseReg, DirectArguments::offsetOfMappedArguments())));
6958
6959 m_jit.load32(CCallHelpers::Address(baseReg, DirectArguments::offsetOfLength()), scratchReg);
6960 auto isOutOfBounds = m_jit.branch32(CCallHelpers::AboveOrEqual, propertyReg, scratchReg);
6961 if (node->arrayMode().isInBounds())
6962 speculationCheck(OutOfBounds, JSValueSource(), 0, isOutOfBounds);
6963
6964 m_jit.loadValue(
6965 MacroAssembler::BaseIndex(
6966 baseReg, propertyReg, MacroAssembler::TimesEight, DirectArguments::storageOffset()),
6967 resultRegs);
6968
6969 if (!node->arrayMode().isInBounds()) {
6970 addSlowPathGenerator(
6971 slowPathCall(
6972 isOutOfBounds, this, operationGetByValObjectInt,
6973 extractResult(resultRegs), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
6974 }
6975
6976 jsValueResult(resultRegs, node);
6977}
6978
6979void SpeculativeJIT::compileGetByValOnScopedArguments(Node* node)
6980{
6981 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
6982 SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
6983 JSValueRegsTemporary result(this);
6984 GPRTemporary scratch(this);
6985 GPRTemporary scratch2(this);
6986
6987 GPRReg baseReg = base.gpr();
6988 GPRReg propertyReg = property.gpr();
6989 JSValueRegs resultRegs = result.regs();
6990 GPRReg scratchReg = scratch.gpr();
6991 GPRReg scratch2Reg = scratch2.gpr();
6992
6993 if (!m_compileOkay)
6994 return;
6995
6996 ASSERT(ArrayMode(Array::ScopedArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.varArgChild(node, 0))));
6997
6998 m_jit.loadPtr(
6999 MacroAssembler::Address(baseReg, ScopedArguments::offsetOfStorage()), resultRegs.payloadGPR());
7000
7001 speculationCheck(
7002 ExoticObjectMode, JSValueSource(), nullptr,
7003 m_jit.branch32(
7004 MacroAssembler::AboveOrEqual, propertyReg,
7005 MacroAssembler::Address(baseReg, ScopedArguments::offsetOfTotalLength())));
7006
7007 m_jit.loadPtr(MacroAssembler::Address(baseReg, ScopedArguments::offsetOfTable()), scratchReg);
7008 m_jit.load32(
7009 MacroAssembler::Address(scratchReg, ScopedArgumentsTable::offsetOfLength()), scratch2Reg);
7010
7011 MacroAssembler::Jump overflowArgument = m_jit.branch32(
7012 MacroAssembler::AboveOrEqual, propertyReg, scratch2Reg);
7013
7014 m_jit.loadPtr(MacroAssembler::Address(baseReg, ScopedArguments::offsetOfScope()), scratch2Reg);
7015
7016 m_jit.loadPtr(
7017 MacroAssembler::Address(scratchReg, ScopedArgumentsTable::offsetOfArguments()),
7018 scratchReg);
7019 m_jit.load32(
7020 MacroAssembler::BaseIndex(scratchReg, propertyReg, MacroAssembler::TimesFour),
7021 scratchReg);
7022
7023 speculationCheck(
7024 ExoticObjectMode, JSValueSource(), nullptr,
7025 m_jit.branch32(
7026 MacroAssembler::Equal, scratchReg, TrustedImm32(ScopeOffset::invalidOffset)));
7027
7028 m_jit.loadValue(
7029 MacroAssembler::BaseIndex(
7030 scratch2Reg, propertyReg, MacroAssembler::TimesEight,
7031 JSLexicalEnvironment::offsetOfVariables()),
7032 resultRegs);
7033
7034 MacroAssembler::Jump done = m_jit.jump();
7035 overflowArgument.link(&m_jit);
7036
7037 m_jit.sub32(propertyReg, scratch2Reg);
7038 m_jit.neg32(scratch2Reg);
7039
7040 m_jit.loadValue(
7041 MacroAssembler::BaseIndex(
7042 resultRegs.payloadGPR(), scratch2Reg, MacroAssembler::TimesEight),
7043 resultRegs);
7044 speculationCheck(ExoticObjectMode, JSValueSource(), nullptr, m_jit.branchIfEmpty(resultRegs));
7045
7046 done.link(&m_jit);
7047
7048 jsValueResult(resultRegs, node);
7049}
7050
7051void SpeculativeJIT::compileGetScope(Node* node)
7052{
7053 SpeculateCellOperand function(this, node->child1());
7054 GPRTemporary result(this, Reuse, function);
7055 m_jit.loadPtr(JITCompiler::Address(function.gpr(), JSFunction::offsetOfScopeChain()), result.gpr());
7056 cellResult(result.gpr(), node);
7057}
7058
7059void SpeculativeJIT::compileSkipScope(Node* node)
7060{
7061 SpeculateCellOperand scope(this, node->child1());
7062 GPRTemporary result(this, Reuse, scope);
7063 m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSScope::offsetOfNext()), result.gpr());
7064 cellResult(result.gpr(), node);
7065}
7066
7067void SpeculativeJIT::compileGetGlobalObject(Node* node)
7068{
7069 SpeculateCellOperand object(this, node->child1());
7070 GPRTemporary result(this);
7071 GPRTemporary scratch(this);
7072 m_jit.emitLoadStructure(vm(), object.gpr(), result.gpr(), scratch.gpr());
7073 m_jit.loadPtr(JITCompiler::Address(result.gpr(), Structure::globalObjectOffset()), result.gpr());
7074 cellResult(result.gpr(), node);
7075}
7076
7077void SpeculativeJIT::compileGetGlobalThis(Node* node)
7078{
7079 GPRTemporary result(this);
7080 GPRReg resultGPR = result.gpr();
7081 auto* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
7082 m_jit.loadPtr(globalObject->addressOfGlobalThis(), resultGPR);
7083 cellResult(resultGPR, node);
7084}
7085
7086bool SpeculativeJIT::canBeRope(Edge& edge)
7087{
7088 if (m_state.forNode(edge).isType(SpecStringIdent))
7089 return false;
7090 // If this value is LazyValue, it will be converted to JSString, and the result must be non-rope string.
7091 String string = edge->tryGetString(m_graph);
7092 if (!string.isNull())
7093 return false;
7094 return true;
7095}
7096
7097void SpeculativeJIT::compileGetArrayLength(Node* node)
7098{
7099 switch (node->arrayMode().type()) {
7100 case Array::Undecided:
7101 case Array::Int32:
7102 case Array::Double:
7103 case Array::Contiguous: {
7104 StorageOperand storage(this, node->child2());
7105 GPRTemporary result(this, Reuse, storage);
7106 GPRReg storageReg = storage.gpr();
7107 GPRReg resultReg = result.gpr();
7108 m_jit.load32(MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()), resultReg);
7109
7110 int32Result(resultReg, node);
7111 break;
7112 }
7113 case Array::ArrayStorage:
7114 case Array::SlowPutArrayStorage: {
7115 StorageOperand storage(this, node->child2());
7116 GPRTemporary result(this, Reuse, storage);
7117 GPRReg storageReg = storage.gpr();
7118 GPRReg resultReg = result.gpr();
7119 m_jit.load32(MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()), resultReg);
7120
7121 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, resultReg, MacroAssembler::TrustedImm32(0)));
7122
7123 int32Result(resultReg, node);
7124 break;
7125 }
7126 case Array::String: {
7127 SpeculateCellOperand base(this, node->child1());
7128 GPRTemporary result(this, Reuse, base);
7129 GPRTemporary temp(this);
7130 GPRReg baseGPR = base.gpr();
7131 GPRReg resultGPR = result.gpr();
7132 GPRReg tempGPR = temp.gpr();
7133
7134 bool needsRopeCase = canBeRope(node->child1());
7135
7136 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSString::offsetOfValue()), tempGPR);
7137 CCallHelpers::Jump isRope;
7138 if (needsRopeCase)
7139 isRope = m_jit.branchIfRopeStringImpl(tempGPR);
7140 m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), resultGPR);
7141 if (needsRopeCase) {
7142 auto done = m_jit.jump();
7143
7144 isRope.link(&m_jit);
7145 m_jit.load32(CCallHelpers::Address(baseGPR, JSRopeString::offsetOfLength()), resultGPR);
7146
7147 done.link(&m_jit);
7148 }
7149 int32Result(resultGPR, node);
7150 break;
7151 }
7152 case Array::DirectArguments: {
7153 SpeculateCellOperand base(this, node->child1());
7154 GPRTemporary result(this, Reuse, base);
7155
7156 GPRReg baseReg = base.gpr();
7157 GPRReg resultReg = result.gpr();
7158
7159 if (!m_compileOkay)
7160 return;
7161
7162 ASSERT(ArrayMode(Array::DirectArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1())));
7163
7164 speculationCheck(
7165 ExoticObjectMode, JSValueSource(), 0,
7166 m_jit.branchTestPtr(
7167 MacroAssembler::NonZero,
7168 MacroAssembler::Address(baseReg, DirectArguments::offsetOfMappedArguments())));
7169
7170 m_jit.load32(
7171 MacroAssembler::Address(baseReg, DirectArguments::offsetOfLength()), resultReg);
7172
7173 int32Result(resultReg, node);
7174 break;
7175 }
7176 case Array::ScopedArguments: {
7177 SpeculateCellOperand base(this, node->child1());
7178 GPRTemporary result(this, Reuse, base);
7179
7180 GPRReg baseReg = base.gpr();
7181 GPRReg resultReg = result.gpr();
7182
7183 if (!m_compileOkay)
7184 return;
7185
7186 ASSERT(ArrayMode(Array::ScopedArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1())));
7187
7188 speculationCheck(
7189 ExoticObjectMode, JSValueSource(), 0,
7190 m_jit.branchTest8(
7191 MacroAssembler::NonZero,
7192 MacroAssembler::Address(baseReg, ScopedArguments::offsetOfOverrodeThings())));
7193
7194 m_jit.load32(
7195 MacroAssembler::Address(baseReg, ScopedArguments::offsetOfTotalLength()), resultReg);
7196
7197 int32Result(resultReg, node);
7198 break;
7199 }
7200 default: {
7201 ASSERT(node->arrayMode().isSomeTypedArrayView());
7202 SpeculateCellOperand base(this, node->child1());
7203 GPRTemporary result(this, Reuse, base);
7204 GPRReg baseGPR = base.gpr();
7205 GPRReg resultGPR = result.gpr();
7206 m_jit.load32(MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfLength()), resultGPR);
7207 int32Result(resultGPR, node);
7208 break;
7209 } }
7210}
7211
7212void SpeculativeJIT::compileCheckIdent(Node* node)
7213{
7214 SpeculateCellOperand stringOrSymbol(this, node->child1());
7215 GPRTemporary impl(this);
7216 GPRReg stringOrSymbolGPR = stringOrSymbol.gpr();
7217 GPRReg implGPR = impl.gpr();
7218
7219 if (node->child1().useKind() == StringIdentUse) {
7220 speculateString(node->child1(), stringOrSymbolGPR);
7221 speculateStringIdentAndLoadStorage(node->child1(), stringOrSymbolGPR, implGPR);
7222 } else {
7223 ASSERT(node->child1().useKind() == SymbolUse);
7224 speculateSymbol(node->child1(), stringOrSymbolGPR);
7225 m_jit.loadPtr(MacroAssembler::Address(stringOrSymbolGPR, Symbol::offsetOfSymbolImpl()), implGPR);
7226 }
7227
7228 UniquedStringImpl* uid = node->uidOperand();
7229 speculationCheck(
7230 BadIdent, JSValueSource(), nullptr,
7231 m_jit.branchPtr(JITCompiler::NotEqual, implGPR, TrustedImmPtr(uid)));
7232 noResult(node);
7233}
7234
7235template <typename ClassType>
7236void SpeculativeJIT::compileNewFunctionCommon(GPRReg resultGPR, RegisteredStructure structure, GPRReg scratch1GPR, GPRReg scratch2GPR, GPRReg scopeGPR, MacroAssembler::JumpList& slowPath, size_t size, FunctionExecutable* executable)
7237{
7238 auto butterfly = TrustedImmPtr(nullptr);
7239 emitAllocateJSObjectWithKnownSize<ClassType>(resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR, slowPath, size);
7240
7241 m_jit.storePtr(scopeGPR, JITCompiler::Address(resultGPR, JSFunction::offsetOfScopeChain()));
7242 m_jit.storePtr(TrustedImmPtr::weakPointer(m_jit.graph(), executable), JITCompiler::Address(resultGPR, JSFunction::offsetOfExecutable()));
7243 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, JSFunction::offsetOfRareData()));
7244 m_jit.storePtr(TrustedImmPtr::weakPointer(m_jit.graph(), structure->globalObject()), JITCompiler::Address(resultGPR, JSFunction::offsetOfGlobalObject()));
7245 m_jit.mutatorFence(vm());
7246}
7247
7248void SpeculativeJIT::compileNewFunction(Node* node)
7249{
7250 NodeType nodeType = node->op();
7251 ASSERT(nodeType == NewFunction || nodeType == NewGeneratorFunction || nodeType == NewAsyncFunction || nodeType == NewAsyncGeneratorFunction);
7252
7253 SpeculateCellOperand scope(this, node->child1());
7254 GPRReg scopeGPR = scope.gpr();
7255
7256 FunctionExecutable* executable = node->castOperand<FunctionExecutable*>();
7257
7258 if (executable->singleton().isStillValid()) {
7259 GPRFlushedCallResult result(this);
7260 GPRReg resultGPR = result.gpr();
7261
7262 flushRegisters();
7263
7264 if (nodeType == NewGeneratorFunction)
7265 callOperation(operationNewGeneratorFunction, resultGPR, &vm(), scopeGPR, executable);
7266 else if (nodeType == NewAsyncFunction)
7267 callOperation(operationNewAsyncFunction, resultGPR, &vm(), scopeGPR, executable);
7268 else if (nodeType == NewAsyncGeneratorFunction)
7269 callOperation(operationNewAsyncGeneratorFunction, resultGPR, &vm(), scopeGPR, executable);
7270 else
7271 callOperation(operationNewFunction, resultGPR, &vm(), scopeGPR, executable);
7272 m_jit.exceptionCheck();
7273 cellResult(resultGPR, node);
7274 return;
7275 }
7276
7277 RegisteredStructure structure = m_jit.graph().registerStructure(
7278 [&] () {
7279 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
7280 switch (nodeType) {
7281 case NewGeneratorFunction:
7282 return globalObject->generatorFunctionStructure();
7283 case NewAsyncFunction:
7284 return globalObject->asyncFunctionStructure();
7285 case NewAsyncGeneratorFunction:
7286 return globalObject->asyncGeneratorFunctionStructure();
7287 case NewFunction:
7288 return JSFunction::selectStructureForNewFuncExp(globalObject, node->castOperand<FunctionExecutable*>());
7289 default:
7290 RELEASE_ASSERT_NOT_REACHED();
7291 }
7292 }());
7293
7294 GPRTemporary result(this);
7295 GPRTemporary scratch1(this);
7296 GPRTemporary scratch2(this);
7297
7298 GPRReg resultGPR = result.gpr();
7299 GPRReg scratch1GPR = scratch1.gpr();
7300 GPRReg scratch2GPR = scratch2.gpr();
7301
7302 JITCompiler::JumpList slowPath;
7303
7304 if (nodeType == NewFunction) {
7305 compileNewFunctionCommon<JSFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSFunction::allocationSize(0), executable);
7306
7307 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewFunctionWithInvalidatedReallocationWatchpoint, resultGPR, &vm(), scopeGPR, executable));
7308 }
7309
7310 if (nodeType == NewGeneratorFunction) {
7311 compileNewFunctionCommon<JSGeneratorFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSGeneratorFunction::allocationSize(0), executable);
7312
7313 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewGeneratorFunctionWithInvalidatedReallocationWatchpoint, resultGPR, &vm(), scopeGPR, executable));
7314 }
7315
7316 if (nodeType == NewAsyncFunction) {
7317 compileNewFunctionCommon<JSAsyncFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSAsyncFunction::allocationSize(0), executable);
7318
7319 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewAsyncFunctionWithInvalidatedReallocationWatchpoint, resultGPR, &vm(), scopeGPR, executable));
7320 }
7321
7322 if (nodeType == NewAsyncGeneratorFunction) {
7323 compileNewFunctionCommon<JSAsyncGeneratorFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSAsyncGeneratorFunction::allocationSize(0), executable);
7324
7325 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewAsyncGeneratorFunctionWithInvalidatedReallocationWatchpoint, resultGPR, &vm(), scopeGPR, executable));
7326 }
7327
7328 cellResult(resultGPR, node);
7329}
7330
7331void SpeculativeJIT::compileSetFunctionName(Node* node)
7332{
7333 SpeculateCellOperand func(this, node->child1());
7334 GPRReg funcGPR = func.gpr();
7335 JSValueOperand nameValue(this, node->child2());
7336 JSValueRegs nameValueRegs = nameValue.jsValueRegs();
7337
7338 flushRegisters();
7339 callOperation(operationSetFunctionName, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), funcGPR, nameValueRegs);
7340 m_jit.exceptionCheck();
7341
7342 noResult(node);
7343}
7344
7345void SpeculativeJIT::compileLoadVarargs(Node* node)
7346{
7347 LoadVarargsData* data = node->loadVarargsData();
7348
7349 JSValueRegs argumentsRegs;
7350 {
7351 JSValueOperand arguments(this, node->child1());
7352 argumentsRegs = arguments.jsValueRegs();
7353 flushRegisters();
7354 }
7355
7356 callOperation(operationSizeOfVarargs, GPRInfo::returnValueGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), argumentsRegs, data->offset);
7357 m_jit.exceptionCheck();
7358
7359 lock(GPRInfo::returnValueGPR);
7360 {
7361 JSValueOperand arguments(this, node->child1());
7362 argumentsRegs = arguments.jsValueRegs();
7363 flushRegisters();
7364 }
7365 unlock(GPRInfo::returnValueGPR);
7366
7367 // FIXME: There is a chance that we will call an effectful length property twice. This is safe
7368 // from the standpoint of the VM's integrity, but it's subtly wrong from a spec compliance
7369 // standpoint. The best solution would be one where we can exit *into* the op_call_varargs right
7370 // past the sizing.
7371 // https://bugs.webkit.org/show_bug.cgi?id=141448
7372
7373 GPRReg argCountIncludingThisGPR =
7374 JITCompiler::selectScratchGPR(GPRInfo::returnValueGPR, argumentsRegs);
7375
7376 m_jit.add32(TrustedImm32(1), GPRInfo::returnValueGPR, argCountIncludingThisGPR);
7377
7378 speculationCheck(
7379 VarargsOverflow, JSValueSource(), Edge(), m_jit.branch32(
7380 MacroAssembler::Above,
7381 GPRInfo::returnValueGPR,
7382 argCountIncludingThisGPR));
7383
7384 speculationCheck(
7385 VarargsOverflow, JSValueSource(), Edge(), m_jit.branch32(
7386 MacroAssembler::Above,
7387 argCountIncludingThisGPR,
7388 TrustedImm32(data->limit)));
7389
7390 m_jit.store32(argCountIncludingThisGPR, JITCompiler::payloadFor(data->machineCount));
7391
7392 callOperation(operationLoadVarargs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), data->machineStart.offset(), argumentsRegs, data->offset, GPRInfo::returnValueGPR, data->mandatoryMinimum);
7393 m_jit.exceptionCheck();
7394
7395 noResult(node);
7396}
7397
7398void SpeculativeJIT::compileForwardVarargs(Node* node)
7399{
7400 LoadVarargsData* data = node->loadVarargsData();
7401 InlineCallFrame* inlineCallFrame;
7402 if (node->child1())
7403 inlineCallFrame = node->child1()->origin.semantic.inlineCallFrame();
7404 else
7405 inlineCallFrame = node->origin.semantic.inlineCallFrame();
7406
7407 GPRTemporary length(this);
7408 JSValueRegsTemporary temp(this);
7409 GPRReg lengthGPR = length.gpr();
7410 JSValueRegs tempRegs = temp.regs();
7411
7412 emitGetLength(inlineCallFrame, lengthGPR, /* includeThis = */ true);
7413 if (data->offset)
7414 m_jit.sub32(TrustedImm32(data->offset), lengthGPR);
7415
7416 speculationCheck(
7417 VarargsOverflow, JSValueSource(), Edge(), m_jit.branch32(
7418 MacroAssembler::Above,
7419 lengthGPR, TrustedImm32(data->limit)));
7420
7421 m_jit.store32(lengthGPR, JITCompiler::payloadFor(data->machineCount));
7422
7423 VirtualRegister sourceStart = JITCompiler::argumentsStart(inlineCallFrame) + data->offset;
7424 VirtualRegister targetStart = data->machineStart;
7425
7426 m_jit.sub32(TrustedImm32(1), lengthGPR);
7427
7428 // First have a loop that fills in the undefined slots in case of an arity check failure.
7429 m_jit.move(TrustedImm32(data->mandatoryMinimum), tempRegs.payloadGPR());
7430 JITCompiler::Jump done = m_jit.branch32(JITCompiler::BelowOrEqual, tempRegs.payloadGPR(), lengthGPR);
7431
7432 JITCompiler::Label loop = m_jit.label();
7433 m_jit.sub32(TrustedImm32(1), tempRegs.payloadGPR());
7434 m_jit.storeTrustedValue(
7435 jsUndefined(),
7436 JITCompiler::BaseIndex(
7437 GPRInfo::callFrameRegister, tempRegs.payloadGPR(), JITCompiler::TimesEight,
7438 targetStart.offset() * sizeof(EncodedJSValue)));
7439 m_jit.branch32(JITCompiler::Above, tempRegs.payloadGPR(), lengthGPR).linkTo(loop, &m_jit);
7440 done.link(&m_jit);
7441
7442 // And then fill in the actual argument values.
7443 done = m_jit.branchTest32(JITCompiler::Zero, lengthGPR);
7444
7445 loop = m_jit.label();
7446 m_jit.sub32(TrustedImm32(1), lengthGPR);
7447 m_jit.loadValue(
7448 JITCompiler::BaseIndex(
7449 GPRInfo::callFrameRegister, lengthGPR, JITCompiler::TimesEight,
7450 sourceStart.offset() * sizeof(EncodedJSValue)),
7451 tempRegs);
7452 m_jit.storeValue(
7453 tempRegs,
7454 JITCompiler::BaseIndex(
7455 GPRInfo::callFrameRegister, lengthGPR, JITCompiler::TimesEight,
7456 targetStart.offset() * sizeof(EncodedJSValue)));
7457 m_jit.branchTest32(JITCompiler::NonZero, lengthGPR).linkTo(loop, &m_jit);
7458
7459 done.link(&m_jit);
7460
7461 noResult(node);
7462}
7463
7464void SpeculativeJIT::compileCreateActivation(Node* node)
7465{
7466 SymbolTable* table = node->castOperand<SymbolTable*>();
7467 RegisteredStructure structure = m_jit.graph().registerStructure(m_jit.graph().globalObjectFor(
7468 node->origin.semantic)->activationStructure());
7469
7470 SpeculateCellOperand scope(this, node->child1());
7471 GPRReg scopeGPR = scope.gpr();
7472 JSValue initializationValue = node->initializationValueForActivation();
7473 ASSERT(initializationValue == jsUndefined() || initializationValue == jsTDZValue());
7474
7475 if (table->singleton().isStillValid()) {
7476 GPRFlushedCallResult result(this);
7477 GPRReg resultGPR = result.gpr();
7478
7479#if USE(JSVALUE32_64)
7480 JSValueRegsTemporary initialization(this);
7481 JSValueRegs initializationRegs = initialization.regs();
7482 m_jit.moveTrustedValue(initializationValue, initializationRegs);
7483#endif
7484
7485 flushRegisters();
7486
7487#if USE(JSVALUE64)
7488 callOperation(operationCreateActivationDirect,
7489 resultGPR, &vm(), structure, scopeGPR, table, TrustedImm64(JSValue::encode(initializationValue)));
7490#else
7491 callOperation(operationCreateActivationDirect,
7492 resultGPR, &vm(), structure, scopeGPR, table, initializationRegs);
7493#endif
7494 m_jit.exceptionCheck();
7495 cellResult(resultGPR, node);
7496 return;
7497 }
7498
7499 GPRTemporary result(this);
7500 GPRTemporary scratch1(this);
7501 GPRTemporary scratch2(this);
7502 GPRReg resultGPR = result.gpr();
7503 GPRReg scratch1GPR = scratch1.gpr();
7504 GPRReg scratch2GPR = scratch2.gpr();
7505
7506#if USE(JSVALUE32_64)
7507 JSValueRegsTemporary initialization(this);
7508 JSValueRegs initializationRegs = initialization.regs();
7509 m_jit.moveTrustedValue(initializationValue, initializationRegs);
7510#endif
7511
7512 JITCompiler::JumpList slowPath;
7513 auto butterfly = TrustedImmPtr(nullptr);
7514 emitAllocateJSObjectWithKnownSize<JSLexicalEnvironment>(
7515 resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR,
7516 slowPath, JSLexicalEnvironment::allocationSize(table));
7517
7518 // Don't need a memory barriers since we just fast-created the activation, so the
7519 // activation must be young.
7520 m_jit.storePtr(scopeGPR, JITCompiler::Address(resultGPR, JSScope::offsetOfNext()));
7521 m_jit.storePtr(
7522 TrustedImmPtr(node->cellOperand()),
7523 JITCompiler::Address(resultGPR, JSLexicalEnvironment::offsetOfSymbolTable()));
7524
7525 // Must initialize all members to undefined or the TDZ empty value.
7526 for (unsigned i = 0; i < table->scopeSize(); ++i) {
7527 m_jit.storeTrustedValue(
7528 initializationValue,
7529 JITCompiler::Address(
7530 resultGPR, JSLexicalEnvironment::offsetOfVariable(ScopeOffset(i))));
7531 }
7532
7533 m_jit.mutatorFence(vm());
7534
7535#if USE(JSVALUE64)
7536 addSlowPathGenerator(
7537 slowPathCall(
7538 slowPath, this, operationCreateActivationDirect, resultGPR, &vm(), structure, scopeGPR, table, TrustedImm64(JSValue::encode(initializationValue))));
7539#else
7540 addSlowPathGenerator(
7541 slowPathCall(
7542 slowPath, this, operationCreateActivationDirect, resultGPR, &vm(), structure, scopeGPR, table, initializationRegs));
7543#endif
7544
7545 cellResult(resultGPR, node);
7546}
7547
7548void SpeculativeJIT::compileCreateDirectArguments(Node* node)
7549{
7550 // FIXME: A more effective way of dealing with the argument count and callee is to have
7551 // them be explicit arguments to this node.
7552 // https://bugs.webkit.org/show_bug.cgi?id=142207
7553
7554 GPRTemporary result(this);
7555 GPRTemporary scratch1(this);
7556 GPRTemporary scratch2(this);
7557 GPRTemporary length;
7558 GPRReg resultGPR = result.gpr();
7559 GPRReg scratch1GPR = scratch1.gpr();
7560 GPRReg scratch2GPR = scratch2.gpr();
7561 GPRReg lengthGPR = InvalidGPRReg;
7562 JSValueRegs valueRegs = JSValueRegs::withTwoAvailableRegs(scratch1GPR, scratch2GPR);
7563
7564 unsigned minCapacity = m_jit.graph().baselineCodeBlockFor(node->origin.semantic)->numParameters() - 1;
7565
7566 unsigned knownLength;
7567 bool lengthIsKnown; // if false, lengthGPR will have the length.
7568 auto* inlineCallFrame = node->origin.semantic.inlineCallFrame();
7569 if (inlineCallFrame
7570 && !inlineCallFrame->isVarargs()) {
7571 knownLength = inlineCallFrame->argumentCountIncludingThis - 1;
7572 lengthIsKnown = true;
7573 } else {
7574 knownLength = UINT_MAX;
7575 lengthIsKnown = false;
7576
7577 GPRTemporary realLength(this);
7578 length.adopt(realLength);
7579 lengthGPR = length.gpr();
7580
7581 VirtualRegister argumentCountRegister = m_jit.argumentCount(node->origin.semantic);
7582 m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), lengthGPR);
7583 m_jit.sub32(TrustedImm32(1), lengthGPR);
7584 }
7585
7586 RegisteredStructure structure =
7587 m_jit.graph().registerStructure(m_jit.graph().globalObjectFor(node->origin.semantic)->directArgumentsStructure());
7588
7589 // Use a different strategy for allocating the object depending on whether we know its
7590 // size statically.
7591 JITCompiler::JumpList slowPath;
7592 if (lengthIsKnown) {
7593 auto butterfly = TrustedImmPtr(nullptr);
7594 emitAllocateJSObjectWithKnownSize<DirectArguments>(
7595 resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR,
7596 slowPath, DirectArguments::allocationSize(std::max(knownLength, minCapacity)));
7597
7598 m_jit.store32(
7599 TrustedImm32(knownLength),
7600 JITCompiler::Address(resultGPR, DirectArguments::offsetOfLength()));
7601 } else {
7602 JITCompiler::Jump tooFewArguments;
7603 if (minCapacity) {
7604 tooFewArguments =
7605 m_jit.branch32(JITCompiler::Below, lengthGPR, TrustedImm32(minCapacity));
7606 }
7607 m_jit.lshift32(lengthGPR, TrustedImm32(3), scratch1GPR);
7608 m_jit.add32(TrustedImm32(DirectArguments::storageOffset()), scratch1GPR);
7609 if (minCapacity) {
7610 JITCompiler::Jump done = m_jit.jump();
7611 tooFewArguments.link(&m_jit);
7612 m_jit.move(TrustedImm32(DirectArguments::allocationSize(minCapacity)), scratch1GPR);
7613 done.link(&m_jit);
7614 }
7615
7616 emitAllocateVariableSizedJSObject<DirectArguments>(
7617 resultGPR, TrustedImmPtr(structure), scratch1GPR, scratch1GPR, scratch2GPR,
7618 slowPath);
7619
7620 m_jit.store32(
7621 lengthGPR, JITCompiler::Address(resultGPR, DirectArguments::offsetOfLength()));
7622 }
7623
7624 m_jit.store32(
7625 TrustedImm32(minCapacity),
7626 JITCompiler::Address(resultGPR, DirectArguments::offsetOfMinCapacity()));
7627
7628 m_jit.storePtr(
7629 TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, DirectArguments::offsetOfMappedArguments()));
7630
7631 m_jit.storePtr(
7632 TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, DirectArguments::offsetOfModifiedArgumentsDescriptor()));
7633
7634 if (lengthIsKnown) {
7635 addSlowPathGenerator(
7636 slowPathCall(
7637 slowPath, this, operationCreateDirectArguments, resultGPR, &vm(), structure,
7638 knownLength, minCapacity));
7639 } else {
7640 auto generator = makeUnique<CallCreateDirectArgumentsSlowPathGenerator>(
7641 slowPath, this, resultGPR, structure, lengthGPR, minCapacity);
7642 addSlowPathGenerator(WTFMove(generator));
7643 }
7644
7645 if (inlineCallFrame) {
7646 if (inlineCallFrame->isClosureCall) {
7647 m_jit.loadPtr(
7648 JITCompiler::addressFor(
7649 inlineCallFrame->calleeRecovery.virtualRegister()),
7650 scratch1GPR);
7651 } else {
7652 m_jit.move(
7653 TrustedImmPtr::weakPointer(
7654 m_jit.graph(), inlineCallFrame->calleeRecovery.constant().asCell()),
7655 scratch1GPR);
7656 }
7657 } else
7658 m_jit.loadPtr(JITCompiler::addressFor(CallFrameSlot::callee), scratch1GPR);
7659
7660 // Don't need a memory barriers since we just fast-created the activation, so the
7661 // activation must be young.
7662 m_jit.storePtr(
7663 scratch1GPR, JITCompiler::Address(resultGPR, DirectArguments::offsetOfCallee()));
7664
7665 VirtualRegister start = m_jit.argumentsStart(node->origin.semantic);
7666 if (lengthIsKnown) {
7667 for (unsigned i = 0; i < std::max(knownLength, minCapacity); ++i) {
7668 m_jit.loadValue(JITCompiler::addressFor(start + i), valueRegs);
7669 m_jit.storeValue(
7670 valueRegs, JITCompiler::Address(resultGPR, DirectArguments::offsetOfSlot(i)));
7671 }
7672 } else {
7673 JITCompiler::Jump done;
7674 if (minCapacity) {
7675 JITCompiler::Jump startLoop = m_jit.branch32(
7676 JITCompiler::AboveOrEqual, lengthGPR, TrustedImm32(minCapacity));
7677 m_jit.move(TrustedImm32(minCapacity), lengthGPR);
7678 startLoop.link(&m_jit);
7679 } else
7680 done = m_jit.branchTest32(MacroAssembler::Zero, lengthGPR);
7681 JITCompiler::Label loop = m_jit.label();
7682 m_jit.sub32(TrustedImm32(1), lengthGPR);
7683 m_jit.loadValue(
7684 JITCompiler::BaseIndex(
7685 GPRInfo::callFrameRegister, lengthGPR, JITCompiler::TimesEight,
7686 start.offset() * static_cast<int>(sizeof(Register))),
7687 valueRegs);
7688 m_jit.storeValue(
7689 valueRegs,
7690 JITCompiler::BaseIndex(
7691 resultGPR, lengthGPR, JITCompiler::TimesEight,
7692 DirectArguments::storageOffset()));
7693 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loop, &m_jit);
7694 if (done.isSet())
7695 done.link(&m_jit);
7696 }
7697
7698 m_jit.mutatorFence(vm());
7699
7700 cellResult(resultGPR, node);
7701}
7702
7703void SpeculativeJIT::compileGetFromArguments(Node* node)
7704{
7705 SpeculateCellOperand arguments(this, node->child1());
7706 JSValueRegsTemporary result(this);
7707
7708 GPRReg argumentsGPR = arguments.gpr();
7709 JSValueRegs resultRegs = result.regs();
7710
7711 m_jit.loadValue(JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfSlot(node->capturedArgumentsOffset().offset())), resultRegs);
7712 jsValueResult(resultRegs, node);
7713}
7714
7715void SpeculativeJIT::compilePutToArguments(Node* node)
7716{
7717 SpeculateCellOperand arguments(this, node->child1());
7718 JSValueOperand value(this, node->child2());
7719
7720 GPRReg argumentsGPR = arguments.gpr();
7721 JSValueRegs valueRegs = value.jsValueRegs();
7722
7723 m_jit.storeValue(valueRegs, JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfSlot(node->capturedArgumentsOffset().offset())));
7724 noResult(node);
7725}
7726
7727void SpeculativeJIT::compileGetArgument(Node* node)
7728{
7729 GPRTemporary argumentCount(this);
7730 JSValueRegsTemporary result(this);
7731 GPRReg argumentCountGPR = argumentCount.gpr();
7732 JSValueRegs resultRegs = result.regs();
7733 m_jit.load32(CCallHelpers::payloadFor(m_jit.argumentCount(node->origin.semantic)), argumentCountGPR);
7734 auto argumentOutOfBounds = m_jit.branch32(CCallHelpers::LessThanOrEqual, argumentCountGPR, CCallHelpers::TrustedImm32(node->argumentIndex()));
7735 m_jit.loadValue(CCallHelpers::addressFor(CCallHelpers::argumentsStart(node->origin.semantic) + node->argumentIndex() - 1), resultRegs);
7736 auto done = m_jit.jump();
7737
7738 argumentOutOfBounds.link(&m_jit);
7739 m_jit.moveValue(jsUndefined(), resultRegs);
7740
7741 done.link(&m_jit);
7742 jsValueResult(resultRegs, node);
7743}
7744
7745void SpeculativeJIT::compileCreateScopedArguments(Node* node)
7746{
7747 SpeculateCellOperand scope(this, node->child1());
7748 GPRReg scopeGPR = scope.gpr();
7749
7750 GPRFlushedCallResult result(this);
7751 GPRReg resultGPR = result.gpr();
7752 flushRegisters();
7753
7754 JSGlobalObject* globalObject = m_jit.globalObjectFor(node->origin.semantic);
7755
7756 // We set up the arguments ourselves, because we have the whole register file and we can
7757 // set them up directly into the argument registers. This also means that we don't have to
7758 // invent a four-argument-register shuffle.
7759
7760 // Arguments: 0:JSGlobalObject*, 1:structure, 2:start, 3:length, 4:callee, 5:scope
7761
7762 // Do the scopeGPR first, since it might alias an argument register.
7763 m_jit.setupArgument(5, [&] (GPRReg destGPR) { m_jit.move(scopeGPR, destGPR); });
7764
7765 // These other things could be done in any order.
7766 m_jit.setupArgument(4, [&] (GPRReg destGPR) { emitGetCallee(node->origin.semantic, destGPR); });
7767 m_jit.setupArgument(3, [&] (GPRReg destGPR) { emitGetLength(node->origin.semantic, destGPR); });
7768 m_jit.setupArgument(2, [&] (GPRReg destGPR) { emitGetArgumentStart(node->origin.semantic, destGPR); });
7769 m_jit.setupArgument(
7770 1, [&] (GPRReg destGPR) {
7771 m_jit.move(
7772 TrustedImmPtr::weakPointer(m_jit.graph(), globalObject->scopedArgumentsStructure()),
7773 destGPR);
7774 });
7775 m_jit.setupArgument(0, [&] (GPRReg destGPR) { m_jit.move(TrustedImmPtr::weakPointer(m_graph, globalObject), destGPR); });
7776
7777 appendCallSetResult(operationCreateScopedArguments, resultGPR);
7778 m_jit.exceptionCheck();
7779
7780 cellResult(resultGPR, node);
7781}
7782
7783void SpeculativeJIT::compileCreateClonedArguments(Node* node)
7784{
7785 GPRFlushedCallResult result(this);
7786 GPRReg resultGPR = result.gpr();
7787 flushRegisters();
7788
7789 JSGlobalObject* globalObject = m_jit.globalObjectFor(node->origin.semantic);
7790
7791 // We set up the arguments ourselves, because we have the whole register file and we can
7792 // set them up directly into the argument registers.
7793
7794 // Arguments: 0:JSGlobalObject*, 1:structure, 2:start, 3:length, 4:callee
7795 m_jit.setupArgument(4, [&] (GPRReg destGPR) { emitGetCallee(node->origin.semantic, destGPR); });
7796 m_jit.setupArgument(3, [&] (GPRReg destGPR) { emitGetLength(node->origin.semantic, destGPR); });
7797 m_jit.setupArgument(2, [&] (GPRReg destGPR) { emitGetArgumentStart(node->origin.semantic, destGPR); });
7798 m_jit.setupArgument(
7799 1, [&] (GPRReg destGPR) {
7800 m_jit.move(
7801 TrustedImmPtr::weakPointer(
7802 m_jit.graph(), globalObject->clonedArgumentsStructure()),
7803 destGPR);
7804 });
7805 m_jit.setupArgument(0, [&] (GPRReg destGPR) { m_jit.move(TrustedImmPtr::weakPointer(m_graph, globalObject), destGPR); });
7806
7807 appendCallSetResult(operationCreateClonedArguments, resultGPR);
7808 m_jit.exceptionCheck();
7809
7810 cellResult(resultGPR, node);
7811}
7812
7813void SpeculativeJIT::compileCreateRest(Node* node)
7814{
7815 ASSERT(node->op() == CreateRest);
7816
7817 if (m_jit.graph().isWatchingHavingABadTimeWatchpoint(node)) {
7818 SpeculateStrictInt32Operand arrayLength(this, node->child1());
7819 GPRTemporary arrayResult(this);
7820
7821 GPRReg arrayLengthGPR = arrayLength.gpr();
7822 GPRReg arrayResultGPR = arrayResult.gpr();
7823
7824 // We can tell compileAllocateNewArrayWithSize() that it does not need to check
7825 // for large arrays and use ArrayStorage structure because arrayLength here will
7826 // always be bounded by stack size. Realistically, we won't be able to push enough
7827 // arguments to have arrayLength exceed MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH.
7828 bool shouldAllowForArrayStorageStructureForLargeArrays = false;
7829 compileAllocateNewArrayWithSize(m_jit.graph().globalObjectFor(node->origin.semantic), arrayResultGPR, arrayLengthGPR, ArrayWithContiguous, shouldAllowForArrayStorageStructureForLargeArrays);
7830
7831 GPRTemporary argumentsStart(this);
7832 GPRReg argumentsStartGPR = argumentsStart.gpr();
7833
7834 emitGetArgumentStart(node->origin.semantic, argumentsStartGPR);
7835
7836 GPRTemporary butterfly(this);
7837 GPRTemporary currentLength(this);
7838 JSValueRegsTemporary value(this);
7839
7840 JSValueRegs valueRegs = value.regs();
7841 GPRReg currentLengthGPR = currentLength.gpr();
7842 GPRReg butterflyGPR = butterfly.gpr();
7843
7844 m_jit.loadPtr(MacroAssembler::Address(arrayResultGPR, JSObject::butterflyOffset()), butterflyGPR);
7845
7846 CCallHelpers::Jump skipLoop = m_jit.branch32(MacroAssembler::Equal, arrayLengthGPR, TrustedImm32(0));
7847 m_jit.zeroExtend32ToPtr(arrayLengthGPR, currentLengthGPR);
7848 m_jit.addPtr(Imm32(sizeof(Register) * node->numberOfArgumentsToSkip()), argumentsStartGPR);
7849
7850 auto loop = m_jit.label();
7851 m_jit.sub32(TrustedImm32(1), currentLengthGPR);
7852 m_jit.loadValue(JITCompiler::BaseIndex(argumentsStartGPR, currentLengthGPR, MacroAssembler::TimesEight), valueRegs);
7853 m_jit.storeValue(valueRegs, MacroAssembler::BaseIndex(butterflyGPR, currentLengthGPR, MacroAssembler::TimesEight));
7854 m_jit.branch32(MacroAssembler::NotEqual, currentLengthGPR, TrustedImm32(0)).linkTo(loop, &m_jit);
7855
7856 skipLoop.link(&m_jit);
7857 cellResult(arrayResultGPR, node);
7858 return;
7859 }
7860
7861 SpeculateStrictInt32Operand arrayLength(this, node->child1());
7862 GPRTemporary argumentsStart(this);
7863 GPRTemporary numberOfArgumentsToSkip(this);
7864
7865 GPRReg arrayLengthGPR = arrayLength.gpr();
7866 GPRReg argumentsStartGPR = argumentsStart.gpr();
7867
7868 emitGetArgumentStart(node->origin.semantic, argumentsStartGPR);
7869
7870 flushRegisters();
7871
7872 GPRFlushedCallResult result(this);
7873 GPRReg resultGPR = result.gpr();
7874 callOperation(operationCreateRest, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), argumentsStartGPR, Imm32(node->numberOfArgumentsToSkip()), arrayLengthGPR);
7875 m_jit.exceptionCheck();
7876
7877 cellResult(resultGPR, node);
7878}
7879
7880void SpeculativeJIT::compileSpread(Node* node)
7881{
7882 ASSERT(node->op() == Spread);
7883
7884 SpeculateCellOperand operand(this, node->child1());
7885 GPRReg argument = operand.gpr();
7886
7887 if (node->child1().useKind() == ArrayUse)
7888 speculateArray(node->child1(), argument);
7889
7890 if (m_jit.graph().canDoFastSpread(node, m_state.forNode(node->child1()))) {
7891#if USE(JSVALUE64)
7892 GPRTemporary result(this);
7893 GPRTemporary scratch1(this);
7894 GPRTemporary scratch2(this);
7895 GPRTemporary length(this);
7896 FPRTemporary doubleRegister(this);
7897
7898 GPRReg resultGPR = result.gpr();
7899 GPRReg scratch1GPR = scratch1.gpr();
7900 GPRReg scratch2GPR = scratch2.gpr();
7901 GPRReg lengthGPR = length.gpr();
7902 FPRReg doubleFPR = doubleRegister.fpr();
7903
7904 MacroAssembler::JumpList slowPath;
7905
7906 m_jit.load8(MacroAssembler::Address(argument, JSCell::indexingTypeAndMiscOffset()), scratch1GPR);
7907 m_jit.and32(TrustedImm32(IndexingShapeMask), scratch1GPR);
7908 m_jit.sub32(TrustedImm32(Int32Shape), scratch1GPR);
7909
7910 slowPath.append(m_jit.branch32(MacroAssembler::Above, scratch1GPR, TrustedImm32(ContiguousShape - Int32Shape)));
7911
7912 m_jit.loadPtr(MacroAssembler::Address(argument, JSObject::butterflyOffset()), lengthGPR);
7913 m_jit.load32(MacroAssembler::Address(lengthGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
7914 static_assert(sizeof(JSValue) == 8 && 1 << 3 == 8, "This is strongly assumed in the code below.");
7915 m_jit.move(lengthGPR, scratch1GPR);
7916 m_jit.lshift32(TrustedImm32(3), scratch1GPR);
7917 m_jit.add32(TrustedImm32(JSFixedArray::offsetOfData()), scratch1GPR);
7918
7919 m_jit.emitAllocateVariableSizedCell<JSFixedArray>(vm(), resultGPR, TrustedImmPtr(m_jit.graph().registerStructure(m_jit.graph().m_vm.fixedArrayStructure.get())), scratch1GPR, scratch1GPR, scratch2GPR, slowPath);
7920 m_jit.store32(lengthGPR, MacroAssembler::Address(resultGPR, JSFixedArray::offsetOfSize()));
7921
7922 m_jit.loadPtr(MacroAssembler::Address(argument, JSObject::butterflyOffset()), scratch1GPR);
7923
7924 MacroAssembler::JumpList done;
7925
7926 m_jit.load8(MacroAssembler::Address(argument, JSCell::indexingTypeAndMiscOffset()), scratch2GPR);
7927 m_jit.and32(TrustedImm32(IndexingShapeMask), scratch2GPR);
7928 auto isDoubleArray = m_jit.branch32(MacroAssembler::Equal, scratch2GPR, TrustedImm32(DoubleShape));
7929
7930 {
7931 done.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR));
7932 auto loopStart = m_jit.label();
7933 m_jit.sub32(TrustedImm32(1), lengthGPR);
7934 m_jit.load64(MacroAssembler::BaseIndex(scratch1GPR, lengthGPR, MacroAssembler::TimesEight), scratch2GPR);
7935 auto notEmpty = m_jit.branchIfNotEmpty(scratch2GPR);
7936 m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), scratch2GPR);
7937 notEmpty.link(&m_jit);
7938 m_jit.store64(scratch2GPR, MacroAssembler::BaseIndex(resultGPR, lengthGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()));
7939 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loopStart, &m_jit);
7940 done.append(m_jit.jump());
7941 }
7942
7943 isDoubleArray.link(&m_jit);
7944 {
7945 done.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR));
7946 auto loopStart = m_jit.label();
7947 m_jit.sub32(TrustedImm32(1), lengthGPR);
7948 m_jit.loadDouble(MacroAssembler::BaseIndex(scratch1GPR, lengthGPR, MacroAssembler::TimesEight), doubleFPR);
7949 auto notEmpty = m_jit.branchIfNotNaN(doubleFPR);
7950 m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), scratch2GPR);
7951 auto doStore = m_jit.jump();
7952 notEmpty.link(&m_jit);
7953 m_jit.boxDouble(doubleFPR, scratch2GPR);
7954 doStore.link(&m_jit);
7955 m_jit.store64(scratch2GPR, MacroAssembler::BaseIndex(resultGPR, lengthGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()));
7956 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loopStart, &m_jit);
7957 done.append(m_jit.jump());
7958 }
7959
7960 m_jit.mutatorFence(vm());
7961
7962 slowPath.link(&m_jit);
7963 addSlowPathGenerator(slowPathCall(m_jit.jump(), this, operationSpreadFastArray, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), argument));
7964
7965 done.link(&m_jit);
7966 cellResult(resultGPR, node);
7967#else
7968 flushRegisters();
7969
7970 GPRFlushedCallResult result(this);
7971 GPRReg resultGPR = result.gpr();
7972 callOperation(operationSpreadFastArray, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), argument);
7973 m_jit.exceptionCheck();
7974 cellResult(resultGPR, node);
7975#endif // USE(JSVALUE64)
7976 } else {
7977 flushRegisters();
7978
7979 GPRFlushedCallResult result(this);
7980 GPRReg resultGPR = result.gpr();
7981 callOperation(operationSpreadGeneric, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), argument);
7982 m_jit.exceptionCheck();
7983 cellResult(resultGPR, node);
7984 }
7985}
7986
7987void SpeculativeJIT::compileNewArray(Node* node)
7988{
7989 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
7990 RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
7991 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(node->indexingType())) {
7992 unsigned numElements = node->numChildren();
7993 unsigned vectorLengthHint = node->vectorLengthHint();
7994 ASSERT(vectorLengthHint >= numElements);
7995
7996 GPRTemporary result(this);
7997 GPRTemporary storage(this);
7998
7999 GPRReg resultGPR = result.gpr();
8000 GPRReg storageGPR = storage.gpr();
8001
8002 emitAllocateRawObject(resultGPR, structure, storageGPR, numElements, vectorLengthHint);
8003
8004 // At this point, one way or another, resultGPR and storageGPR have pointers to
8005 // the JSArray and the Butterfly, respectively.
8006
8007 ASSERT(!hasUndecided(structure->indexingType()) || !node->numChildren());
8008
8009 for (unsigned operandIdx = 0; operandIdx < node->numChildren(); ++operandIdx) {
8010 Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + operandIdx];
8011 switch (node->indexingType()) {
8012 case ALL_BLANK_INDEXING_TYPES:
8013 case ALL_UNDECIDED_INDEXING_TYPES:
8014 CRASH();
8015 break;
8016 case ALL_DOUBLE_INDEXING_TYPES: {
8017 SpeculateDoubleOperand operand(this, use);
8018 FPRReg opFPR = operand.fpr();
8019 DFG_TYPE_CHECK(
8020 JSValueRegs(), use, SpecDoubleReal,
8021 m_jit.branchIfNaN(opFPR));
8022 m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx));
8023 break;
8024 }
8025 case ALL_INT32_INDEXING_TYPES:
8026 case ALL_CONTIGUOUS_INDEXING_TYPES: {
8027 JSValueOperand operand(this, use, ManualOperandSpeculation);
8028 JSValueRegs operandRegs = operand.jsValueRegs();
8029 if (hasInt32(node->indexingType())) {
8030 DFG_TYPE_CHECK(
8031 operandRegs, use, SpecInt32Only,
8032 m_jit.branchIfNotInt32(operandRegs));
8033 }
8034 m_jit.storeValue(operandRegs, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx));
8035 break;
8036 }
8037 default:
8038 CRASH();
8039 break;
8040 }
8041 }
8042
8043 // Yuck, we should *really* have a way of also returning the storageGPR. But
8044 // that's the least of what's wrong with this code. We really shouldn't be
8045 // allocating the array after having computed - and probably spilled to the
8046 // stack - all of the things that will go into the array. The solution to that
8047 // bigger problem will also likely fix the redundancy in reloading the storage
8048 // pointer that we currently have.
8049
8050 cellResult(resultGPR, node);
8051 return;
8052 }
8053
8054 if (!node->numChildren()) {
8055 flushRegisters();
8056 GPRFlushedCallResult result(this);
8057 callOperation(operationNewEmptyArray, result.gpr(), &vm(), structure);
8058 m_jit.exceptionCheck();
8059 cellResult(result.gpr(), node);
8060 return;
8061 }
8062
8063 size_t scratchSize = sizeof(EncodedJSValue) * node->numChildren();
8064 ScratchBuffer* scratchBuffer = vm().scratchBufferForSize(scratchSize);
8065 EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : nullptr;
8066
8067 for (unsigned operandIdx = 0; operandIdx < node->numChildren(); ++operandIdx) {
8068 // Need to perform the speculations that this node promises to perform. If we're
8069 // emitting code here and the indexing type is not array storage then there is
8070 // probably something hilarious going on and we're already failing at all the
8071 // things, but at least we're going to be sound.
8072 Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + operandIdx];
8073 switch (node->indexingType()) {
8074 case ALL_BLANK_INDEXING_TYPES:
8075 case ALL_UNDECIDED_INDEXING_TYPES:
8076 CRASH();
8077 break;
8078 case ALL_DOUBLE_INDEXING_TYPES: {
8079 SpeculateDoubleOperand operand(this, use);
8080 FPRReg opFPR = operand.fpr();
8081 DFG_TYPE_CHECK(
8082 JSValueRegs(), use, SpecDoubleReal,
8083 m_jit.branchIfNaN(opFPR));
8084#if USE(JSVALUE64)
8085 JSValueRegsTemporary scratch(this);
8086 JSValueRegs scratchRegs = scratch.regs();
8087 m_jit.boxDouble(opFPR, scratchRegs);
8088 m_jit.storeValue(scratchRegs, buffer + operandIdx);
8089#else
8090 m_jit.storeDouble(opFPR, TrustedImmPtr(buffer + operandIdx));
8091#endif
8092 operand.use();
8093 break;
8094 }
8095 case ALL_INT32_INDEXING_TYPES:
8096 case ALL_CONTIGUOUS_INDEXING_TYPES:
8097 case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
8098 JSValueOperand operand(this, use, ManualOperandSpeculation);
8099 JSValueRegs operandRegs = operand.jsValueRegs();
8100 if (hasInt32(node->indexingType())) {
8101 DFG_TYPE_CHECK(
8102 operandRegs, use, SpecInt32Only,
8103 m_jit.branchIfNotInt32(operandRegs));
8104 }
8105 m_jit.storeValue(operandRegs, buffer + operandIdx);
8106 operand.use();
8107 break;
8108 }
8109 default:
8110 CRASH();
8111 break;
8112 }
8113 }
8114
8115 flushRegisters();
8116
8117 if (scratchSize) {
8118 GPRTemporary scratch(this);
8119
8120 // Tell GC mark phase how much of the scratch buffer is active during call.
8121 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratch.gpr());
8122 m_jit.storePtr(TrustedImmPtr(scratchSize), scratch.gpr());
8123 }
8124
8125 GPRFlushedCallResult result(this);
8126
8127 callOperation(
8128 operationNewArray, result.gpr(), TrustedImmPtr::weakPointer(m_graph, globalObject), m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())),
8129 static_cast<void*>(buffer), size_t(node->numChildren()));
8130 m_jit.exceptionCheck();
8131
8132 if (scratchSize) {
8133 GPRTemporary scratch(this);
8134
8135 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratch.gpr());
8136 m_jit.storePtr(TrustedImmPtr(nullptr), scratch.gpr());
8137 }
8138
8139 cellResult(result.gpr(), node, UseChildrenCalledExplicitly);
8140}
8141
8142void SpeculativeJIT::compileNewArrayWithSpread(Node* node)
8143{
8144 ASSERT(node->op() == NewArrayWithSpread);
8145
8146#if USE(JSVALUE64)
8147 if (m_jit.graph().isWatchingHavingABadTimeWatchpoint(node)) {
8148 GPRTemporary result(this);
8149 GPRReg resultGPR = result.gpr();
8150
8151 BitVector* bitVector = node->bitVector();
8152 {
8153 unsigned startLength = 0;
8154 for (unsigned i = 0; i < node->numChildren(); ++i) {
8155 if (!bitVector->get(i))
8156 ++startLength;
8157 }
8158
8159 GPRTemporary length(this);
8160 GPRReg lengthGPR = length.gpr();
8161 m_jit.move(TrustedImm32(startLength), lengthGPR);
8162
8163 for (unsigned i = 0; i < node->numChildren(); ++i) {
8164 if (bitVector->get(i)) {
8165 Edge use = m_jit.graph().varArgChild(node, i);
8166 SpeculateCellOperand fixedArray(this, use);
8167 GPRReg fixedArrayGPR = fixedArray.gpr();
8168 speculationCheck(Overflow, JSValueRegs(), nullptr, m_jit.branchAdd32(MacroAssembler::Overflow, MacroAssembler::Address(fixedArrayGPR, JSFixedArray::offsetOfSize()), lengthGPR));
8169 }
8170 }
8171
8172 speculationCheck(Overflow, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::AboveOrEqual, lengthGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)));
8173
8174 // We can tell compileAllocateNewArrayWithSize() that it does not need to
8175 // check for large arrays and use ArrayStorage structure because we already
8176 // ensured above that the spread array length will definitely fit in a
8177 // non-ArrayStorage shaped array.
8178 bool shouldAllowForArrayStorageStructureForLargeArrays = false;
8179 compileAllocateNewArrayWithSize(m_jit.graph().globalObjectFor(node->origin.semantic), resultGPR, lengthGPR, ArrayWithContiguous, shouldAllowForArrayStorageStructureForLargeArrays);
8180 }
8181
8182 GPRTemporary index(this);
8183 GPRReg indexGPR = index.gpr();
8184
8185 GPRTemporary storage(this);
8186 GPRReg storageGPR = storage.gpr();
8187
8188 m_jit.move(TrustedImm32(0), indexGPR);
8189 m_jit.loadPtr(MacroAssembler::Address(resultGPR, JSObject::butterflyOffset()), storageGPR);
8190
8191 for (unsigned i = 0; i < node->numChildren(); ++i) {
8192 Edge use = m_jit.graph().varArgChild(node, i);
8193 if (bitVector->get(i)) {
8194 SpeculateCellOperand fixedArray(this, use);
8195 GPRReg fixedArrayGPR = fixedArray.gpr();
8196
8197 GPRTemporary fixedIndex(this);
8198 GPRReg fixedIndexGPR = fixedIndex.gpr();
8199
8200 GPRTemporary item(this);
8201 GPRReg itemGPR = item.gpr();
8202
8203 GPRTemporary fixedLength(this);
8204 GPRReg fixedLengthGPR = fixedLength.gpr();
8205
8206 m_jit.load32(MacroAssembler::Address(fixedArrayGPR, JSFixedArray::offsetOfSize()), fixedLengthGPR);
8207 m_jit.move(TrustedImm32(0), fixedIndexGPR);
8208 auto done = m_jit.branchPtr(MacroAssembler::AboveOrEqual, fixedIndexGPR, fixedLengthGPR);
8209 auto loopStart = m_jit.label();
8210 m_jit.load64(
8211 MacroAssembler::BaseIndex(fixedArrayGPR, fixedIndexGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()),
8212 itemGPR);
8213
8214 m_jit.store64(itemGPR, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight));
8215 m_jit.addPtr(TrustedImm32(1), fixedIndexGPR);
8216 m_jit.addPtr(TrustedImm32(1), indexGPR);
8217 m_jit.branchPtr(MacroAssembler::Below, fixedIndexGPR, fixedLengthGPR).linkTo(loopStart, &m_jit);
8218
8219 done.link(&m_jit);
8220 } else {
8221 JSValueOperand item(this, use);
8222 GPRReg itemGPR = item.gpr();
8223 m_jit.store64(itemGPR, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight));
8224 m_jit.addPtr(TrustedImm32(1), indexGPR);
8225 }
8226 }
8227
8228 cellResult(resultGPR, node);
8229 return;
8230 }
8231#endif // USE(JSVALUE64)
8232
8233 ASSERT(node->numChildren());
8234 size_t scratchSize = sizeof(EncodedJSValue) * node->numChildren();
8235 ScratchBuffer* scratchBuffer = vm().scratchBufferForSize(scratchSize);
8236 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
8237
8238 BitVector* bitVector = node->bitVector();
8239 for (unsigned i = 0; i < node->numChildren(); ++i) {
8240 Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + i];
8241 if (bitVector->get(i)) {
8242 SpeculateCellOperand fixedArray(this, use);
8243 GPRReg arrayGPR = fixedArray.gpr();
8244#if USE(JSVALUE64)
8245 m_jit.store64(arrayGPR, &buffer[i]);
8246#else
8247 char* pointer = static_cast<char*>(static_cast<void*>(&buffer[i]));
8248 m_jit.store32(arrayGPR, pointer + PayloadOffset);
8249 m_jit.store32(TrustedImm32(JSValue::CellTag), pointer + TagOffset);
8250#endif
8251 } else {
8252 JSValueOperand input(this, use);
8253 JSValueRegs inputRegs = input.jsValueRegs();
8254 m_jit.storeValue(inputRegs, &buffer[i]);
8255 }
8256 }
8257
8258 {
8259 GPRTemporary scratch(this);
8260 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratch.gpr());
8261 m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(scratch.gpr()));
8262 }
8263
8264 flushRegisters();
8265
8266 GPRFlushedCallResult result(this);
8267 GPRReg resultGPR = result.gpr();
8268
8269 callOperation(operationNewArrayWithSpreadSlow, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), buffer, node->numChildren());
8270 m_jit.exceptionCheck();
8271 {
8272 GPRTemporary scratch(this);
8273 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratch.gpr());
8274 m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(scratch.gpr()));
8275 }
8276
8277 cellResult(resultGPR, node);
8278}
8279
8280void SpeculativeJIT::compileGetRestLength(Node* node)
8281{
8282 ASSERT(node->op() == GetRestLength);
8283
8284 GPRTemporary result(this);
8285 GPRReg resultGPR = result.gpr();
8286
8287 emitGetLength(node->origin.semantic, resultGPR);
8288 CCallHelpers::Jump hasNonZeroLength = m_jit.branch32(MacroAssembler::Above, resultGPR, Imm32(node->numberOfArgumentsToSkip()));
8289 m_jit.move(TrustedImm32(0), resultGPR);
8290 CCallHelpers::Jump done = m_jit.jump();
8291 hasNonZeroLength.link(&m_jit);
8292 if (node->numberOfArgumentsToSkip())
8293 m_jit.sub32(TrustedImm32(node->numberOfArgumentsToSkip()), resultGPR);
8294 done.link(&m_jit);
8295 int32Result(resultGPR, node);
8296}
8297
8298void SpeculativeJIT::emitPopulateSliceIndex(Edge& target, Optional<GPRReg> indexGPR, GPRReg lengthGPR, GPRReg resultGPR)
8299{
8300 if (target->isInt32Constant()) {
8301 int32_t value = target->asInt32();
8302 if (value == 0) {
8303 m_jit.move(TrustedImm32(0), resultGPR);
8304 return;
8305 }
8306
8307 MacroAssembler::JumpList done;
8308 if (value > 0) {
8309 m_jit.move(TrustedImm32(value), resultGPR);
8310 done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, resultGPR, lengthGPR));
8311 m_jit.move(lengthGPR, resultGPR);
8312 } else {
8313 ASSERT(value != 0);
8314 m_jit.move(lengthGPR, resultGPR);
8315 done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, TrustedImm32(value), resultGPR));
8316 m_jit.move(TrustedImm32(0), resultGPR);
8317 }
8318 done.link(&m_jit);
8319 return;
8320 }
8321
8322 Optional<SpeculateInt32Operand> index;
8323 if (!indexGPR) {
8324 index.emplace(this, target);
8325 indexGPR = index->gpr();
8326 }
8327 MacroAssembler::JumpList done;
8328
8329 auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR.value(), TrustedImm32(0));
8330 m_jit.move(lengthGPR, resultGPR);
8331 done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR.value(), resultGPR));
8332 m_jit.move(TrustedImm32(0), resultGPR);
8333 done.append(m_jit.jump());
8334
8335 isPositive.link(&m_jit);
8336 m_jit.move(indexGPR.value(), resultGPR);
8337 done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, resultGPR, lengthGPR));
8338 m_jit.move(lengthGPR, resultGPR);
8339
8340 done.link(&m_jit);
8341}
8342
8343void SpeculativeJIT::compileArraySlice(Node* node)
8344{
8345 ASSERT(node->op() == ArraySlice);
8346
8347 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
8348
8349 GPRTemporary temp(this);
8350 StorageOperand storage(this, m_jit.graph().varArgChild(node, node->numChildren() - 1));
8351 GPRTemporary result(this);
8352
8353 GPRReg storageGPR = storage.gpr();
8354 GPRReg resultGPR = result.gpr();
8355 GPRReg tempGPR = temp.gpr();
8356
8357 if (node->numChildren() == 2)
8358 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempGPR);
8359 else {
8360 ASSERT(node->numChildren() == 3 || node->numChildren() == 4);
8361 GPRTemporary tempLength(this);
8362 GPRReg lengthGPR = tempLength.gpr();
8363 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
8364
8365 if (node->numChildren() == 4)
8366 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, lengthGPR, tempGPR);
8367 else
8368 m_jit.move(lengthGPR, tempGPR);
8369
8370 if (m_jit.graph().varArgChild(node, 1)->isInt32Constant() && m_jit.graph().varArgChild(node, 1)->asInt32() == 0) {
8371 // Do nothing for array.slice(0, end) or array.slice(0) cases.
8372 // `tempGPR` already points to the size of a newly created array.
8373 } else {
8374 GPRTemporary tempStartIndex(this);
8375 GPRReg startGPR = tempStartIndex.gpr();
8376 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), WTF::nullopt, lengthGPR, startGPR);
8377
8378 auto tooBig = m_jit.branch32(MacroAssembler::Above, startGPR, tempGPR);
8379 m_jit.sub32(startGPR, tempGPR); // the size of the array we'll make.
8380 auto done = m_jit.jump();
8381
8382 tooBig.link(&m_jit);
8383 m_jit.move(TrustedImm32(0), tempGPR);
8384 done.link(&m_jit);
8385 }
8386 }
8387
8388 GPRTemporary temp3(this);
8389 GPRReg tempValue = temp3.gpr();
8390
8391 {
8392 // We need to keep the source array alive at least until after we're done
8393 // with anything that can GC (e.g. allocating the result array below).
8394 SpeculateCellOperand cell(this, m_jit.graph().varArgChild(node, 0));
8395
8396 m_jit.load8(MacroAssembler::Address(cell.gpr(), JSCell::indexingTypeAndMiscOffset()), tempValue);
8397 // We can ignore the writability of the cell since we won't write to the source.
8398 m_jit.and32(TrustedImm32(AllWritableArrayTypesAndHistory), tempValue);
8399
8400 JSValueRegsTemporary emptyValue(this);
8401 JSValueRegs emptyValueRegs = emptyValue.regs();
8402
8403 GPRTemporary storage(this);
8404 GPRReg storageResultGPR = storage.gpr();
8405
8406 GPRReg sizeGPR = tempGPR;
8407
8408 CCallHelpers::JumpList done;
8409
8410 auto emitMoveEmptyValue = [&] (JSValue v) {
8411 m_jit.moveValue(v, emptyValueRegs);
8412 };
8413
8414 auto isContiguous = m_jit.branch32(MacroAssembler::Equal, tempValue, TrustedImm32(ArrayWithContiguous));
8415 auto isInt32 = m_jit.branch32(MacroAssembler::Equal, tempValue, TrustedImm32(ArrayWithInt32));
8416 // When we emit an ArraySlice, we dominate the use of the array by a CheckStructure
8417 // to ensure the incoming array is one to be one of the original array structures
8418 // with one of the following indexing shapes: Int32, Contiguous, Double. Therefore,
8419 // we're a double array here.
8420 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithDouble))), tempValue);
8421 emitMoveEmptyValue(jsNaN());
8422 done.append(m_jit.jump());
8423
8424 isContiguous.link(&m_jit);
8425 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous))), tempValue);
8426 emitMoveEmptyValue(JSValue());
8427 done.append(m_jit.jump());
8428
8429 isInt32.link(&m_jit);
8430 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithInt32))), tempValue);
8431 emitMoveEmptyValue(JSValue());
8432
8433 done.link(&m_jit);
8434
8435 MacroAssembler::JumpList slowCases;
8436 m_jit.move(TrustedImmPtr(nullptr), storageResultGPR);
8437 // Enable the fast case on 64-bit platforms, where a sufficient amount of GP registers should be available.
8438 // Other platforms could support the same approach with custom code, but that is not currently worth the extra code maintenance.
8439 if (is64Bit()) {
8440 GPRTemporary scratch(this);
8441 GPRTemporary scratch2(this);
8442 GPRReg scratchGPR = scratch.gpr();
8443 GPRReg scratch2GPR = scratch2.gpr();
8444
8445 emitAllocateButterfly(storageResultGPR, sizeGPR, scratchGPR, scratch2GPR, resultGPR, slowCases);
8446 emitInitializeButterfly(storageResultGPR, sizeGPR, emptyValueRegs, scratchGPR);
8447 emitAllocateJSObject<JSArray>(resultGPR, tempValue, storageResultGPR, scratchGPR, scratch2GPR, slowCases);
8448 m_jit.mutatorFence(vm());
8449 } else {
8450 slowCases.append(m_jit.jump());
8451 }
8452
8453 addSlowPathGenerator(makeUnique<CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator>(
8454 slowCases, this, operationNewArrayWithSize, resultGPR, TrustedImmPtr::weakPointer(m_graph, globalObject), tempValue, sizeGPR, storageResultGPR));
8455 }
8456
8457 GPRTemporary temp4(this);
8458 GPRReg loadIndex = temp4.gpr();
8459
8460 if (node->numChildren() == 2) {
8461 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempGPR);
8462 m_jit.move(TrustedImm32(0), loadIndex);
8463 } else {
8464 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempValue);
8465 if (node->numChildren() == 4)
8466 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, tempValue, tempGPR);
8467 else
8468 m_jit.move(tempValue, tempGPR);
8469 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), WTF::nullopt, tempValue, loadIndex);
8470 }
8471
8472 GPRTemporary temp5(this);
8473 GPRReg storeIndex = temp5.gpr();
8474 m_jit.move(TrustedImmPtr(nullptr), storeIndex);
8475
8476 GPRTemporary temp2(this);
8477 GPRReg resultButterfly = temp2.gpr();
8478
8479 m_jit.loadPtr(MacroAssembler::Address(resultGPR, JSObject::butterflyOffset()), resultButterfly);
8480 m_jit.zeroExtend32ToPtr(tempGPR, tempGPR);
8481 m_jit.zeroExtend32ToPtr(loadIndex, loadIndex);
8482 auto done = m_jit.branchPtr(MacroAssembler::AboveOrEqual, loadIndex, tempGPR);
8483
8484 auto loop = m_jit.label();
8485#if USE(JSVALUE64)
8486 m_jit.load64(
8487 MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight), tempValue);
8488 m_jit.store64(
8489 tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight));
8490#else
8491 m_jit.load32(
8492 MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight, PayloadOffset), tempValue);
8493 m_jit.store32(
8494 tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight, PayloadOffset));
8495 m_jit.load32(
8496 MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight, TagOffset), tempValue);
8497 m_jit.store32(
8498 tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight, TagOffset));
8499#endif // USE(JSVALUE64)
8500 m_jit.addPtr(TrustedImm32(1), loadIndex);
8501 m_jit.addPtr(TrustedImm32(1), storeIndex);
8502 m_jit.branchPtr(MacroAssembler::Below, loadIndex, tempGPR).linkTo(loop, &m_jit);
8503
8504 done.link(&m_jit);
8505 cellResult(resultGPR, node);
8506}
8507
8508void SpeculativeJIT::compileArrayIndexOf(Node* node)
8509{
8510 ASSERT(node->op() == ArrayIndexOf);
8511
8512 StorageOperand storage(this, m_jit.graph().varArgChild(node, node->numChildren() == 3 ? 2 : 3));
8513 GPRTemporary index(this);
8514 GPRTemporary tempLength(this);
8515
8516 GPRReg storageGPR = storage.gpr();
8517 GPRReg indexGPR = index.gpr();
8518 GPRReg lengthGPR = tempLength.gpr();
8519
8520 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
8521
8522 if (node->numChildren() == 4)
8523 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, lengthGPR, indexGPR);
8524 else
8525 m_jit.move(TrustedImm32(0), indexGPR);
8526
8527 Edge& searchElementEdge = m_jit.graph().varArgChild(node, 1);
8528 switch (searchElementEdge.useKind()) {
8529 case Int32Use:
8530 case ObjectUse:
8531 case SymbolUse:
8532 case OtherUse: {
8533 auto emitLoop = [&] (auto emitCompare) {
8534#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
8535 m_jit.clearRegisterAllocationOffsets();
8536#endif
8537
8538 m_jit.zeroExtend32ToPtr(lengthGPR, lengthGPR);
8539 m_jit.zeroExtend32ToPtr(indexGPR, indexGPR);
8540
8541 auto loop = m_jit.label();
8542 auto notFound = m_jit.branch32(CCallHelpers::Equal, indexGPR, lengthGPR);
8543
8544 auto found = emitCompare();
8545
8546 m_jit.add32(TrustedImm32(1), indexGPR);
8547 m_jit.jump().linkTo(loop, &m_jit);
8548
8549 notFound.link(&m_jit);
8550 m_jit.move(TrustedImm32(-1), indexGPR);
8551 found.link(&m_jit);
8552 int32Result(indexGPR, node);
8553 };
8554
8555 if (searchElementEdge.useKind() == Int32Use) {
8556 ASSERT(node->arrayMode().type() == Array::Int32);
8557#if USE(JSVALUE64)
8558 JSValueOperand searchElement(this, searchElementEdge, ManualOperandSpeculation);
8559 JSValueRegs searchElementRegs = searchElement.jsValueRegs();
8560 speculateInt32(searchElementEdge, searchElementRegs);
8561 GPRReg searchElementGPR = searchElementRegs.payloadGPR();
8562#else
8563 SpeculateInt32Operand searchElement(this, searchElementEdge);
8564 GPRReg searchElementGPR = searchElement.gpr();
8565
8566 GPRTemporary temp(this);
8567 GPRReg tempGPR = temp.gpr();
8568#endif
8569 emitLoop([&] () {
8570#if USE(JSVALUE64)
8571 auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementGPR);
8572#else
8573 auto skip = m_jit.branch32(CCallHelpers::NotEqual, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), TrustedImm32(JSValue::Int32Tag));
8574 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, PayloadOffset), tempGPR);
8575 auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementGPR);
8576 skip.link(&m_jit);
8577#endif
8578 return found;
8579 });
8580 return;
8581 }
8582
8583 if (searchElementEdge.useKind() == OtherUse) {
8584 ASSERT(node->arrayMode().type() == Array::Contiguous);
8585 JSValueOperand searchElement(this, searchElementEdge, ManualOperandSpeculation);
8586 GPRTemporary temp(this);
8587
8588 JSValueRegs searchElementRegs = searchElement.jsValueRegs();
8589 GPRReg tempGPR = temp.gpr();
8590 speculateOther(searchElementEdge, searchElementRegs, tempGPR);
8591
8592 emitLoop([&] () {
8593#if USE(JSVALUE64)
8594 auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementRegs.payloadGPR());
8595#else
8596 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), tempGPR);
8597 auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementRegs.tagGPR());
8598#endif
8599 return found;
8600 });
8601 return;
8602 }
8603
8604 ASSERT(node->arrayMode().type() == Array::Contiguous);
8605 SpeculateCellOperand searchElement(this, searchElementEdge);
8606 GPRReg searchElementGPR = searchElement.gpr();
8607
8608 if (searchElementEdge.useKind() == ObjectUse)
8609 speculateObject(searchElementEdge, searchElementGPR);
8610 else {
8611 ASSERT(searchElementEdge.useKind() == SymbolUse);
8612 speculateSymbol(searchElementEdge, searchElementGPR);
8613 }
8614
8615#if USE(JSVALUE32_64)
8616 GPRTemporary temp(this);
8617 GPRReg tempGPR = temp.gpr();
8618#endif
8619
8620 emitLoop([&] () {
8621#if USE(JSVALUE64)
8622 auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementGPR);
8623#else
8624 auto skip = m_jit.branch32(CCallHelpers::NotEqual, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), TrustedImm32(JSValue::CellTag));
8625 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, PayloadOffset), tempGPR);
8626 auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementGPR);
8627 skip.link(&m_jit);
8628#endif
8629 return found;
8630 });
8631 return;
8632 }
8633
8634 case DoubleRepUse: {
8635 ASSERT(node->arrayMode().type() == Array::Double);
8636 SpeculateDoubleOperand searchElement(this, searchElementEdge);
8637 FPRTemporary tempDouble(this);
8638
8639 FPRReg searchElementFPR = searchElement.fpr();
8640 FPRReg tempFPR = tempDouble.fpr();
8641
8642#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
8643 m_jit.clearRegisterAllocationOffsets();
8644#endif
8645
8646 m_jit.zeroExtend32ToPtr(lengthGPR, lengthGPR);
8647 m_jit.zeroExtend32ToPtr(indexGPR, indexGPR);
8648
8649 auto loop = m_jit.label();
8650 auto notFound = m_jit.branch32(CCallHelpers::Equal, indexGPR, lengthGPR);
8651 m_jit.loadDouble(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), tempFPR);
8652 auto found = m_jit.branchDouble(CCallHelpers::DoubleEqual, tempFPR, searchElementFPR);
8653 m_jit.add32(TrustedImm32(1), indexGPR);
8654 m_jit.jump().linkTo(loop, &m_jit);
8655
8656 notFound.link(&m_jit);
8657 m_jit.move(TrustedImm32(-1), indexGPR);
8658 found.link(&m_jit);
8659 int32Result(indexGPR, node);
8660 return;
8661 }
8662
8663 case StringUse: {
8664 ASSERT(node->arrayMode().type() == Array::Contiguous);
8665 SpeculateCellOperand searchElement(this, searchElementEdge);
8666
8667 GPRReg searchElementGPR = searchElement.gpr();
8668
8669 speculateString(searchElementEdge, searchElementGPR);
8670
8671 flushRegisters();
8672
8673 callOperation(operationArrayIndexOfString, lengthGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), storageGPR, searchElementGPR, indexGPR);
8674 m_jit.exceptionCheck();
8675
8676 int32Result(lengthGPR, node);
8677 return;
8678 }
8679
8680 case UntypedUse: {
8681 JSValueOperand searchElement(this, searchElementEdge);
8682
8683 JSValueRegs searchElementRegs = searchElement.jsValueRegs();
8684
8685 flushRegisters();
8686 switch (node->arrayMode().type()) {
8687 case Array::Double:
8688 callOperation(operationArrayIndexOfValueDouble, lengthGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), storageGPR, searchElementRegs, indexGPR);
8689 break;
8690 case Array::Int32:
8691 case Array::Contiguous:
8692 callOperation(operationArrayIndexOfValueInt32OrContiguous, lengthGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), storageGPR, searchElementRegs, indexGPR);
8693 break;
8694 default:
8695 RELEASE_ASSERT_NOT_REACHED();
8696 break;
8697 }
8698 m_jit.exceptionCheck();
8699
8700 int32Result(lengthGPR, node);
8701 return;
8702 }
8703
8704 default:
8705 RELEASE_ASSERT_NOT_REACHED();
8706 return;
8707 }
8708}
8709
8710void SpeculativeJIT::compileArrayPush(Node* node)
8711{
8712 ASSERT(node->arrayMode().isJSArray());
8713
8714 Edge& storageEdge = m_jit.graph().varArgChild(node, 0);
8715 Edge& arrayEdge = m_jit.graph().varArgChild(node, 1);
8716
8717 SpeculateCellOperand base(this, arrayEdge);
8718 GPRTemporary storageLength(this);
8719
8720 GPRReg baseGPR = base.gpr();
8721 GPRReg storageLengthGPR = storageLength.gpr();
8722
8723 StorageOperand storage(this, storageEdge);
8724 GPRReg storageGPR = storage.gpr();
8725 unsigned elementOffset = 2;
8726 unsigned elementCount = node->numChildren() - elementOffset;
8727
8728#if USE(JSVALUE32_64)
8729 GPRTemporary tag(this);
8730 GPRReg tagGPR = tag.gpr();
8731 JSValueRegs resultRegs { tagGPR, storageLengthGPR };
8732#else
8733 JSValueRegs resultRegs { storageLengthGPR };
8734#endif
8735
8736 auto getStorageBufferAddress = [&] (GPRReg storageGPR, GPRReg indexGPR, int32_t offset, GPRReg bufferGPR) {
8737 static_assert(sizeof(JSValue) == 8 && 1 << 3 == 8, "This is strongly assumed in the code below.");
8738 m_jit.getEffectiveAddress(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, offset), bufferGPR);
8739 };
8740
8741 switch (node->arrayMode().type()) {
8742 case Array::Int32:
8743 case Array::Contiguous: {
8744 if (elementCount == 1) {
8745 Edge& element = m_jit.graph().varArgChild(node, elementOffset);
8746 if (node->arrayMode().type() == Array::Int32) {
8747 ASSERT(element.useKind() == Int32Use);
8748 speculateInt32(element);
8749 }
8750 JSValueOperand value(this, element, ManualOperandSpeculation);
8751 JSValueRegs valueRegs = value.jsValueRegs();
8752
8753 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
8754 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
8755 m_jit.storeValue(valueRegs, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
8756 m_jit.add32(TrustedImm32(1), storageLengthGPR);
8757 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
8758 m_jit.boxInt32(storageLengthGPR, resultRegs);
8759
8760 addSlowPathGenerator(
8761 slowPathCall(slowPath, this, operationArrayPush, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueRegs, baseGPR));
8762
8763 jsValueResult(resultRegs, node);
8764 return;
8765 }
8766
8767 if (node->arrayMode().type() == Array::Int32) {
8768 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8769 Edge element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8770 ASSERT(element.useKind() == Int32Use);
8771 speculateInt32(element);
8772 }
8773 }
8774
8775 GPRTemporary buffer(this);
8776 GPRReg bufferGPR = buffer.gpr();
8777
8778 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
8779 m_jit.move(storageLengthGPR, bufferGPR);
8780 m_jit.add32(TrustedImm32(elementCount), bufferGPR);
8781 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::Above, bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
8782
8783 m_jit.store32(bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
8784 getStorageBufferAddress(storageGPR, storageLengthGPR, 0, bufferGPR);
8785 m_jit.add32(TrustedImm32(elementCount), storageLengthGPR);
8786 m_jit.boxInt32(storageLengthGPR, resultRegs);
8787 auto storageDone = m_jit.jump();
8788
8789 slowPath.link(&m_jit);
8790
8791 size_t scratchSize = sizeof(EncodedJSValue) * elementCount;
8792 ScratchBuffer* scratchBuffer = vm().scratchBufferForSize(scratchSize);
8793 m_jit.move(TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())), bufferGPR);
8794 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), storageLengthGPR);
8795 m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(storageLengthGPR));
8796
8797 storageDone.link(&m_jit);
8798 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8799 Edge& element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8800 JSValueOperand value(this, element, ManualOperandSpeculation); // We did type checks above.
8801 JSValueRegs valueRegs = value.jsValueRegs();
8802
8803 m_jit.storeValue(valueRegs, MacroAssembler::Address(bufferGPR, sizeof(EncodedJSValue) * elementIndex));
8804 value.use();
8805 }
8806
8807 MacroAssembler::Jump fastPath = m_jit.branchPtr(MacroAssembler::NotEqual, bufferGPR, TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
8808
8809 addSlowPathGenerator(slowPathCall(m_jit.jump(), this, operationArrayPushMultiple, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, bufferGPR, TrustedImm32(elementCount)));
8810
8811 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), bufferGPR);
8812 m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(bufferGPR));
8813
8814 base.use();
8815 storage.use();
8816
8817 fastPath.link(&m_jit);
8818 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
8819 return;
8820 }
8821
8822 case Array::Double: {
8823 if (elementCount == 1) {
8824 Edge& element = m_jit.graph().varArgChild(node, elementOffset);
8825 speculate(node, element);
8826 SpeculateDoubleOperand value(this, element);
8827 FPRReg valueFPR = value.fpr();
8828
8829 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
8830 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
8831 m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
8832 m_jit.add32(TrustedImm32(1), storageLengthGPR);
8833 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
8834 m_jit.boxInt32(storageLengthGPR, resultRegs);
8835
8836 addSlowPathGenerator(
8837 slowPathCall(slowPath, this, operationArrayPushDouble, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueFPR, baseGPR));
8838
8839 jsValueResult(resultRegs, node);
8840 return;
8841 }
8842
8843 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8844 Edge element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8845 ASSERT(element.useKind() == DoubleRepRealUse);
8846 speculate(node, element);
8847 }
8848
8849 GPRTemporary buffer(this);
8850 GPRReg bufferGPR = buffer.gpr();
8851
8852 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
8853 m_jit.move(storageLengthGPR, bufferGPR);
8854 m_jit.add32(TrustedImm32(elementCount), bufferGPR);
8855 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::Above, bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
8856
8857 m_jit.store32(bufferGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
8858 getStorageBufferAddress(storageGPR, storageLengthGPR, 0, bufferGPR);
8859 m_jit.add32(TrustedImm32(elementCount), storageLengthGPR);
8860 m_jit.boxInt32(storageLengthGPR, resultRegs);
8861 auto storageDone = m_jit.jump();
8862
8863 slowPath.link(&m_jit);
8864
8865 size_t scratchSize = sizeof(double) * elementCount;
8866 ScratchBuffer* scratchBuffer = vm().scratchBufferForSize(scratchSize);
8867 m_jit.move(TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())), bufferGPR);
8868 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), storageLengthGPR);
8869 m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(storageLengthGPR));
8870
8871 storageDone.link(&m_jit);
8872 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8873 Edge& element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8874 SpeculateDoubleOperand value(this, element);
8875 FPRReg valueFPR = value.fpr();
8876
8877 m_jit.storeDouble(valueFPR, MacroAssembler::Address(bufferGPR, sizeof(double) * elementIndex));
8878 value.use();
8879 }
8880
8881 MacroAssembler::Jump fastPath = m_jit.branchPtr(MacroAssembler::NotEqual, bufferGPR, TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
8882
8883 addSlowPathGenerator(slowPathCall(m_jit.jump(), this, operationArrayPushDoubleMultiple, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, bufferGPR, TrustedImm32(elementCount)));
8884
8885 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), bufferGPR);
8886 m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(bufferGPR));
8887
8888 base.use();
8889 storage.use();
8890
8891 fastPath.link(&m_jit);
8892 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
8893 return;
8894 }
8895
8896 case Array::ArrayStorage: {
8897 // This ensures that the result of ArrayPush is Int32 in AI.
8898 int32_t largestPositiveInt32Length = 0x7fffffff - elementCount;
8899 if (elementCount == 1) {
8900 Edge& element = m_jit.graph().varArgChild(node, elementOffset);
8901 JSValueOperand value(this, element);
8902 JSValueRegs valueRegs = value.jsValueRegs();
8903
8904 m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
8905
8906 // Refuse to handle bizarre lengths.
8907 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(largestPositiveInt32Length)));
8908
8909 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
8910
8911 m_jit.storeValue(valueRegs, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()));
8912
8913 m_jit.add32(TrustedImm32(1), storageLengthGPR);
8914 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
8915 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
8916 m_jit.boxInt32(storageLengthGPR, resultRegs);
8917
8918 addSlowPathGenerator(
8919 slowPathCall(slowPath, this, operationArrayPush, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueRegs, baseGPR));
8920
8921 jsValueResult(resultRegs, node);
8922 return;
8923 }
8924
8925 GPRTemporary buffer(this);
8926 GPRReg bufferGPR = buffer.gpr();
8927
8928 m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
8929
8930 // Refuse to handle bizarre lengths.
8931 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(largestPositiveInt32Length)));
8932
8933 m_jit.move(storageLengthGPR, bufferGPR);
8934 m_jit.add32(TrustedImm32(elementCount), bufferGPR);
8935 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::Above, bufferGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
8936
8937 m_jit.store32(bufferGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
8938 getStorageBufferAddress(storageGPR, storageLengthGPR, ArrayStorage::vectorOffset(), bufferGPR);
8939 m_jit.add32(TrustedImm32(elementCount), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
8940 m_jit.add32(TrustedImm32(elementCount), storageLengthGPR);
8941 m_jit.boxInt32(storageLengthGPR, resultRegs);
8942 auto storageDone = m_jit.jump();
8943
8944 slowPath.link(&m_jit);
8945
8946 size_t scratchSize = sizeof(EncodedJSValue) * elementCount;
8947 ScratchBuffer* scratchBuffer = vm().scratchBufferForSize(scratchSize);
8948 m_jit.move(TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())), bufferGPR);
8949 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), storageLengthGPR);
8950 m_jit.storePtr(TrustedImmPtr(scratchSize), MacroAssembler::Address(storageLengthGPR));
8951
8952 storageDone.link(&m_jit);
8953 for (unsigned elementIndex = 0; elementIndex < elementCount; ++elementIndex) {
8954 Edge& element = m_jit.graph().varArgChild(node, elementIndex + elementOffset);
8955 JSValueOperand value(this, element);
8956 JSValueRegs valueRegs = value.jsValueRegs();
8957
8958 m_jit.storeValue(valueRegs, MacroAssembler::Address(bufferGPR, sizeof(EncodedJSValue) * elementIndex));
8959 value.use();
8960 }
8961
8962 MacroAssembler::Jump fastPath = m_jit.branchPtr(MacroAssembler::NotEqual, bufferGPR, TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer())));
8963
8964 addSlowPathGenerator(
8965 slowPathCall(m_jit.jump(), this, operationArrayPushMultiple, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, bufferGPR, TrustedImm32(elementCount)));
8966
8967 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), bufferGPR);
8968 m_jit.storePtr(TrustedImmPtr(nullptr), MacroAssembler::Address(bufferGPR));
8969
8970 base.use();
8971 storage.use();
8972
8973 fastPath.link(&m_jit);
8974 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
8975 return;
8976 }
8977
8978 default:
8979 RELEASE_ASSERT_NOT_REACHED();
8980 }
8981}
8982
8983void SpeculativeJIT::compileNotifyWrite(Node* node)
8984{
8985 WatchpointSet* set = node->watchpointSet();
8986
8987 JITCompiler::Jump slowCase = m_jit.branch8(
8988 JITCompiler::NotEqual,
8989 JITCompiler::AbsoluteAddress(set->addressOfState()),
8990 TrustedImm32(IsInvalidated));
8991
8992 addSlowPathGenerator(
8993 slowPathCall(slowCase, this, operationNotifyWrite, NeedToSpill, ExceptionCheckRequirement::CheckNotNeeded, NoResult, &vm(), set));
8994
8995 noResult(node);
8996}
8997
8998void SpeculativeJIT::compileIsObject(Node* node)
8999{
9000 JSValueOperand value(this, node->child1());
9001 GPRTemporary result(this, Reuse, value, TagWord);
9002
9003 JSValueRegs valueRegs = value.jsValueRegs();
9004 GPRReg resultGPR = result.gpr();
9005
9006 JITCompiler::Jump isNotCell = m_jit.branchIfNotCell(valueRegs);
9007
9008 m_jit.compare8(JITCompiler::AboveOrEqual,
9009 JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoTypeOffset()),
9010 TrustedImm32(ObjectType),
9011 resultGPR);
9012 JITCompiler::Jump done = m_jit.jump();
9013
9014 isNotCell.link(&m_jit);
9015 m_jit.move(TrustedImm32(0), resultGPR);
9016
9017 done.link(&m_jit);
9018 unblessedBooleanResult(resultGPR, node);
9019}
9020
9021void SpeculativeJIT::compileIsObjectOrNull(Node* node)
9022{
9023 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
9024
9025 JSValueOperand value(this, node->child1());
9026 JSValueRegs valueRegs = value.jsValueRegs();
9027
9028 GPRTemporary result(this);
9029 GPRReg resultGPR = result.gpr();
9030
9031 JITCompiler::Jump isCell = m_jit.branchIfCell(valueRegs);
9032
9033 JITCompiler::Jump isNull = m_jit.branchIfEqual(valueRegs, jsNull());
9034 JITCompiler::Jump isNonNullNonCell = m_jit.jump();
9035
9036 isCell.link(&m_jit);
9037 JITCompiler::Jump isFunction = m_jit.branchIfFunction(valueRegs.payloadGPR());
9038 JITCompiler::Jump notObject = m_jit.branchIfNotObject(valueRegs.payloadGPR());
9039
9040 JITCompiler::Jump slowPath = m_jit.branchTest8(
9041 JITCompiler::NonZero,
9042 JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoFlagsOffset()),
9043 TrustedImm32(MasqueradesAsUndefined | OverridesGetCallData));
9044
9045 isNull.link(&m_jit);
9046 m_jit.move(TrustedImm32(1), resultGPR);
9047 JITCompiler::Jump done = m_jit.jump();
9048
9049 isNonNullNonCell.link(&m_jit);
9050 isFunction.link(&m_jit);
9051 notObject.link(&m_jit);
9052 m_jit.move(TrustedImm32(0), resultGPR);
9053
9054 addSlowPathGenerator(
9055 slowPathCall(
9056 slowPath, this, operationObjectIsObject, resultGPR, globalObject,
9057 valueRegs.payloadGPR()));
9058
9059 done.link(&m_jit);
9060
9061 unblessedBooleanResult(resultGPR, node);
9062}
9063
9064void SpeculativeJIT::compileIsFunction(Node* node)
9065{
9066 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
9067
9068 JSValueOperand value(this, node->child1());
9069 JSValueRegs valueRegs = value.jsValueRegs();
9070
9071 GPRTemporary result(this);
9072 GPRReg resultGPR = result.gpr();
9073
9074 JITCompiler::Jump notCell = m_jit.branchIfNotCell(valueRegs);
9075 JITCompiler::Jump isFunction = m_jit.branchIfFunction(valueRegs.payloadGPR());
9076 JITCompiler::Jump notObject = m_jit.branchIfNotObject(valueRegs.payloadGPR());
9077
9078 JITCompiler::Jump slowPath = m_jit.branchTest8(
9079 JITCompiler::NonZero,
9080 JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoFlagsOffset()),
9081 TrustedImm32(MasqueradesAsUndefined | OverridesGetCallData));
9082
9083 notCell.link(&m_jit);
9084 notObject.link(&m_jit);
9085 m_jit.move(TrustedImm32(0), resultGPR);
9086 JITCompiler::Jump done = m_jit.jump();
9087
9088 isFunction.link(&m_jit);
9089 m_jit.move(TrustedImm32(1), resultGPR);
9090
9091 addSlowPathGenerator(
9092 slowPathCall(
9093 slowPath, this, operationObjectIsFunction, resultGPR, globalObject,
9094 valueRegs.payloadGPR()));
9095
9096 done.link(&m_jit);
9097
9098 unblessedBooleanResult(resultGPR, node);
9099}
9100
9101void SpeculativeJIT::compileTypeOf(Node* node)
9102{
9103 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
9104
9105 JSValueOperand value(this, node->child1());
9106 JSValueRegs valueRegs = value.jsValueRegs();
9107
9108 GPRTemporary result(this);
9109 GPRReg resultGPR = result.gpr();
9110
9111 JITCompiler::JumpList done;
9112 JITCompiler::Jump slowPath;
9113 m_jit.emitTypeOf(
9114 valueRegs, resultGPR,
9115 [&] (TypeofType type, bool fallsThrough) {
9116 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), vm().smallStrings.typeString(type)), resultGPR);
9117 if (!fallsThrough)
9118 done.append(m_jit.jump());
9119 },
9120 [&] (JITCompiler::Jump theSlowPath) {
9121 slowPath = theSlowPath;
9122 });
9123 done.link(&m_jit);
9124
9125 addSlowPathGenerator(
9126 slowPathCall(
9127 slowPath, this, operationTypeOfObject, resultGPR, globalObject,
9128 valueRegs.payloadGPR()));
9129
9130 cellResult(resultGPR, node);
9131}
9132
9133void SpeculativeJIT::emitStructureCheck(Node* node, GPRReg cellGPR, GPRReg tempGPR)
9134{
9135 ASSERT(node->structureSet().size());
9136
9137 if (node->structureSet().size() == 1) {
9138 speculationCheck(
9139 BadCache, JSValueSource::unboxedCell(cellGPR), 0,
9140 m_jit.branchWeakStructure(
9141 JITCompiler::NotEqual,
9142 JITCompiler::Address(cellGPR, JSCell::structureIDOffset()),
9143 node->structureSet()[0]));
9144 } else {
9145 std::unique_ptr<GPRTemporary> structure;
9146 GPRReg structureGPR;
9147
9148 if (tempGPR == InvalidGPRReg) {
9149 structure = makeUnique<GPRTemporary>(this);
9150 structureGPR = structure->gpr();
9151 } else
9152 structureGPR = tempGPR;
9153
9154 m_jit.load32(JITCompiler::Address(cellGPR, JSCell::structureIDOffset()), structureGPR);
9155
9156 JITCompiler::JumpList done;
9157
9158 for (size_t i = 0; i < node->structureSet().size() - 1; ++i) {
9159 done.append(
9160 m_jit.branchWeakStructure(JITCompiler::Equal, structureGPR, node->structureSet()[i]));
9161 }
9162
9163 speculationCheck(
9164 BadCache, JSValueSource::unboxedCell(cellGPR), 0,
9165 m_jit.branchWeakStructure(
9166 JITCompiler::NotEqual, structureGPR, node->structureSet().last()));
9167
9168 done.link(&m_jit);
9169 }
9170}
9171
9172void SpeculativeJIT::compileCheckCell(Node* node)
9173{
9174 SpeculateCellOperand cell(this, node->child1());
9175 speculationCheck(BadCell, JSValueSource::unboxedCell(cell.gpr()), node->child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, cell.gpr(), node->cellOperand()->cell()));
9176 noResult(node);
9177}
9178
9179void SpeculativeJIT::compileCheckNotEmpty(Node* node)
9180{
9181 JSValueOperand operand(this, node->child1());
9182 JSValueRegs regs = operand.jsValueRegs();
9183 speculationCheck(TDZFailure, JSValueSource(), nullptr, m_jit.branchIfEmpty(regs));
9184 noResult(node);
9185}
9186
9187void SpeculativeJIT::compileCheckStructure(Node* node)
9188{
9189 switch (node->child1().useKind()) {
9190 case CellUse:
9191 case KnownCellUse: {
9192 SpeculateCellOperand cell(this, node->child1());
9193 emitStructureCheck(node, cell.gpr(), InvalidGPRReg);
9194 noResult(node);
9195 return;
9196 }
9197
9198 case CellOrOtherUse: {
9199 JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
9200 GPRTemporary temp(this);
9201
9202 JSValueRegs valueRegs = value.jsValueRegs();
9203 GPRReg tempGPR = temp.gpr();
9204
9205 JITCompiler::Jump cell = m_jit.branchIfCell(valueRegs);
9206 DFG_TYPE_CHECK(
9207 valueRegs, node->child1(), SpecCell | SpecOther,
9208 m_jit.branchIfNotOther(valueRegs, tempGPR));
9209 JITCompiler::Jump done = m_jit.jump();
9210 cell.link(&m_jit);
9211 emitStructureCheck(node, valueRegs.payloadGPR(), tempGPR);
9212 done.link(&m_jit);
9213 noResult(node);
9214 return;
9215 }
9216
9217 default:
9218 DFG_CRASH(m_jit.graph(), node, "Bad use kind");
9219 return;
9220 }
9221}
9222
9223void SpeculativeJIT::compileAllocatePropertyStorage(Node* node)
9224{
9225 ASSERT(!node->transition()->previous->outOfLineCapacity());
9226 ASSERT(initialOutOfLineCapacity == node->transition()->next->outOfLineCapacity());
9227
9228 size_t size = initialOutOfLineCapacity * sizeof(JSValue);
9229
9230 Allocator allocator = vm().jsValueGigacageAuxiliarySpace.allocatorForNonVirtual(size, AllocatorForMode::AllocatorIfExists);
9231
9232 if (!allocator || node->transition()->previous->couldHaveIndexingHeader()) {
9233 SpeculateCellOperand base(this, node->child1());
9234
9235 GPRReg baseGPR = base.gpr();
9236
9237 flushRegisters();
9238
9239 GPRFlushedCallResult result(this);
9240 callOperation(operationAllocateComplexPropertyStorageWithInitialCapacity, result.gpr(), &vm(), baseGPR);
9241 m_jit.exceptionCheck();
9242
9243 storageResult(result.gpr(), node);
9244 return;
9245 }
9246
9247 GPRTemporary scratch1(this);
9248 GPRTemporary scratch2(this);
9249 GPRTemporary scratch3(this);
9250
9251 GPRReg scratchGPR1 = scratch1.gpr();
9252 GPRReg scratchGPR2 = scratch2.gpr();
9253 GPRReg scratchGPR3 = scratch3.gpr();
9254
9255 JITCompiler::JumpList slowPath;
9256 m_jit.emitAllocate(scratchGPR1, JITAllocator::constant(allocator), scratchGPR2, scratchGPR3, slowPath);
9257 m_jit.addPtr(JITCompiler::TrustedImm32(size + sizeof(IndexingHeader)), scratchGPR1);
9258
9259 addSlowPathGenerator(
9260 slowPathCall(slowPath, this, operationAllocateSimplePropertyStorageWithInitialCapacity, scratchGPR1, &vm()));
9261
9262 for (ptrdiff_t offset = 0; offset < static_cast<ptrdiff_t>(size); offset += sizeof(void*))
9263 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratchGPR1, -(offset + sizeof(JSValue) + sizeof(void*))));
9264
9265 storageResult(scratchGPR1, node);
9266}
9267
9268void SpeculativeJIT::compileReallocatePropertyStorage(Node* node)
9269{
9270 size_t oldSize = node->transition()->previous->outOfLineCapacity() * sizeof(JSValue);
9271 size_t newSize = oldSize * outOfLineGrowthFactor;
9272 ASSERT(newSize == node->transition()->next->outOfLineCapacity() * sizeof(JSValue));
9273
9274 Allocator allocator = vm().jsValueGigacageAuxiliarySpace.allocatorForNonVirtual(newSize, AllocatorForMode::AllocatorIfExists);
9275
9276 if (!allocator || node->transition()->previous->couldHaveIndexingHeader()) {
9277 SpeculateCellOperand base(this, node->child1());
9278
9279 GPRReg baseGPR = base.gpr();
9280
9281 flushRegisters();
9282
9283 GPRFlushedCallResult result(this);
9284 callOperation(operationAllocateComplexPropertyStorage, result.gpr(), &vm(), baseGPR, newSize / sizeof(JSValue));
9285 m_jit.exceptionCheck();
9286
9287 storageResult(result.gpr(), node);
9288 return;
9289 }
9290
9291 StorageOperand oldStorage(this, node->child2());
9292 GPRTemporary scratch1(this);
9293 GPRTemporary scratch2(this);
9294 GPRTemporary scratch3(this);
9295
9296 GPRReg oldStorageGPR = oldStorage.gpr();
9297 GPRReg scratchGPR1 = scratch1.gpr();
9298 GPRReg scratchGPR2 = scratch2.gpr();
9299 GPRReg scratchGPR3 = scratch3.gpr();
9300
9301 JITCompiler::JumpList slowPath;
9302 m_jit.emitAllocate(scratchGPR1, JITAllocator::constant(allocator), scratchGPR2, scratchGPR3, slowPath);
9303
9304 m_jit.addPtr(JITCompiler::TrustedImm32(newSize + sizeof(IndexingHeader)), scratchGPR1);
9305
9306 addSlowPathGenerator(
9307 slowPathCall(slowPath, this, operationAllocateSimplePropertyStorage, scratchGPR1, &vm(), newSize / sizeof(JSValue)));
9308
9309 for (ptrdiff_t offset = oldSize; offset < static_cast<ptrdiff_t>(newSize); offset += sizeof(void*))
9310 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratchGPR1, -(offset + sizeof(JSValue) + sizeof(void*))));
9311
9312 // We have scratchGPR1 = new storage, scratchGPR2 = scratch
9313 for (ptrdiff_t offset = 0; offset < static_cast<ptrdiff_t>(oldSize); offset += sizeof(void*)) {
9314 m_jit.loadPtr(JITCompiler::Address(oldStorageGPR, -(offset + sizeof(JSValue) + sizeof(void*))), scratchGPR2);
9315 m_jit.storePtr(scratchGPR2, JITCompiler::Address(scratchGPR1, -(offset + sizeof(JSValue) + sizeof(void*))));
9316 }
9317
9318 storageResult(scratchGPR1, node);
9319}
9320
9321void SpeculativeJIT::compileNukeStructureAndSetButterfly(Node* node)
9322{
9323 SpeculateCellOperand base(this, node->child1());
9324 StorageOperand storage(this, node->child2());
9325
9326 GPRReg baseGPR = base.gpr();
9327 GPRReg storageGPR = storage.gpr();
9328
9329 m_jit.nukeStructureAndStoreButterfly(vm(), storageGPR, baseGPR);
9330
9331 noResult(node);
9332}
9333
9334void SpeculativeJIT::compileGetButterfly(Node* node)
9335{
9336 SpeculateCellOperand base(this, node->child1());
9337 GPRTemporary result(this, Reuse, base);
9338
9339 GPRReg baseGPR = base.gpr();
9340 GPRReg resultGPR = result.gpr();
9341
9342 m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::butterflyOffset()), resultGPR);
9343
9344 storageResult(resultGPR, node);
9345}
9346
9347static void allocateTemporaryRegistersForSnippet(SpeculativeJIT* jit, Vector<GPRTemporary>& gpHolders, Vector<FPRTemporary>& fpHolders, Vector<GPRReg>& gpScratch, Vector<FPRReg>& fpScratch, Snippet& snippet)
9348{
9349 for (unsigned i = 0; i < snippet.numGPScratchRegisters; ++i) {
9350 GPRTemporary temporary(jit);
9351 gpScratch.append(temporary.gpr());
9352 gpHolders.append(WTFMove(temporary));
9353 }
9354
9355 for (unsigned i = 0; i < snippet.numFPScratchRegisters; ++i) {
9356 FPRTemporary temporary(jit);
9357 fpScratch.append(temporary.fpr());
9358 fpHolders.append(WTFMove(temporary));
9359 }
9360}
9361
9362void SpeculativeJIT::compileCallDOM(Node* node)
9363{
9364 const DOMJIT::Signature* signature = node->signature();
9365
9366 // FIXME: We should have a way to call functions with the vector of registers.
9367 // https://bugs.webkit.org/show_bug.cgi?id=163099
9368 Vector<Variant<SpeculateCellOperand, SpeculateInt32Operand, SpeculateBooleanOperand>, JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS_INCLUDING_THIS> operands;
9369 Vector<GPRReg, JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS_INCLUDING_THIS> regs;
9370
9371 auto appendCell = [&](Edge& edge) {
9372 SpeculateCellOperand operand(this, edge);
9373 regs.append(operand.gpr());
9374 operands.append(WTFMove(operand));
9375 };
9376
9377 auto appendString = [&](Edge& edge) {
9378 SpeculateCellOperand operand(this, edge);
9379 GPRReg gpr = operand.gpr();
9380 regs.append(gpr);
9381 speculateString(edge, gpr);
9382 operands.append(WTFMove(operand));
9383 };
9384
9385 auto appendInt32 = [&](Edge& edge) {
9386 SpeculateInt32Operand operand(this, edge);
9387 regs.append(operand.gpr());
9388 operands.append(WTFMove(operand));
9389 };
9390
9391 auto appendBoolean = [&](Edge& edge) {
9392 SpeculateBooleanOperand operand(this, edge);
9393 regs.append(operand.gpr());
9394 operands.append(WTFMove(operand));
9395 };
9396
9397 unsigned index = 0;
9398 m_jit.graph().doToChildren(node, [&](Edge edge) {
9399 if (!index)
9400 appendCell(edge);
9401 else {
9402 switch (signature->arguments[index - 1]) {
9403 case SpecString:
9404 appendString(edge);
9405 break;
9406 case SpecInt32Only:
9407 appendInt32(edge);
9408 break;
9409 case SpecBoolean:
9410 appendBoolean(edge);
9411 break;
9412 default:
9413 RELEASE_ASSERT_NOT_REACHED();
9414 break;
9415 }
9416 }
9417 ++index;
9418 });
9419
9420 JSValueRegsTemporary result(this);
9421 JSValueRegs resultRegs = result.regs();
9422
9423 flushRegisters();
9424
9425 // FIXME: Revisit JSGlobalObject.
9426 // https://bugs.webkit.org/show_bug.cgi?id=203204
9427 auto function = CFunctionPtr(signature->functionWithoutTypeCheck);
9428 unsigned argumentCountIncludingThis = signature->argumentCount + 1;
9429 switch (argumentCountIncludingThis) {
9430 case 1:
9431 callOperation(reinterpret_cast<J_JITOperation_GP>(function.get()), extractResult(resultRegs), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), regs[0]);
9432 break;
9433 case 2:
9434 callOperation(reinterpret_cast<J_JITOperation_GPP>(function.get()), extractResult(resultRegs), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), regs[0], regs[1]);
9435 break;
9436 case 3:
9437 callOperation(reinterpret_cast<J_JITOperation_GPPP>(function.get()), extractResult(resultRegs), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), regs[0], regs[1], regs[2]);
9438 break;
9439 default:
9440 RELEASE_ASSERT_NOT_REACHED();
9441 break;
9442 }
9443
9444 m_jit.exceptionCheck();
9445 jsValueResult(resultRegs, node);
9446}
9447
9448void SpeculativeJIT::compileCallDOMGetter(Node* node)
9449{
9450 DOMJIT::CallDOMGetterSnippet* snippet = node->callDOMGetterData()->snippet;
9451 if (!snippet) {
9452 FunctionPtr<OperationPtrTag> getter = node->callDOMGetterData()->customAccessorGetter;
9453 SpeculateCellOperand base(this, node->child1());
9454 JSValueRegsTemporary result(this);
9455
9456 JSValueRegs resultRegs = result.regs();
9457 GPRReg baseGPR = base.gpr();
9458
9459 flushRegisters();
9460 m_jit.setupArguments<J_JITOperation_GJI>(TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), CCallHelpers::CellValue(baseGPR), identifierUID(node->callDOMGetterData()->identifierNumber));
9461 m_jit.storePtr(GPRInfo::callFrameRegister, &vm().topCallFrame);
9462 m_jit.emitStoreCodeOrigin(m_currentNode->origin.semantic);
9463 m_jit.appendCall(getter.retagged<CFunctionPtrTag>());
9464 m_jit.setupResults(resultRegs);
9465
9466 m_jit.exceptionCheck();
9467 jsValueResult(resultRegs, node);
9468 return;
9469 }
9470
9471 Vector<GPRReg> gpScratch;
9472 Vector<FPRReg> fpScratch;
9473 Vector<SnippetParams::Value> regs;
9474
9475 JSValueRegsTemporary result(this);
9476 regs.append(result.regs());
9477
9478 Edge& baseEdge = node->child1();
9479 SpeculateCellOperand base(this, baseEdge);
9480 regs.append(SnippetParams::Value(base.gpr(), m_state.forNode(baseEdge).value()));
9481
9482 Optional<SpeculateCellOperand> globalObject;
9483 if (snippet->requireGlobalObject) {
9484 Edge& globalObjectEdge = node->child2();
9485 globalObject.emplace(this, globalObjectEdge);
9486 regs.append(SnippetParams::Value(globalObject->gpr(), m_state.forNode(globalObjectEdge).value()));
9487 }
9488
9489 Vector<GPRTemporary> gpTempraries;
9490 Vector<FPRTemporary> fpTempraries;
9491 allocateTemporaryRegistersForSnippet(this, gpTempraries, fpTempraries, gpScratch, fpScratch, *snippet);
9492 SnippetParams params(this, WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
9493 snippet->generator()->run(m_jit, params);
9494 jsValueResult(result.regs(), node);
9495}
9496
9497void SpeculativeJIT::compileCheckSubClass(Node* node)
9498{
9499 const ClassInfo* classInfo = node->classInfo();
9500 if (!classInfo->checkSubClassSnippet) {
9501 SpeculateCellOperand base(this, node->child1());
9502 GPRTemporary other(this);
9503 GPRTemporary specified(this);
9504
9505 GPRReg baseGPR = base.gpr();
9506 GPRReg otherGPR = other.gpr();
9507 GPRReg specifiedGPR = specified.gpr();
9508
9509 m_jit.emitLoadStructure(vm(), baseGPR, otherGPR, specifiedGPR);
9510 m_jit.loadPtr(CCallHelpers::Address(otherGPR, Structure::classInfoOffset()), otherGPR);
9511 m_jit.move(CCallHelpers::TrustedImmPtr(node->classInfo()), specifiedGPR);
9512
9513 CCallHelpers::Label loop = m_jit.label();
9514 auto done = m_jit.branchPtr(CCallHelpers::Equal, otherGPR, specifiedGPR);
9515 m_jit.loadPtr(CCallHelpers::Address(otherGPR, ClassInfo::offsetOfParentClass()), otherGPR);
9516 m_jit.branchTestPtr(CCallHelpers::NonZero, otherGPR).linkTo(loop, &m_jit);
9517 speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node->child1(), m_jit.jump());
9518 done.link(&m_jit);
9519 noResult(node);
9520 return;
9521 }
9522
9523 Ref<Snippet> snippet = classInfo->checkSubClassSnippet();
9524
9525 Vector<GPRReg> gpScratch;
9526 Vector<FPRReg> fpScratch;
9527 Vector<SnippetParams::Value> regs;
9528
9529 SpeculateCellOperand base(this, node->child1());
9530 GPRReg baseGPR = base.gpr();
9531 regs.append(SnippetParams::Value(baseGPR, m_state.forNode(node->child1()).value()));
9532
9533 Vector<GPRTemporary> gpTempraries;
9534 Vector<FPRTemporary> fpTempraries;
9535 allocateTemporaryRegistersForSnippet(this, gpTempraries, fpTempraries, gpScratch, fpScratch, snippet.get());
9536
9537 SnippetParams params(this, WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
9538 CCallHelpers::JumpList failureCases = snippet->generator()->run(m_jit, params);
9539 speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node->child1(), failureCases);
9540 noResult(node);
9541}
9542
9543GPRReg SpeculativeJIT::temporaryRegisterForPutByVal(GPRTemporary& temporary, ArrayMode arrayMode)
9544{
9545 if (!putByValWillNeedExtraRegister(arrayMode))
9546 return InvalidGPRReg;
9547
9548 GPRTemporary realTemporary(this);
9549 temporary.adopt(realTemporary);
9550 return temporary.gpr();
9551}
9552
9553void SpeculativeJIT::compileToStringOrCallStringConstructorOrStringValueOf(Node* node)
9554{
9555 ASSERT(node->op() != StringValueOf || node->child1().useKind() == UntypedUse);
9556 switch (node->child1().useKind()) {
9557 case NotCellUse: {
9558 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
9559 JSValueRegs op1Regs = op1.jsValueRegs();
9560
9561 GPRFlushedCallResult result(this);
9562 GPRReg resultGPR = result.gpr();
9563
9564 speculateNotCell(node->child1(), op1Regs);
9565
9566 flushRegisters();
9567
9568 if (node->op() == ToString)
9569 callOperation(operationToString, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs);
9570 else {
9571 ASSERT(node->op() == CallStringConstructor);
9572 callOperation(operationCallStringConstructor, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs);
9573 }
9574 m_jit.exceptionCheck();
9575 cellResult(resultGPR, node);
9576 return;
9577 }
9578
9579 case UntypedUse: {
9580 JSValueOperand op1(this, node->child1());
9581 JSValueRegs op1Regs = op1.jsValueRegs();
9582 GPRReg op1PayloadGPR = op1Regs.payloadGPR();
9583
9584 GPRFlushedCallResult result(this);
9585 GPRReg resultGPR = result.gpr();
9586
9587 flushRegisters();
9588
9589 JITCompiler::Jump done;
9590 if (node->child1()->prediction() & SpecString) {
9591 JITCompiler::Jump slowPath1 = m_jit.branchIfNotCell(op1.jsValueRegs());
9592 JITCompiler::Jump slowPath2 = m_jit.branchIfNotString(op1PayloadGPR);
9593 m_jit.move(op1PayloadGPR, resultGPR);
9594 done = m_jit.jump();
9595 slowPath1.link(&m_jit);
9596 slowPath2.link(&m_jit);
9597 }
9598 if (node->op() == ToString)
9599 callOperation(operationToString, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs);
9600 else if (node->op() == StringValueOf)
9601 callOperation(operationStringValueOf, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs);
9602 else {
9603 ASSERT(node->op() == CallStringConstructor);
9604 callOperation(operationCallStringConstructor, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs);
9605 }
9606 m_jit.exceptionCheck();
9607 if (done.isSet())
9608 done.link(&m_jit);
9609 cellResult(resultGPR, node);
9610 return;
9611 }
9612
9613 case Int32Use:
9614 case Int52RepUse:
9615 case DoubleRepUse:
9616 compileNumberToStringWithValidRadixConstant(node, 10);
9617 return;
9618
9619 default:
9620 break;
9621 }
9622
9623 SpeculateCellOperand op1(this, node->child1());
9624 GPRReg op1GPR = op1.gpr();
9625
9626 switch (node->child1().useKind()) {
9627 case StringObjectUse: {
9628 GPRTemporary result(this);
9629 GPRReg resultGPR = result.gpr();
9630
9631 speculateStringObject(node->child1(), op1GPR);
9632
9633 m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR);
9634 cellResult(resultGPR, node);
9635 break;
9636 }
9637
9638 case StringOrStringObjectUse: {
9639 GPRTemporary result(this);
9640 GPRReg resultGPR = result.gpr();
9641
9642 m_jit.load8(JITCompiler::Address(op1GPR, JSCell::typeInfoTypeOffset()), resultGPR);
9643 JITCompiler::Jump isString = m_jit.branch32(JITCompiler::Equal, resultGPR, TrustedImm32(StringType));
9644
9645 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1().node(), m_jit.branch32(JITCompiler::NotEqual, resultGPR, TrustedImm32(StringObjectType)));
9646 m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR);
9647 JITCompiler::Jump done = m_jit.jump();
9648
9649 isString.link(&m_jit);
9650 m_jit.move(op1GPR, resultGPR);
9651 done.link(&m_jit);
9652
9653 m_interpreter.filter(node->child1(), SpecString | SpecStringObject);
9654
9655 cellResult(resultGPR, node);
9656 break;
9657 }
9658
9659 case CellUse: {
9660 GPRFlushedCallResult result(this);
9661 GPRReg resultGPR = result.gpr();
9662
9663 // We flush registers instead of silent spill/fill because in this mode we
9664 // believe that most likely the input is not a string, and we need to take
9665 // slow path.
9666 flushRegisters();
9667 JITCompiler::Jump done;
9668 if (node->child1()->prediction() & SpecString) {
9669 JITCompiler::Jump needCall = m_jit.branchIfNotString(op1GPR);
9670 m_jit.move(op1GPR, resultGPR);
9671 done = m_jit.jump();
9672 needCall.link(&m_jit);
9673 }
9674 if (node->op() == ToString)
9675 callOperation(operationToStringOnCell, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1GPR);
9676 else {
9677 ASSERT(node->op() == CallStringConstructor);
9678 callOperation(operationCallStringConstructorOnCell, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1GPR);
9679 }
9680 m_jit.exceptionCheck();
9681 if (done.isSet())
9682 done.link(&m_jit);
9683 cellResult(resultGPR, node);
9684 break;
9685 }
9686
9687 default:
9688 RELEASE_ASSERT_NOT_REACHED();
9689 }
9690}
9691
9692void SpeculativeJIT::compileNumberToStringWithValidRadixConstant(Node* node)
9693{
9694 compileNumberToStringWithValidRadixConstant(node, node->validRadixConstant());
9695}
9696
9697void SpeculativeJIT::compileNumberToStringWithValidRadixConstant(Node* node, int32_t radix)
9698{
9699 auto callToString = [&] (auto operation, GPRReg resultGPR, auto valueReg) {
9700 flushRegisters();
9701 callOperation(operation, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueReg, TrustedImm32(radix));
9702 m_jit.exceptionCheck();
9703 cellResult(resultGPR, node);
9704 };
9705
9706 switch (node->child1().useKind()) {
9707 case Int32Use: {
9708 SpeculateStrictInt32Operand value(this, node->child1());
9709 GPRFlushedCallResult result(this);
9710 callToString(operationInt32ToStringWithValidRadix, result.gpr(), value.gpr());
9711 break;
9712 }
9713
9714#if USE(JSVALUE64)
9715 case Int52RepUse: {
9716 SpeculateStrictInt52Operand value(this, node->child1());
9717 GPRFlushedCallResult result(this);
9718 callToString(operationInt52ToStringWithValidRadix, result.gpr(), value.gpr());
9719 break;
9720 }
9721#endif
9722
9723 case DoubleRepUse: {
9724 SpeculateDoubleOperand value(this, node->child1());
9725 GPRFlushedCallResult result(this);
9726 callToString(operationDoubleToStringWithValidRadix, result.gpr(), value.fpr());
9727 break;
9728 }
9729
9730 default:
9731 RELEASE_ASSERT_NOT_REACHED();
9732 }
9733}
9734
9735void SpeculativeJIT::compileNumberToStringWithRadix(Node* node)
9736{
9737 bool validRadixIsGuaranteed = false;
9738 if (node->child2()->isInt32Constant()) {
9739 int32_t radix = node->child2()->asInt32();
9740 if (radix >= 2 && radix <= 36)
9741 validRadixIsGuaranteed = true;
9742 }
9743
9744 auto callToString = [&] (auto operation, GPRReg resultGPR, auto valueReg, GPRReg radixGPR) {
9745 flushRegisters();
9746 callOperation(operation, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueReg, radixGPR);
9747 m_jit.exceptionCheck();
9748 cellResult(resultGPR, node);
9749 };
9750
9751 switch (node->child1().useKind()) {
9752 case Int32Use: {
9753 SpeculateStrictInt32Operand value(this, node->child1());
9754 SpeculateStrictInt32Operand radix(this, node->child2());
9755 GPRFlushedCallResult result(this);
9756 callToString(validRadixIsGuaranteed ? operationInt32ToStringWithValidRadix : operationInt32ToString, result.gpr(), value.gpr(), radix.gpr());
9757 break;
9758 }
9759
9760#if USE(JSVALUE64)
9761 case Int52RepUse: {
9762 SpeculateStrictInt52Operand value(this, node->child1());
9763 SpeculateStrictInt32Operand radix(this, node->child2());
9764 GPRFlushedCallResult result(this);
9765 callToString(validRadixIsGuaranteed ? operationInt52ToStringWithValidRadix : operationInt52ToString, result.gpr(), value.gpr(), radix.gpr());
9766 break;
9767 }
9768#endif
9769
9770 case DoubleRepUse: {
9771 SpeculateDoubleOperand value(this, node->child1());
9772 SpeculateStrictInt32Operand radix(this, node->child2());
9773 GPRFlushedCallResult result(this);
9774 callToString(validRadixIsGuaranteed ? operationDoubleToStringWithValidRadix : operationDoubleToString, result.gpr(), value.fpr(), radix.gpr());
9775 break;
9776 }
9777
9778 default:
9779 RELEASE_ASSERT_NOT_REACHED();
9780 }
9781}
9782
9783void SpeculativeJIT::compileNewStringObject(Node* node)
9784{
9785 SpeculateCellOperand operand(this, node->child1());
9786
9787 GPRTemporary result(this);
9788 GPRTemporary scratch1(this);
9789 GPRTemporary scratch2(this);
9790
9791 GPRReg operandGPR = operand.gpr();
9792 GPRReg resultGPR = result.gpr();
9793 GPRReg scratch1GPR = scratch1.gpr();
9794 GPRReg scratch2GPR = scratch2.gpr();
9795
9796 JITCompiler::JumpList slowPath;
9797
9798 auto butterfly = TrustedImmPtr(nullptr);
9799 emitAllocateJSObject<StringObject>(
9800 resultGPR, TrustedImmPtr(node->structure()), butterfly, scratch1GPR, scratch2GPR,
9801 slowPath);
9802
9803 m_jit.storePtr(
9804 TrustedImmPtr(StringObject::info()),
9805 JITCompiler::Address(resultGPR, JSDestructibleObject::classInfoOffset()));
9806#if USE(JSVALUE64)
9807 m_jit.store64(
9808 operandGPR, JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset()));
9809#else
9810 m_jit.store32(
9811 TrustedImm32(JSValue::CellTag),
9812 JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
9813 m_jit.store32(
9814 operandGPR,
9815 JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
9816#endif
9817
9818 m_jit.mutatorFence(vm());
9819
9820 addSlowPathGenerator(slowPathCall(
9821 slowPath, this, operationNewStringObject, resultGPR, &vm(), operandGPR, node->structure()));
9822
9823 cellResult(resultGPR, node);
9824}
9825
9826void SpeculativeJIT::compileNewSymbol(Node* node)
9827{
9828 if (!node->child1()) {
9829 flushRegisters();
9830 GPRFlushedCallResult result(this);
9831 GPRReg resultGPR = result.gpr();
9832 callOperation(operationNewSymbol, resultGPR, &vm());
9833 m_jit.exceptionCheck();
9834 cellResult(resultGPR, node);
9835 return;
9836 }
9837
9838
9839 ASSERT(node->child1().useKind() == KnownStringUse);
9840 SpeculateCellOperand operand(this, node->child1());
9841
9842 GPRReg stringGPR = operand.gpr();
9843
9844 flushRegisters();
9845 GPRFlushedCallResult result(this);
9846 GPRReg resultGPR = result.gpr();
9847 callOperation(operationNewSymbolWithDescription, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), stringGPR);
9848 m_jit.exceptionCheck();
9849 cellResult(resultGPR, node);
9850}
9851
9852void SpeculativeJIT::compileNewTypedArrayWithSize(Node* node)
9853{
9854 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
9855 auto typedArrayType = node->typedArrayType();
9856 RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->typedArrayStructureConcurrently(typedArrayType));
9857 RELEASE_ASSERT(structure.get());
9858
9859 SpeculateInt32Operand size(this, node->child1());
9860 GPRReg sizeGPR = size.gpr();
9861
9862 GPRTemporary result(this);
9863 GPRTemporary storage(this);
9864 GPRTemporary scratch(this);
9865 GPRTemporary scratch2(this);
9866 GPRReg resultGPR = result.gpr();
9867 GPRReg storageGPR = storage.gpr();
9868 GPRReg scratchGPR = scratch.gpr();
9869 GPRReg scratchGPR2 = scratch2.gpr();
9870
9871 JITCompiler::JumpList slowCases;
9872
9873 m_jit.move(TrustedImmPtr(nullptr), storageGPR);
9874
9875 slowCases.append(m_jit.branch32(
9876 MacroAssembler::Above, sizeGPR, TrustedImm32(JSArrayBufferView::fastSizeLimit)));
9877
9878 m_jit.move(sizeGPR, scratchGPR);
9879 m_jit.lshift32(TrustedImm32(logElementSize(typedArrayType)), scratchGPR);
9880 if (elementSize(typedArrayType) < 8) {
9881 m_jit.add32(TrustedImm32(7), scratchGPR);
9882 m_jit.and32(TrustedImm32(~7), scratchGPR);
9883 }
9884 m_jit.emitAllocateVariableSized(
9885 storageGPR, vm().primitiveGigacageAuxiliarySpace, scratchGPR, scratchGPR,
9886 scratchGPR2, slowCases);
9887
9888 MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, sizeGPR);
9889 m_jit.move(sizeGPR, scratchGPR);
9890 if (elementSize(typedArrayType) != 4) {
9891 if (elementSize(typedArrayType) > 4)
9892 m_jit.lshift32(TrustedImm32(logElementSize(typedArrayType) - 2), scratchGPR);
9893 else {
9894 if (elementSize(typedArrayType) > 1)
9895 m_jit.lshift32(TrustedImm32(logElementSize(typedArrayType)), scratchGPR);
9896 m_jit.add32(TrustedImm32(3), scratchGPR);
9897 m_jit.urshift32(TrustedImm32(2), scratchGPR);
9898 }
9899 }
9900 MacroAssembler::Label loop = m_jit.label();
9901 m_jit.sub32(TrustedImm32(1), scratchGPR);
9902 m_jit.store32(
9903 TrustedImm32(0),
9904 MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesFour));
9905 m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
9906 done.link(&m_jit);
9907#if CPU(ARM64E)
9908 // sizeGPR is still boxed as a number and there is no 32-bit variant of the PAC instructions.
9909 m_jit.zeroExtend32ToPtr(sizeGPR, scratchGPR);
9910 m_jit.tagArrayPtr(scratchGPR, storageGPR);
9911#endif
9912
9913 auto butterfly = TrustedImmPtr(nullptr);
9914 emitAllocateJSObject<JSArrayBufferView>(
9915 resultGPR, TrustedImmPtr(structure), butterfly, scratchGPR, scratchGPR2,
9916 slowCases);
9917
9918 m_jit.storePtr(
9919 storageGPR,
9920 MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfVector()));
9921 m_jit.store32(
9922 sizeGPR,
9923 MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfLength()));
9924 m_jit.store32(
9925 TrustedImm32(FastTypedArray),
9926 MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfMode()));
9927
9928 m_jit.mutatorFence(vm());
9929
9930 addSlowPathGenerator(slowPathCall(
9931 slowCases, this, operationNewTypedArrayWithSizeForType(typedArrayType),
9932 resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), structure, sizeGPR, storageGPR));
9933
9934 cellResult(resultGPR, node);
9935}
9936
9937void SpeculativeJIT::compileNewRegexp(Node* node)
9938{
9939 RegExp* regexp = node->castOperand<RegExp*>();
9940
9941 GPRTemporary result(this);
9942 GPRTemporary scratch1(this);
9943 GPRTemporary scratch2(this);
9944 JSValueOperand lastIndex(this, node->child1());
9945
9946 GPRReg resultGPR = result.gpr();
9947 GPRReg scratch1GPR = scratch1.gpr();
9948 GPRReg scratch2GPR = scratch2.gpr();
9949 JSValueRegs lastIndexRegs = lastIndex.jsValueRegs();
9950
9951 JITCompiler::JumpList slowPath;
9952
9953 auto structure = m_jit.graph().registerStructure(m_jit.graph().globalObjectFor(node->origin.semantic)->regExpStructure());
9954 auto butterfly = TrustedImmPtr(nullptr);
9955 emitAllocateJSObject<RegExpObject>(resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR, slowPath);
9956
9957 m_jit.storePtr(
9958 TrustedImmPtr(node->cellOperand()),
9959 CCallHelpers::Address(resultGPR, RegExpObject::offsetOfRegExpAndLastIndexIsNotWritableFlag()));
9960 m_jit.storeValue(lastIndexRegs, CCallHelpers::Address(resultGPR, RegExpObject::offsetOfLastIndex()));
9961 m_jit.mutatorFence(vm());
9962
9963 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewRegexpWithLastIndex, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), regexp, lastIndexRegs));
9964
9965 cellResult(resultGPR, node);
9966}
9967
9968void SpeculativeJIT::speculateCellTypeWithoutTypeFiltering(
9969 Edge edge, GPRReg cellGPR, JSType jsType)
9970{
9971 speculationCheck(
9972 BadType, JSValueSource::unboxedCell(cellGPR), edge,
9973 m_jit.branchIfNotType(cellGPR, jsType));
9974}
9975
9976void SpeculativeJIT::speculateCellType(
9977 Edge edge, GPRReg cellGPR, SpeculatedType specType, JSType jsType)
9978{
9979 DFG_TYPE_CHECK(
9980 JSValueSource::unboxedCell(cellGPR), edge, specType,
9981 m_jit.branchIfNotType(cellGPR, jsType));
9982}
9983
9984void SpeculativeJIT::speculateInt32(Edge edge)
9985{
9986 if (!needsTypeCheck(edge, SpecInt32Only))
9987 return;
9988
9989 (SpeculateInt32Operand(this, edge)).gpr();
9990}
9991
9992void SpeculativeJIT::speculateNumber(Edge edge)
9993{
9994 if (!needsTypeCheck(edge, SpecBytecodeNumber))
9995 return;
9996
9997 JSValueOperand value(this, edge, ManualOperandSpeculation);
9998#if USE(JSVALUE64)
9999 GPRReg gpr = value.gpr();
10000 typeCheck(
10001 JSValueRegs(gpr), edge, SpecBytecodeNumber,
10002 m_jit.branchIfNotNumber(gpr));
10003#else
10004 IGNORE_WARNINGS_BEGIN("enum-compare")
10005 static_assert(JSValue::Int32Tag >= JSValue::LowestTag, "Int32Tag is included in >= JSValue::LowestTag range.");
10006 IGNORE_WARNINGS_END
10007 GPRReg tagGPR = value.tagGPR();
10008 DFG_TYPE_CHECK(
10009 value.jsValueRegs(), edge, ~SpecInt32Only,
10010 m_jit.branchIfInt32(tagGPR));
10011 DFG_TYPE_CHECK(
10012 value.jsValueRegs(), edge, SpecBytecodeNumber,
10013 m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag)));
10014#endif
10015}
10016
10017void SpeculativeJIT::speculateRealNumber(Edge edge)
10018{
10019 if (!needsTypeCheck(edge, SpecBytecodeRealNumber))
10020 return;
10021
10022 JSValueOperand op1(this, edge, ManualOperandSpeculation);
10023 FPRTemporary result(this);
10024
10025 JSValueRegs op1Regs = op1.jsValueRegs();
10026 FPRReg resultFPR = result.fpr();
10027
10028#if USE(JSVALUE64)
10029 GPRTemporary temp(this);
10030 GPRReg tempGPR = temp.gpr();
10031 m_jit.unboxDoubleWithoutAssertions(op1Regs.gpr(), tempGPR, resultFPR);
10032#else
10033 FPRTemporary temp(this);
10034 FPRReg tempFPR = temp.fpr();
10035 unboxDouble(op1Regs.tagGPR(), op1Regs.payloadGPR(), resultFPR, tempFPR);
10036#endif
10037
10038 JITCompiler::Jump done = m_jit.branchIfNotNaN(resultFPR);
10039
10040 typeCheck(op1Regs, edge, SpecBytecodeRealNumber, m_jit.branchIfNotInt32(op1Regs));
10041
10042 done.link(&m_jit);
10043}
10044
10045void SpeculativeJIT::speculateDoubleRepReal(Edge edge)
10046{
10047 if (!needsTypeCheck(edge, SpecDoubleReal))
10048 return;
10049
10050 SpeculateDoubleOperand operand(this, edge);
10051 FPRReg fpr = operand.fpr();
10052 typeCheck(
10053 JSValueRegs(), edge, SpecDoubleReal,
10054 m_jit.branchIfNaN(fpr));
10055}
10056
10057void SpeculativeJIT::speculateBoolean(Edge edge)
10058{
10059 if (!needsTypeCheck(edge, SpecBoolean))
10060 return;
10061
10062 (SpeculateBooleanOperand(this, edge)).gpr();
10063}
10064
10065void SpeculativeJIT::speculateCell(Edge edge)
10066{
10067 if (!needsTypeCheck(edge, SpecCellCheck))
10068 return;
10069
10070 (SpeculateCellOperand(this, edge)).gpr();
10071}
10072
10073void SpeculativeJIT::speculateCellOrOther(Edge edge)
10074{
10075 if (!needsTypeCheck(edge, SpecCellCheck | SpecOther))
10076 return;
10077
10078 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10079 GPRTemporary temp(this);
10080 GPRReg tempGPR = temp.gpr();
10081
10082 MacroAssembler::Jump ok = m_jit.branchIfCell(operand.jsValueRegs());
10083 DFG_TYPE_CHECK(
10084 operand.jsValueRegs(), edge, SpecCellCheck | SpecOther,
10085 m_jit.branchIfNotOther(operand.jsValueRegs(), tempGPR));
10086 ok.link(&m_jit);
10087}
10088
10089void SpeculativeJIT::speculateObject(Edge edge, GPRReg cell)
10090{
10091 DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, SpecObject, m_jit.branchIfNotObject(cell));
10092}
10093
10094void SpeculativeJIT::speculateObject(Edge edge)
10095{
10096 if (!needsTypeCheck(edge, SpecObject))
10097 return;
10098
10099 SpeculateCellOperand operand(this, edge);
10100 speculateObject(edge, operand.gpr());
10101}
10102
10103void SpeculativeJIT::speculateFunction(Edge edge, GPRReg cell)
10104{
10105 speculateCellType(edge, cell, SpecFunction, JSFunctionType);
10106}
10107
10108void SpeculativeJIT::speculateFunction(Edge edge)
10109{
10110 if (!needsTypeCheck(edge, SpecFunction))
10111 return;
10112
10113 SpeculateCellOperand operand(this, edge);
10114 speculateFunction(edge, operand.gpr());
10115}
10116
10117void SpeculativeJIT::speculateFinalObject(Edge edge, GPRReg cell)
10118{
10119 speculateCellType(edge, cell, SpecFinalObject, FinalObjectType);
10120}
10121
10122void SpeculativeJIT::speculateFinalObject(Edge edge)
10123{
10124 if (!needsTypeCheck(edge, SpecFinalObject))
10125 return;
10126
10127 SpeculateCellOperand operand(this, edge);
10128 speculateFinalObject(edge, operand.gpr());
10129}
10130
10131void SpeculativeJIT::speculateRegExpObject(Edge edge, GPRReg cell)
10132{
10133 speculateCellType(edge, cell, SpecRegExpObject, RegExpObjectType);
10134}
10135
10136void SpeculativeJIT::speculateRegExpObject(Edge edge)
10137{
10138 if (!needsTypeCheck(edge, SpecRegExpObject))
10139 return;
10140
10141 SpeculateCellOperand operand(this, edge);
10142 speculateRegExpObject(edge, operand.gpr());
10143}
10144
10145void SpeculativeJIT::speculateArray(Edge edge, GPRReg cell)
10146{
10147 speculateCellType(edge, cell, SpecArray, ArrayType);
10148}
10149
10150void SpeculativeJIT::speculateArray(Edge edge)
10151{
10152 if (!needsTypeCheck(edge, SpecArray))
10153 return;
10154
10155 SpeculateCellOperand operand(this, edge);
10156 speculateArray(edge, operand.gpr());
10157}
10158
10159void SpeculativeJIT::speculateProxyObject(Edge edge, GPRReg cell)
10160{
10161 speculateCellType(edge, cell, SpecProxyObject, ProxyObjectType);
10162}
10163
10164void SpeculativeJIT::speculateProxyObject(Edge edge)
10165{
10166 if (!needsTypeCheck(edge, SpecProxyObject))
10167 return;
10168
10169 SpeculateCellOperand operand(this, edge);
10170 speculateProxyObject(edge, operand.gpr());
10171}
10172
10173void SpeculativeJIT::speculateDerivedArray(Edge edge, GPRReg cell)
10174{
10175 speculateCellType(edge, cell, SpecDerivedArray, DerivedArrayType);
10176}
10177
10178void SpeculativeJIT::speculateDerivedArray(Edge edge)
10179{
10180 if (!needsTypeCheck(edge, SpecDerivedArray))
10181 return;
10182
10183 SpeculateCellOperand operand(this, edge);
10184 speculateDerivedArray(edge, operand.gpr());
10185}
10186
10187void SpeculativeJIT::speculatePromiseObject(Edge edge, GPRReg cell)
10188{
10189 speculateCellType(edge, cell, SpecPromiseObject, JSPromiseType);
10190}
10191
10192void SpeculativeJIT::speculatePromiseObject(Edge edge)
10193{
10194 if (!needsTypeCheck(edge, SpecPromiseObject))
10195 return;
10196
10197 SpeculateCellOperand operand(this, edge);
10198 speculatePromiseObject(edge, operand.gpr());
10199}
10200
10201void SpeculativeJIT::speculateDateObject(Edge edge, GPRReg cell)
10202{
10203 speculateCellType(edge, cell, SpecDateObject, JSDateType);
10204}
10205
10206void SpeculativeJIT::speculateDateObject(Edge edge)
10207{
10208 if (!needsTypeCheck(edge, SpecDateObject))
10209 return;
10210
10211 SpeculateCellOperand operand(this, edge);
10212 speculateDateObject(edge, operand.gpr());
10213}
10214
10215void SpeculativeJIT::speculateMapObject(Edge edge, GPRReg cell)
10216{
10217 speculateCellType(edge, cell, SpecMapObject, JSMapType);
10218}
10219
10220void SpeculativeJIT::speculateMapObject(Edge edge)
10221{
10222 if (!needsTypeCheck(edge, SpecMapObject))
10223 return;
10224
10225 SpeculateCellOperand operand(this, edge);
10226 speculateMapObject(edge, operand.gpr());
10227}
10228
10229void SpeculativeJIT::speculateSetObject(Edge edge, GPRReg cell)
10230{
10231 speculateCellType(edge, cell, SpecSetObject, JSSetType);
10232}
10233
10234void SpeculativeJIT::speculateSetObject(Edge edge)
10235{
10236 if (!needsTypeCheck(edge, SpecSetObject))
10237 return;
10238
10239 SpeculateCellOperand operand(this, edge);
10240 speculateSetObject(edge, operand.gpr());
10241}
10242
10243void SpeculativeJIT::speculateWeakMapObject(Edge edge, GPRReg cell)
10244{
10245 speculateCellType(edge, cell, SpecWeakMapObject, JSWeakMapType);
10246}
10247
10248void SpeculativeJIT::speculateWeakMapObject(Edge edge)
10249{
10250 if (!needsTypeCheck(edge, SpecWeakMapObject))
10251 return;
10252
10253 SpeculateCellOperand operand(this, edge);
10254 speculateWeakMapObject(edge, operand.gpr());
10255}
10256
10257void SpeculativeJIT::speculateWeakSetObject(Edge edge, GPRReg cell)
10258{
10259 speculateCellType(edge, cell, SpecWeakSetObject, JSWeakSetType);
10260}
10261
10262void SpeculativeJIT::speculateWeakSetObject(Edge edge)
10263{
10264 if (!needsTypeCheck(edge, SpecWeakSetObject))
10265 return;
10266
10267 SpeculateCellOperand operand(this, edge);
10268 speculateWeakSetObject(edge, operand.gpr());
10269}
10270
10271void SpeculativeJIT::speculateDataViewObject(Edge edge, GPRReg cell)
10272{
10273 speculateCellType(edge, cell, SpecDataViewObject, DataViewType);
10274}
10275
10276void SpeculativeJIT::speculateDataViewObject(Edge edge)
10277{
10278 if (!needsTypeCheck(edge, SpecDataViewObject))
10279 return;
10280
10281 SpeculateCellOperand operand(this, edge);
10282 speculateDataViewObject(edge, operand.gpr());
10283}
10284
10285void SpeculativeJIT::speculateObjectOrOther(Edge edge)
10286{
10287 if (!needsTypeCheck(edge, SpecObject | SpecOther))
10288 return;
10289
10290 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10291 GPRTemporary temp(this);
10292 GPRReg tempGPR = temp.gpr();
10293 MacroAssembler::Jump notCell = m_jit.branchIfNotCell(operand.jsValueRegs());
10294 GPRReg gpr = operand.jsValueRegs().payloadGPR();
10295 DFG_TYPE_CHECK(
10296 operand.jsValueRegs(), edge, (~SpecCellCheck) | SpecObject, m_jit.branchIfNotObject(gpr));
10297 MacroAssembler::Jump done = m_jit.jump();
10298 notCell.link(&m_jit);
10299 DFG_TYPE_CHECK(
10300 operand.jsValueRegs(), edge, SpecCellCheck | SpecOther,
10301 m_jit.branchIfNotOther(operand.jsValueRegs(), tempGPR));
10302 done.link(&m_jit);
10303}
10304
10305void SpeculativeJIT::speculateString(Edge edge, GPRReg cell)
10306{
10307 DFG_TYPE_CHECK(
10308 JSValueSource::unboxedCell(cell), edge, SpecString | ~SpecCellCheck, m_jit.branchIfNotString(cell));
10309}
10310
10311void SpeculativeJIT::speculateStringOrOther(Edge edge, JSValueRegs regs, GPRReg scratch)
10312{
10313 JITCompiler::Jump notCell = m_jit.branchIfNotCell(regs);
10314 GPRReg cell = regs.payloadGPR();
10315 DFG_TYPE_CHECK(regs, edge, (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cell));
10316 JITCompiler::Jump done = m_jit.jump();
10317 notCell.link(&m_jit);
10318 DFG_TYPE_CHECK(regs, edge, SpecCellCheck | SpecOther, m_jit.branchIfNotOther(regs, scratch));
10319 done.link(&m_jit);
10320}
10321
10322void SpeculativeJIT::speculateStringOrOther(Edge edge)
10323{
10324 if (!needsTypeCheck(edge, SpecString | SpecOther))
10325 return;
10326
10327 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10328 GPRTemporary temp(this);
10329 JSValueRegs regs = operand.jsValueRegs();
10330 GPRReg tempGPR = temp.gpr();
10331 speculateStringOrOther(edge, regs, tempGPR);
10332}
10333
10334void SpeculativeJIT::speculateStringIdentAndLoadStorage(Edge edge, GPRReg string, GPRReg storage)
10335{
10336 m_jit.loadPtr(MacroAssembler::Address(string, JSString::offsetOfValue()), storage);
10337
10338 if (!needsTypeCheck(edge, SpecStringIdent | ~SpecString))
10339 return;
10340
10341 speculationCheck(
10342 BadType, JSValueSource::unboxedCell(string), edge,
10343 m_jit.branchIfRopeStringImpl(storage));
10344 speculationCheck(
10345 BadType, JSValueSource::unboxedCell(string), edge, m_jit.branchTest32(
10346 MacroAssembler::Zero,
10347 MacroAssembler::Address(storage, StringImpl::flagsOffset()),
10348 MacroAssembler::TrustedImm32(StringImpl::flagIsAtom())));
10349
10350 m_interpreter.filter(edge, SpecStringIdent | ~SpecString);
10351}
10352
10353void SpeculativeJIT::speculateStringIdent(Edge edge, GPRReg string)
10354{
10355 if (!needsTypeCheck(edge, SpecStringIdent))
10356 return;
10357
10358 GPRTemporary temp(this);
10359 speculateStringIdentAndLoadStorage(edge, string, temp.gpr());
10360}
10361
10362void SpeculativeJIT::speculateStringIdent(Edge edge)
10363{
10364 if (!needsTypeCheck(edge, SpecStringIdent))
10365 return;
10366
10367 SpeculateCellOperand operand(this, edge);
10368 GPRReg gpr = operand.gpr();
10369 speculateString(edge, gpr);
10370 speculateStringIdent(edge, gpr);
10371}
10372
10373void SpeculativeJIT::speculateString(Edge edge)
10374{
10375 if (!needsTypeCheck(edge, SpecString))
10376 return;
10377
10378 SpeculateCellOperand operand(this, edge);
10379 speculateString(edge, operand.gpr());
10380}
10381
10382void SpeculativeJIT::speculateStringObject(Edge edge, GPRReg cellGPR)
10383{
10384 DFG_TYPE_CHECK(JSValueSource::unboxedCell(cellGPR), edge, ~SpecCellCheck | SpecStringObject, m_jit.branchIfNotType(cellGPR, StringObjectType));
10385}
10386
10387void SpeculativeJIT::speculateStringObject(Edge edge)
10388{
10389 if (!needsTypeCheck(edge, SpecStringObject))
10390 return;
10391
10392 SpeculateCellOperand operand(this, edge);
10393 GPRReg gpr = operand.gpr();
10394 speculateStringObject(edge, gpr);
10395}
10396
10397void SpeculativeJIT::speculateStringOrStringObject(Edge edge)
10398{
10399 if (!needsTypeCheck(edge, SpecString | SpecStringObject))
10400 return;
10401
10402 SpeculateCellOperand operand(this, edge);
10403 GPRReg gpr = operand.gpr();
10404 if (!needsTypeCheck(edge, SpecString | SpecStringObject))
10405 return;
10406
10407 GPRTemporary typeTemp(this);
10408 GPRReg typeGPR = typeTemp.gpr();
10409
10410 m_jit.load8(JITCompiler::Address(gpr, JSCell::typeInfoTypeOffset()), typeGPR);
10411
10412 JITCompiler::Jump isString = m_jit.branch32(JITCompiler::Equal, typeGPR, TrustedImm32(StringType));
10413 speculationCheck(BadType, JSValueSource::unboxedCell(gpr), edge.node(), m_jit.branch32(JITCompiler::NotEqual, typeGPR, TrustedImm32(StringObjectType)));
10414 isString.link(&m_jit);
10415
10416 m_interpreter.filter(edge, SpecString | SpecStringObject);
10417}
10418
10419void SpeculativeJIT::speculateNotStringVar(Edge edge)
10420{
10421 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10422 GPRTemporary temp(this);
10423 GPRReg tempGPR = temp.gpr();
10424
10425 JITCompiler::Jump notCell = m_jit.branchIfNotCell(operand.jsValueRegs());
10426 GPRReg cell = operand.jsValueRegs().payloadGPR();
10427
10428 JITCompiler::Jump notString = m_jit.branchIfNotString(cell);
10429
10430 speculateStringIdentAndLoadStorage(edge, cell, tempGPR);
10431
10432 notString.link(&m_jit);
10433 notCell.link(&m_jit);
10434}
10435
10436void SpeculativeJIT::speculateNotSymbol(Edge edge)
10437{
10438 if (!needsTypeCheck(edge, ~SpecSymbol))
10439 return;
10440
10441 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10442 auto valueRegs = operand.jsValueRegs();
10443 GPRReg value = valueRegs.payloadGPR();
10444 JITCompiler::Jump notCell;
10445
10446 bool needsCellCheck = needsTypeCheck(edge, SpecCell);
10447 if (needsCellCheck)
10448 notCell = m_jit.branchIfNotCell(valueRegs);
10449
10450 speculationCheck(BadType, JSValueSource::unboxedCell(value), edge.node(), m_jit.branchIfSymbol(value));
10451
10452 if (needsCellCheck)
10453 notCell.link(&m_jit);
10454
10455 m_interpreter.filter(edge, ~SpecSymbol);
10456}
10457
10458void SpeculativeJIT::speculateSymbol(Edge edge, GPRReg cell)
10459{
10460 DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, ~SpecCellCheck | SpecSymbol, m_jit.branchIfNotSymbol(cell));
10461}
10462
10463void SpeculativeJIT::speculateSymbol(Edge edge)
10464{
10465 if (!needsTypeCheck(edge, SpecSymbol))
10466 return;
10467
10468 SpeculateCellOperand operand(this, edge);
10469 speculateSymbol(edge, operand.gpr());
10470}
10471
10472void SpeculativeJIT::speculateBigInt(Edge edge, GPRReg cell)
10473{
10474 DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, ~SpecCellCheck | SpecBigInt, m_jit.branchIfNotBigInt(cell));
10475}
10476
10477void SpeculativeJIT::speculateBigInt(Edge edge)
10478{
10479 if (!needsTypeCheck(edge, SpecBigInt))
10480 return;
10481
10482 SpeculateCellOperand operand(this, edge);
10483 speculateBigInt(edge, operand.gpr());
10484}
10485
10486void SpeculativeJIT::speculateNotCell(Edge edge, JSValueRegs regs)
10487{
10488 DFG_TYPE_CHECK(regs, edge, ~SpecCellCheck, m_jit.branchIfCell(regs));
10489}
10490
10491void SpeculativeJIT::speculateNotCell(Edge edge)
10492{
10493 if (!needsTypeCheck(edge, ~SpecCellCheck))
10494 return;
10495
10496 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10497 speculateNotCell(edge, operand.jsValueRegs());
10498}
10499
10500void SpeculativeJIT::speculateOther(Edge edge, JSValueRegs regs, GPRReg tempGPR)
10501{
10502 DFG_TYPE_CHECK(regs, edge, SpecOther, m_jit.branchIfNotOther(regs, tempGPR));
10503}
10504
10505void SpeculativeJIT::speculateOther(Edge edge, JSValueRegs regs)
10506{
10507 if (!needsTypeCheck(edge, SpecOther))
10508 return;
10509
10510 GPRTemporary temp(this);
10511 GPRReg tempGPR = temp.gpr();
10512 speculateOther(edge, regs, tempGPR);
10513}
10514
10515void SpeculativeJIT::speculateOther(Edge edge)
10516{
10517 if (!needsTypeCheck(edge, SpecOther))
10518 return;
10519
10520 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10521 speculateOther(edge, operand.jsValueRegs());
10522}
10523
10524void SpeculativeJIT::speculateMisc(Edge edge, JSValueRegs regs)
10525{
10526#if USE(JSVALUE64)
10527 DFG_TYPE_CHECK(
10528 regs, edge, SpecMisc,
10529 m_jit.branch64(MacroAssembler::Above, regs.gpr(), MacroAssembler::TrustedImm64(JSValue::MiscTag)));
10530#else
10531 IGNORE_WARNINGS_BEGIN("enum-compare")
10532 static_assert(JSValue::Int32Tag >= JSValue::UndefinedTag, "Int32Tag is included in >= JSValue::UndefinedTag range.");
10533 IGNORE_WARNINGS_END
10534 DFG_TYPE_CHECK(
10535 regs, edge, ~SpecInt32Only,
10536 m_jit.branchIfInt32(regs.tagGPR()));
10537 DFG_TYPE_CHECK(
10538 regs, edge, SpecMisc,
10539 m_jit.branch32(MacroAssembler::Below, regs.tagGPR(), MacroAssembler::TrustedImm32(JSValue::UndefinedTag)));
10540#endif
10541}
10542
10543void SpeculativeJIT::speculateMisc(Edge edge)
10544{
10545 if (!needsTypeCheck(edge, SpecMisc))
10546 return;
10547
10548 JSValueOperand operand(this, edge, ManualOperandSpeculation);
10549 speculateMisc(edge, operand.jsValueRegs());
10550}
10551
10552void SpeculativeJIT::speculate(Node*, Edge edge)
10553{
10554 switch (edge.useKind()) {
10555 case UntypedUse:
10556 break;
10557 case DoubleRepUse:
10558 case Int52RepUse:
10559 case KnownInt32Use:
10560 case KnownCellUse:
10561 case KnownStringUse:
10562 case KnownPrimitiveUse:
10563 case KnownOtherUse:
10564 case KnownBooleanUse:
10565 ASSERT(!m_interpreter.needsTypeCheck(edge));
10566 break;
10567 case Int32Use:
10568 speculateInt32(edge);
10569 break;
10570 case NumberUse:
10571 speculateNumber(edge);
10572 break;
10573 case RealNumberUse:
10574 speculateRealNumber(edge);
10575 break;
10576 case DoubleRepRealUse:
10577 speculateDoubleRepReal(edge);
10578 break;
10579#if USE(JSVALUE64)
10580 case AnyIntUse:
10581 speculateAnyInt(edge);
10582 break;
10583 case DoubleRepAnyIntUse:
10584 speculateDoubleRepAnyInt(edge);
10585 break;
10586#endif
10587 case BooleanUse:
10588 speculateBoolean(edge);
10589 break;
10590 case CellUse:
10591 speculateCell(edge);
10592 break;
10593 case CellOrOtherUse:
10594 speculateCellOrOther(edge);
10595 break;
10596 case ObjectUse:
10597 speculateObject(edge);
10598 break;
10599 case FunctionUse:
10600 speculateFunction(edge);
10601 break;
10602 case ArrayUse:
10603 speculateArray(edge);
10604 break;
10605 case FinalObjectUse:
10606 speculateFinalObject(edge);
10607 break;
10608 case RegExpObjectUse:
10609 speculateRegExpObject(edge);
10610 break;
10611 case PromiseObjectUse:
10612 speculatePromiseObject(edge);
10613 break;
10614 case ProxyObjectUse:
10615 speculateProxyObject(edge);
10616 break;
10617 case DerivedArrayUse:
10618 speculateDerivedArray(edge);
10619 break;
10620 case DateObjectUse:
10621 speculateDateObject(edge);
10622 break;
10623 case MapObjectUse:
10624 speculateMapObject(edge);
10625 break;
10626 case SetObjectUse:
10627 speculateSetObject(edge);
10628 break;
10629 case WeakMapObjectUse:
10630 speculateWeakMapObject(edge);
10631 break;
10632 case WeakSetObjectUse:
10633 speculateWeakSetObject(edge);
10634 break;
10635 case DataViewObjectUse:
10636 speculateDataViewObject(edge);
10637 break;
10638 case ObjectOrOtherUse:
10639 speculateObjectOrOther(edge);
10640 break;
10641 case StringIdentUse:
10642 speculateStringIdent(edge);
10643 break;
10644 case StringUse:
10645 speculateString(edge);
10646 break;
10647 case StringOrOtherUse:
10648 speculateStringOrOther(edge);
10649 break;
10650 case SymbolUse:
10651 speculateSymbol(edge);
10652 break;
10653 case BigIntUse:
10654 speculateBigInt(edge);
10655 break;
10656 case StringObjectUse:
10657 speculateStringObject(edge);
10658 break;
10659 case StringOrStringObjectUse:
10660 speculateStringOrStringObject(edge);
10661 break;
10662 case NotStringVarUse:
10663 speculateNotStringVar(edge);
10664 break;
10665 case NotSymbolUse:
10666 speculateNotSymbol(edge);
10667 break;
10668 case NotCellUse:
10669 speculateNotCell(edge);
10670 break;
10671 case OtherUse:
10672 speculateOther(edge);
10673 break;
10674 case MiscUse:
10675 speculateMisc(edge);
10676 break;
10677 default:
10678 RELEASE_ASSERT_NOT_REACHED();
10679 break;
10680 }
10681}
10682
10683void SpeculativeJIT::emitSwitchIntJump(
10684 SwitchData* data, GPRReg value, GPRReg scratch)
10685{
10686 SimpleJumpTable& table = m_jit.codeBlock()->switchJumpTable(data->switchTableIndex);
10687 table.ensureCTITable();
10688 m_jit.sub32(Imm32(table.min), value);
10689 addBranch(
10690 m_jit.branch32(JITCompiler::AboveOrEqual, value, Imm32(table.ctiOffsets.size())),
10691 data->fallThrough.block);
10692 m_jit.move(TrustedImmPtr(table.ctiOffsets.begin()), scratch);
10693 m_jit.loadPtr(JITCompiler::BaseIndex(scratch, value, JITCompiler::timesPtr()), scratch);
10694
10695 m_jit.farJump(scratch, JSSwitchPtrTag);
10696 data->didUseJumpTable = true;
10697}
10698
10699void SpeculativeJIT::emitSwitchImm(Node* node, SwitchData* data)
10700{
10701 switch (node->child1().useKind()) {
10702 case Int32Use: {
10703 SpeculateInt32Operand value(this, node->child1());
10704 GPRTemporary temp(this);
10705 emitSwitchIntJump(data, value.gpr(), temp.gpr());
10706 noResult(node);
10707 break;
10708 }
10709
10710 case UntypedUse: {
10711 JSValueOperand value(this, node->child1());
10712 GPRTemporary temp(this);
10713 JSValueRegs valueRegs = value.jsValueRegs();
10714 GPRReg scratch = temp.gpr();
10715
10716 value.use();
10717
10718 auto notInt32 = m_jit.branchIfNotInt32(valueRegs);
10719 emitSwitchIntJump(data, valueRegs.payloadGPR(), scratch);
10720 notInt32.link(&m_jit);
10721 addBranch(m_jit.branchIfNotNumber(valueRegs, scratch), data->fallThrough.block);
10722 silentSpillAllRegisters(scratch);
10723 callOperation(operationFindSwitchImmTargetForDouble, scratch, &vm(), valueRegs, data->switchTableIndex);
10724 silentFillAllRegisters();
10725
10726 m_jit.farJump(scratch, JSSwitchPtrTag);
10727 noResult(node, UseChildrenCalledExplicitly);
10728 break;
10729 }
10730
10731 default:
10732 RELEASE_ASSERT_NOT_REACHED();
10733 break;
10734 }
10735}
10736
10737void SpeculativeJIT::emitSwitchCharStringJump(Node* node, SwitchData* data, GPRReg value, GPRReg scratch)
10738{
10739 m_jit.loadPtr(MacroAssembler::Address(value, JSString::offsetOfValue()), scratch);
10740 auto isRope = m_jit.branchIfRopeStringImpl(scratch);
10741 addSlowPathGenerator(slowPathCall(isRope, this, operationResolveRope, scratch, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), value));
10742
10743 addBranch(
10744 m_jit.branch32(
10745 MacroAssembler::NotEqual,
10746 MacroAssembler::Address(scratch, StringImpl::lengthMemoryOffset()),
10747 TrustedImm32(1)),
10748 data->fallThrough.block);
10749
10750 m_jit.loadPtr(MacroAssembler::Address(scratch, StringImpl::dataOffset()), value);
10751
10752 JITCompiler::Jump is8Bit = m_jit.branchTest32(
10753 MacroAssembler::NonZero,
10754 MacroAssembler::Address(scratch, StringImpl::flagsOffset()),
10755 TrustedImm32(StringImpl::flagIs8Bit()));
10756
10757 m_jit.load16(MacroAssembler::Address(value), scratch);
10758
10759 JITCompiler::Jump ready = m_jit.jump();
10760
10761 is8Bit.link(&m_jit);
10762 m_jit.load8(MacroAssembler::Address(value), scratch);
10763
10764 ready.link(&m_jit);
10765 emitSwitchIntJump(data, scratch, value);
10766}
10767
10768void SpeculativeJIT::emitSwitchChar(Node* node, SwitchData* data)
10769{
10770 switch (node->child1().useKind()) {
10771 case StringUse: {
10772 SpeculateCellOperand op1(this, node->child1());
10773 GPRTemporary temp(this);
10774
10775 GPRReg op1GPR = op1.gpr();
10776 GPRReg tempGPR = temp.gpr();
10777
10778 op1.use();
10779
10780 speculateString(node->child1(), op1GPR);
10781 emitSwitchCharStringJump(node, data, op1GPR, tempGPR);
10782 noResult(node, UseChildrenCalledExplicitly);
10783 break;
10784 }
10785
10786 case UntypedUse: {
10787 JSValueOperand op1(this, node->child1());
10788 GPRTemporary temp(this);
10789
10790 JSValueRegs op1Regs = op1.jsValueRegs();
10791 GPRReg tempGPR = temp.gpr();
10792
10793 op1.use();
10794
10795 addBranch(m_jit.branchIfNotCell(op1Regs), data->fallThrough.block);
10796
10797 addBranch(m_jit.branchIfNotString(op1Regs.payloadGPR()), data->fallThrough.block);
10798
10799 emitSwitchCharStringJump(node, data, op1Regs.payloadGPR(), tempGPR);
10800 noResult(node, UseChildrenCalledExplicitly);
10801 break;
10802 }
10803
10804 default:
10805 RELEASE_ASSERT_NOT_REACHED();
10806 break;
10807 }
10808}
10809
10810namespace {
10811
10812struct CharacterCase {
10813 bool operator<(const CharacterCase& other) const
10814 {
10815 return character < other.character;
10816 }
10817
10818 LChar character;
10819 unsigned begin;
10820 unsigned end;
10821};
10822
10823} // anonymous namespace
10824
10825void SpeculativeJIT::emitBinarySwitchStringRecurse(
10826 SwitchData* data, const Vector<SpeculativeJIT::StringSwitchCase>& cases,
10827 unsigned numChecked, unsigned begin, unsigned end, GPRReg buffer, GPRReg length,
10828 GPRReg temp, unsigned alreadyCheckedLength, bool checkedExactLength)
10829{
10830 static constexpr bool verbose = false;
10831
10832 if (verbose) {
10833 dataLog("We're down to the following cases, alreadyCheckedLength = ", alreadyCheckedLength, ":\n");
10834 for (unsigned i = begin; i < end; ++i) {
10835 dataLog(" ", cases[i].string, "\n");
10836 }
10837 }
10838
10839 if (begin == end) {
10840 jump(data->fallThrough.block, ForceJump);
10841 return;
10842 }
10843
10844 unsigned minLength = cases[begin].string->length();
10845 unsigned commonChars = minLength;
10846 bool allLengthsEqual = true;
10847 for (unsigned i = begin + 1; i < end; ++i) {
10848 unsigned myCommonChars = numChecked;
10849 for (unsigned j = numChecked;
10850 j < std::min(cases[begin].string->length(), cases[i].string->length());
10851 ++j) {
10852 if (cases[begin].string->at(j) != cases[i].string->at(j)) {
10853 if (verbose)
10854 dataLog("string(", cases[i].string, ")[", j, "] != string(", cases[begin].string, ")[", j, "]\n");
10855 break;
10856 }
10857 myCommonChars++;
10858 }
10859 commonChars = std::min(commonChars, myCommonChars);
10860 if (minLength != cases[i].string->length())
10861 allLengthsEqual = false;
10862 minLength = std::min(minLength, cases[i].string->length());
10863 }
10864
10865 if (checkedExactLength) {
10866 RELEASE_ASSERT(alreadyCheckedLength == minLength);
10867 RELEASE_ASSERT(allLengthsEqual);
10868 }
10869
10870 RELEASE_ASSERT(minLength >= commonChars);
10871
10872 if (verbose)
10873 dataLog("length = ", minLength, ", commonChars = ", commonChars, ", allLengthsEqual = ", allLengthsEqual, "\n");
10874
10875 if (!allLengthsEqual && alreadyCheckedLength < minLength)
10876 branch32(MacroAssembler::Below, length, Imm32(minLength), data->fallThrough.block);
10877 if (allLengthsEqual && (alreadyCheckedLength < minLength || !checkedExactLength))
10878 branch32(MacroAssembler::NotEqual, length, Imm32(minLength), data->fallThrough.block);
10879
10880 for (unsigned i = numChecked; i < commonChars; ++i) {
10881 branch8(
10882 MacroAssembler::NotEqual, MacroAssembler::Address(buffer, i),
10883 TrustedImm32(cases[begin].string->at(i)), data->fallThrough.block);
10884 }
10885
10886 if (minLength == commonChars) {
10887 // This is the case where one of the cases is a prefix of all of the other cases.
10888 // We've already checked that the input string is a prefix of all of the cases,
10889 // so we just check length to jump to that case.
10890
10891 if (!ASSERT_DISABLED) {
10892 ASSERT(cases[begin].string->length() == commonChars);
10893 for (unsigned i = begin + 1; i < end; ++i)
10894 ASSERT(cases[i].string->length() > commonChars);
10895 }
10896
10897 if (allLengthsEqual) {
10898 RELEASE_ASSERT(end == begin + 1);
10899 jump(cases[begin].target, ForceJump);
10900 return;
10901 }
10902
10903 branch32(MacroAssembler::Equal, length, Imm32(commonChars), cases[begin].target);
10904
10905 // We've checked if the length is >= minLength, and then we checked if the
10906 // length is == commonChars. We get to this point if it is >= minLength but not
10907 // == commonChars. Hence we know that it now must be > minLength, i.e., that
10908 // it's >= minLength + 1.
10909 emitBinarySwitchStringRecurse(
10910 data, cases, commonChars, begin + 1, end, buffer, length, temp, minLength + 1, false);
10911 return;
10912 }
10913
10914 // At this point we know that the string is longer than commonChars, and we've only
10915 // verified commonChars. Use a binary switch on the next unchecked character, i.e.
10916 // string[commonChars].
10917
10918 RELEASE_ASSERT(end >= begin + 2);
10919
10920 m_jit.load8(MacroAssembler::Address(buffer, commonChars), temp);
10921
10922 Vector<CharacterCase> characterCases;
10923 CharacterCase currentCase;
10924 currentCase.character = cases[begin].string->at(commonChars);
10925 currentCase.begin = begin;
10926 currentCase.end = begin + 1;
10927 for (unsigned i = begin + 1; i < end; ++i) {
10928 if (cases[i].string->at(commonChars) != currentCase.character) {
10929 if (verbose)
10930 dataLog("string(", cases[i].string, ")[", commonChars, "] != string(", cases[begin].string, ")[", commonChars, "]\n");
10931 currentCase.end = i;
10932 characterCases.append(currentCase);
10933 currentCase.character = cases[i].string->at(commonChars);
10934 currentCase.begin = i;
10935 currentCase.end = i + 1;
10936 } else
10937 currentCase.end = i + 1;
10938 }
10939 characterCases.append(currentCase);
10940
10941 Vector<int64_t> characterCaseValues;
10942 for (unsigned i = 0; i < characterCases.size(); ++i)
10943 characterCaseValues.append(characterCases[i].character);
10944
10945 BinarySwitch binarySwitch(temp, characterCaseValues, BinarySwitch::Int32);
10946 while (binarySwitch.advance(m_jit)) {
10947 const CharacterCase& myCase = characterCases[binarySwitch.caseIndex()];
10948 emitBinarySwitchStringRecurse(
10949 data, cases, commonChars + 1, myCase.begin, myCase.end, buffer, length,
10950 temp, minLength, allLengthsEqual);
10951 }
10952
10953 addBranch(binarySwitch.fallThrough(), data->fallThrough.block);
10954}
10955
10956void SpeculativeJIT::emitSwitchStringOnString(Node* node, SwitchData* data, GPRReg string)
10957{
10958 data->didUseJumpTable = true;
10959
10960 bool canDoBinarySwitch = true;
10961 unsigned totalLength = 0;
10962
10963 for (unsigned i = data->cases.size(); i--;) {
10964 StringImpl* string = data->cases[i].value.stringImpl();
10965 if (!string->is8Bit()) {
10966 canDoBinarySwitch = false;
10967 break;
10968 }
10969 if (string->length() > Options::maximumBinaryStringSwitchCaseLength()) {
10970 canDoBinarySwitch = false;
10971 break;
10972 }
10973 totalLength += string->length();
10974 }
10975
10976 if (!canDoBinarySwitch || totalLength > Options::maximumBinaryStringSwitchTotalLength()) {
10977 flushRegisters();
10978 callOperation(
10979 operationSwitchString, string, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), static_cast<size_t>(data->switchTableIndex), string);
10980 m_jit.exceptionCheck();
10981 m_jit.farJump(string, JSSwitchPtrTag);
10982 return;
10983 }
10984
10985 GPRTemporary length(this);
10986 GPRTemporary temp(this);
10987
10988 GPRReg lengthGPR = length.gpr();
10989 GPRReg tempGPR = temp.gpr();
10990
10991 MacroAssembler::JumpList slowCases;
10992 m_jit.loadPtr(MacroAssembler::Address(string, JSString::offsetOfValue()), tempGPR);
10993 slowCases.append(m_jit.branchIfRopeStringImpl(tempGPR));
10994 m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), lengthGPR);
10995
10996 slowCases.append(m_jit.branchTest32(
10997 MacroAssembler::Zero,
10998 MacroAssembler::Address(tempGPR, StringImpl::flagsOffset()),
10999 TrustedImm32(StringImpl::flagIs8Bit())));
11000
11001 m_jit.loadPtr(MacroAssembler::Address(tempGPR, StringImpl::dataOffset()), string);
11002
11003 Vector<StringSwitchCase> cases;
11004 for (unsigned i = 0; i < data->cases.size(); ++i) {
11005 cases.append(
11006 StringSwitchCase(data->cases[i].value.stringImpl(), data->cases[i].target.block));
11007 }
11008
11009 std::sort(cases.begin(), cases.end());
11010
11011 emitBinarySwitchStringRecurse(
11012 data, cases, 0, 0, cases.size(), string, lengthGPR, tempGPR, 0, false);
11013
11014 slowCases.link(&m_jit);
11015 silentSpillAllRegisters(string);
11016 callOperation(operationSwitchString, string, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), static_cast<size_t>(data->switchTableIndex), string);
11017 silentFillAllRegisters();
11018 m_jit.exceptionCheck();
11019 m_jit.farJump(string, JSSwitchPtrTag);
11020}
11021
11022void SpeculativeJIT::emitSwitchString(Node* node, SwitchData* data)
11023{
11024 switch (node->child1().useKind()) {
11025 case StringIdentUse: {
11026 SpeculateCellOperand op1(this, node->child1());
11027 GPRTemporary temp(this);
11028
11029 GPRReg op1GPR = op1.gpr();
11030 GPRReg tempGPR = temp.gpr();
11031
11032 speculateString(node->child1(), op1GPR);
11033 speculateStringIdentAndLoadStorage(node->child1(), op1GPR, tempGPR);
11034
11035 Vector<int64_t> identifierCaseValues;
11036 for (unsigned i = 0; i < data->cases.size(); ++i) {
11037 identifierCaseValues.append(
11038 static_cast<int64_t>(bitwise_cast<intptr_t>(data->cases[i].value.stringImpl())));
11039 }
11040
11041 BinarySwitch binarySwitch(tempGPR, identifierCaseValues, BinarySwitch::IntPtr);
11042 while (binarySwitch.advance(m_jit))
11043 jump(data->cases[binarySwitch.caseIndex()].target.block, ForceJump);
11044 addBranch(binarySwitch.fallThrough(), data->fallThrough.block);
11045
11046 noResult(node);
11047 break;
11048 }
11049
11050 case StringUse: {
11051 SpeculateCellOperand op1(this, node->child1());
11052
11053 GPRReg op1GPR = op1.gpr();
11054
11055 op1.use();
11056
11057 speculateString(node->child1(), op1GPR);
11058 emitSwitchStringOnString(node, data, op1GPR);
11059 noResult(node, UseChildrenCalledExplicitly);
11060 break;
11061 }
11062
11063 case UntypedUse: {
11064 JSValueOperand op1(this, node->child1());
11065
11066 JSValueRegs op1Regs = op1.jsValueRegs();
11067
11068 op1.use();
11069
11070 addBranch(m_jit.branchIfNotCell(op1Regs), data->fallThrough.block);
11071
11072 addBranch(m_jit.branchIfNotString(op1Regs.payloadGPR()), data->fallThrough.block);
11073
11074 emitSwitchStringOnString(node, data, op1Regs.payloadGPR());
11075 noResult(node, UseChildrenCalledExplicitly);
11076 break;
11077 }
11078
11079 default:
11080 RELEASE_ASSERT_NOT_REACHED();
11081 break;
11082 }
11083}
11084
11085void SpeculativeJIT::emitSwitch(Node* node)
11086{
11087 SwitchData* data = node->switchData();
11088 switch (data->kind) {
11089 case SwitchImm: {
11090 emitSwitchImm(node, data);
11091 return;
11092 }
11093 case SwitchChar: {
11094 emitSwitchChar(node, data);
11095 return;
11096 }
11097 case SwitchString: {
11098 emitSwitchString(node, data);
11099 return;
11100 }
11101 case SwitchCell: {
11102 DFG_CRASH(m_jit.graph(), node, "Bad switch kind");
11103 return;
11104 } }
11105 RELEASE_ASSERT_NOT_REACHED();
11106}
11107
11108void SpeculativeJIT::addBranch(const MacroAssembler::JumpList& jump, BasicBlock* destination)
11109{
11110 for (unsigned i = jump.jumps().size(); i--;)
11111 addBranch(jump.jumps()[i], destination);
11112}
11113
11114void SpeculativeJIT::linkBranches()
11115{
11116 for (auto& branch : m_branches)
11117 branch.jump.linkTo(m_jit.blockHeads()[branch.destination->index], &m_jit);
11118}
11119
11120void SpeculativeJIT::compileStoreBarrier(Node* node)
11121{
11122 ASSERT(node->op() == StoreBarrier || node->op() == FencedStoreBarrier);
11123
11124 bool isFenced = node->op() == FencedStoreBarrier;
11125
11126 SpeculateCellOperand base(this, node->child1());
11127 GPRTemporary scratch1(this);
11128
11129 GPRReg baseGPR = base.gpr();
11130 GPRReg scratch1GPR = scratch1.gpr();
11131
11132 JITCompiler::JumpList ok;
11133
11134 if (isFenced) {
11135 ok.append(m_jit.barrierBranch(vm(), baseGPR, scratch1GPR));
11136
11137 JITCompiler::Jump noFence = m_jit.jumpIfMutatorFenceNotNeeded(vm());
11138 m_jit.memoryFence();
11139 ok.append(m_jit.barrierBranchWithoutFence(baseGPR));
11140 noFence.link(&m_jit);
11141 } else
11142 ok.append(m_jit.barrierBranchWithoutFence(baseGPR));
11143
11144 silentSpillAllRegisters(InvalidGPRReg);
11145 callOperation(operationWriteBarrierSlowPath, &vm(), baseGPR);
11146 silentFillAllRegisters();
11147
11148 ok.link(&m_jit);
11149
11150 noResult(node);
11151}
11152
11153void SpeculativeJIT::compilePutAccessorById(Node* node)
11154{
11155 SpeculateCellOperand base(this, node->child1());
11156 SpeculateCellOperand accessor(this, node->child2());
11157
11158 GPRReg baseGPR = base.gpr();
11159 GPRReg accessorGPR = accessor.gpr();
11160
11161 flushRegisters();
11162 callOperation(node->op() == PutGetterById ? operationPutGetterById : operationPutSetterById, NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, identifierUID(node->identifierNumber()), node->accessorAttributes(), accessorGPR);
11163 m_jit.exceptionCheck();
11164
11165 noResult(node);
11166}
11167
11168void SpeculativeJIT::compilePutGetterSetterById(Node* node)
11169{
11170 SpeculateCellOperand base(this, node->child1());
11171 JSValueOperand getter(this, node->child2());
11172 JSValueOperand setter(this, node->child3());
11173
11174#if USE(JSVALUE64)
11175 GPRReg baseGPR = base.gpr();
11176 GPRReg getterGPR = getter.gpr();
11177 GPRReg setterGPR = setter.gpr();
11178
11179 flushRegisters();
11180 callOperation(operationPutGetterSetter, NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, identifierUID(node->identifierNumber()), node->accessorAttributes(), getterGPR, setterGPR);
11181#else
11182 // These JSValues may be JSUndefined OR JSFunction*.
11183 // At that time,
11184 // 1. If the JSValue is JSUndefined, its payload becomes nullptr.
11185 // 2. If the JSValue is JSFunction*, its payload becomes JSFunction*.
11186 // So extract payload and pass it to operationPutGetterSetter. This hack is used as the same way in baseline JIT.
11187 GPRReg baseGPR = base.gpr();
11188 JSValueRegs getterRegs = getter.jsValueRegs();
11189 JSValueRegs setterRegs = setter.jsValueRegs();
11190
11191 flushRegisters();
11192 callOperation(operationPutGetterSetter, NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, identifierUID(node->identifierNumber()), node->accessorAttributes(), getterRegs.payloadGPR(), setterRegs.payloadGPR());
11193#endif
11194 m_jit.exceptionCheck();
11195
11196 noResult(node);
11197}
11198
11199void SpeculativeJIT::compileResolveScope(Node* node)
11200{
11201 SpeculateCellOperand scope(this, node->child1());
11202 GPRReg scopeGPR = scope.gpr();
11203 GPRFlushedCallResult result(this);
11204 GPRReg resultGPR = result.gpr();
11205 flushRegisters();
11206 callOperation(operationResolveScope, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), scopeGPR, identifierUID(node->identifierNumber()));
11207 m_jit.exceptionCheck();
11208 cellResult(resultGPR, node);
11209}
11210
11211void SpeculativeJIT::compileResolveScopeForHoistingFuncDeclInEval(Node* node)
11212{
11213 SpeculateCellOperand scope(this, node->child1());
11214 GPRReg scopeGPR = scope.gpr();
11215 flushRegisters();
11216 JSValueRegsFlushedCallResult result(this);
11217 JSValueRegs resultRegs = result.regs();
11218 callOperation(operationResolveScopeForHoistingFuncDeclInEval, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), scopeGPR, identifierUID(node->identifierNumber()));
11219 m_jit.exceptionCheck();
11220 jsValueResult(resultRegs, node);
11221}
11222
11223void SpeculativeJIT::compileGetGlobalVariable(Node* node)
11224{
11225 JSValueRegsTemporary result(this);
11226 JSValueRegs resultRegs = result.regs();
11227 m_jit.loadValue(node->variablePointer(), resultRegs);
11228 jsValueResult(resultRegs, node);
11229}
11230
11231void SpeculativeJIT::compilePutGlobalVariable(Node* node)
11232{
11233 JSValueOperand value(this, node->child2());
11234 JSValueRegs valueRegs = value.jsValueRegs();
11235 m_jit.storeValue(valueRegs, node->variablePointer());
11236 noResult(node);
11237}
11238
11239void SpeculativeJIT::compileGetDynamicVar(Node* node)
11240{
11241 SpeculateCellOperand scope(this, node->child1());
11242 GPRReg scopeGPR = scope.gpr();
11243 flushRegisters();
11244 JSValueRegsFlushedCallResult result(this);
11245 JSValueRegs resultRegs = result.regs();
11246 callOperation(operationGetDynamicVar, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), scopeGPR, identifierUID(node->identifierNumber()), node->getPutInfo());
11247 m_jit.exceptionCheck();
11248 jsValueResult(resultRegs, node);
11249}
11250
11251void SpeculativeJIT::compilePutDynamicVar(Node* node)
11252{
11253 SpeculateCellOperand scope(this, node->child1());
11254 JSValueOperand value(this, node->child2());
11255
11256 GPRReg scopeGPR = scope.gpr();
11257 JSValueRegs valueRegs = value.jsValueRegs();
11258
11259 flushRegisters();
11260 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutDynamicVarStrict : operationPutDynamicVarNonStrict, NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), scopeGPR, valueRegs, identifierUID(node->identifierNumber()), node->getPutInfo());
11261 m_jit.exceptionCheck();
11262 noResult(node);
11263}
11264
11265void SpeculativeJIT::compileGetClosureVar(Node* node)
11266{
11267 SpeculateCellOperand base(this, node->child1());
11268 JSValueRegsTemporary result(this);
11269
11270 GPRReg baseGPR = base.gpr();
11271 JSValueRegs resultRegs = result.regs();
11272
11273 m_jit.loadValue(JITCompiler::Address(baseGPR, JSLexicalEnvironment::offsetOfVariable(node->scopeOffset())), resultRegs);
11274 jsValueResult(resultRegs, node);
11275}
11276
11277void SpeculativeJIT::compilePutClosureVar(Node* node)
11278{
11279 SpeculateCellOperand base(this, node->child1());
11280 JSValueOperand value(this, node->child2());
11281
11282 GPRReg baseGPR = base.gpr();
11283 JSValueRegs valueRegs = value.jsValueRegs();
11284
11285 m_jit.storeValue(valueRegs, JITCompiler::Address(baseGPR, JSLexicalEnvironment::offsetOfVariable(node->scopeOffset())));
11286 noResult(node);
11287}
11288
11289void SpeculativeJIT::compileGetInternalField(Node* node)
11290{
11291 SpeculateCellOperand base(this, node->child1());
11292 JSValueRegsTemporary result(this);
11293
11294 GPRReg baseGPR = base.gpr();
11295 JSValueRegs resultRegs = result.regs();
11296
11297 m_jit.loadValue(JITCompiler::Address(baseGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(node->internalFieldIndex())), resultRegs);
11298 jsValueResult(resultRegs, node);
11299}
11300
11301void SpeculativeJIT::compilePutInternalField(Node* node)
11302{
11303 SpeculateCellOperand base(this, node->child1());
11304 JSValueOperand value(this, node->child2());
11305
11306 GPRReg baseGPR = base.gpr();
11307 JSValueRegs valueRegs = value.jsValueRegs();
11308
11309 m_jit.storeValue(valueRegs, JITCompiler::Address(baseGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(node->internalFieldIndex())));
11310 noResult(node);
11311}
11312
11313void SpeculativeJIT::compilePutAccessorByVal(Node* node)
11314{
11315 SpeculateCellOperand base(this, node->child1());
11316 JSValueOperand subscript(this, node->child2());
11317 SpeculateCellOperand accessor(this, node->child3());
11318
11319 auto operation = node->op() == PutGetterByVal ? operationPutGetterByVal : operationPutSetterByVal;
11320
11321 GPRReg baseGPR = base.gpr();
11322 JSValueRegs subscriptRegs = subscript.jsValueRegs();
11323 GPRReg accessorGPR = accessor.gpr();
11324
11325 flushRegisters();
11326 callOperation(operation, NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, subscriptRegs, node->accessorAttributes(), accessorGPR);
11327 m_jit.exceptionCheck();
11328
11329 noResult(node);
11330}
11331
11332void SpeculativeJIT::compileGetRegExpObjectLastIndex(Node* node)
11333{
11334 SpeculateCellOperand regExp(this, node->child1());
11335 JSValueRegsTemporary result(this);
11336 GPRReg regExpGPR = regExp.gpr();
11337 JSValueRegs resultRegs = result.regs();
11338 speculateRegExpObject(node->child1(), regExpGPR);
11339 m_jit.loadValue(JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndex()), resultRegs);
11340 jsValueResult(resultRegs, node);
11341}
11342
11343void SpeculativeJIT::compileSetRegExpObjectLastIndex(Node* node)
11344{
11345 SpeculateCellOperand regExp(this, node->child1());
11346 JSValueOperand value(this, node->child2());
11347 GPRReg regExpGPR = regExp.gpr();
11348 JSValueRegs valueRegs = value.jsValueRegs();
11349
11350 if (!node->ignoreLastIndexIsWritable()) {
11351 speculateRegExpObject(node->child1(), regExpGPR);
11352 speculationCheck(
11353 ExoticObjectMode, JSValueRegs(), nullptr,
11354 m_jit.branchTestPtr(
11355 JITCompiler::NonZero,
11356 JITCompiler::Address(regExpGPR, RegExpObject::offsetOfRegExpAndLastIndexIsNotWritableFlag()),
11357 JITCompiler::TrustedImm32(RegExpObject::lastIndexIsNotWritableFlag)));
11358 }
11359
11360 m_jit.storeValue(valueRegs, JITCompiler::Address(regExpGPR, RegExpObject::offsetOfLastIndex()));
11361 noResult(node);
11362}
11363
11364void SpeculativeJIT::compileRegExpExec(Node* node)
11365{
11366 bool sample = false;
11367 if (sample)
11368 m_jit.incrementSuperSamplerCount();
11369
11370 SpeculateCellOperand globalObject(this, node->child1());
11371 GPRReg globalObjectGPR = globalObject.gpr();
11372
11373 if (node->child2().useKind() == RegExpObjectUse) {
11374 if (node->child3().useKind() == StringUse) {
11375 SpeculateCellOperand base(this, node->child2());
11376 SpeculateCellOperand argument(this, node->child3());
11377 GPRReg baseGPR = base.gpr();
11378 GPRReg argumentGPR = argument.gpr();
11379 speculateRegExpObject(node->child2(), baseGPR);
11380 speculateString(node->child3(), argumentGPR);
11381
11382 flushRegisters();
11383 JSValueRegsFlushedCallResult result(this);
11384 JSValueRegs resultRegs = result.regs();
11385 callOperation(operationRegExpExecString, resultRegs, globalObjectGPR, baseGPR, argumentGPR);
11386 m_jit.exceptionCheck();
11387
11388 jsValueResult(resultRegs, node);
11389
11390 if (sample)
11391 m_jit.decrementSuperSamplerCount();
11392 return;
11393 }
11394
11395 SpeculateCellOperand base(this, node->child2());
11396 JSValueOperand argument(this, node->child3());
11397 GPRReg baseGPR = base.gpr();
11398 JSValueRegs argumentRegs = argument.jsValueRegs();
11399 speculateRegExpObject(node->child2(), baseGPR);
11400
11401 flushRegisters();
11402 JSValueRegsFlushedCallResult result(this);
11403 JSValueRegs resultRegs = result.regs();
11404 callOperation(operationRegExpExec, resultRegs, globalObjectGPR, baseGPR, argumentRegs);
11405 m_jit.exceptionCheck();
11406
11407 jsValueResult(resultRegs, node);
11408
11409 if (sample)
11410 m_jit.decrementSuperSamplerCount();
11411 return;
11412 }
11413
11414 JSValueOperand base(this, node->child2());
11415 JSValueOperand argument(this, node->child3());
11416 JSValueRegs baseRegs = base.jsValueRegs();
11417 JSValueRegs argumentRegs = argument.jsValueRegs();
11418
11419 flushRegisters();
11420 JSValueRegsFlushedCallResult result(this);
11421 JSValueRegs resultRegs = result.regs();
11422 callOperation(operationRegExpExecGeneric, resultRegs, globalObjectGPR, baseRegs, argumentRegs);
11423 m_jit.exceptionCheck();
11424
11425 jsValueResult(resultRegs, node);
11426
11427 if (sample)
11428 m_jit.decrementSuperSamplerCount();
11429}
11430
11431void SpeculativeJIT::compileRegExpTest(Node* node)
11432{
11433 SpeculateCellOperand globalObject(this, node->child1());
11434 GPRReg globalObjectGPR = globalObject.gpr();
11435
11436 if (node->child2().useKind() == RegExpObjectUse) {
11437 if (node->child3().useKind() == StringUse) {
11438 SpeculateCellOperand base(this, node->child2());
11439 SpeculateCellOperand argument(this, node->child3());
11440 GPRReg baseGPR = base.gpr();
11441 GPRReg argumentGPR = argument.gpr();
11442 speculateRegExpObject(node->child2(), baseGPR);
11443 speculateString(node->child3(), argumentGPR);
11444
11445 flushRegisters();
11446 GPRFlushedCallResult result(this);
11447 callOperation(operationRegExpTestString, result.gpr(), globalObjectGPR, baseGPR, argumentGPR);
11448 m_jit.exceptionCheck();
11449
11450 unblessedBooleanResult(result.gpr(), node);
11451 return;
11452 }
11453
11454 SpeculateCellOperand base(this, node->child2());
11455 JSValueOperand argument(this, node->child3());
11456 GPRReg baseGPR = base.gpr();
11457 JSValueRegs argumentRegs = argument.jsValueRegs();
11458 speculateRegExpObject(node->child2(), baseGPR);
11459
11460 flushRegisters();
11461 GPRFlushedCallResult result(this);
11462 callOperation(operationRegExpTest, result.gpr(), globalObjectGPR, baseGPR, argumentRegs);
11463 m_jit.exceptionCheck();
11464
11465 unblessedBooleanResult(result.gpr(), node);
11466 return;
11467 }
11468
11469 JSValueOperand base(this, node->child2());
11470 JSValueOperand argument(this, node->child3());
11471 JSValueRegs baseRegs = base.jsValueRegs();
11472 JSValueRegs argumentRegs = argument.jsValueRegs();
11473
11474 flushRegisters();
11475 GPRFlushedCallResult result(this);
11476 callOperation(operationRegExpTestGeneric, result.gpr(), globalObjectGPR, baseRegs, argumentRegs);
11477 m_jit.exceptionCheck();
11478
11479 unblessedBooleanResult(result.gpr(), node);
11480}
11481
11482void SpeculativeJIT::compileStringReplace(Node* node)
11483{
11484 ASSERT(node->op() == StringReplace || node->op() == StringReplaceRegExp);
11485 bool sample = false;
11486 if (sample)
11487 m_jit.incrementSuperSamplerCount();
11488
11489 if (node->child1().useKind() == StringUse
11490 && node->child2().useKind() == RegExpObjectUse
11491 && node->child3().useKind() == StringUse) {
11492 if (JSString* replace = node->child3()->dynamicCastConstant<JSString*>(vm())) {
11493 if (!replace->length()) {
11494 SpeculateCellOperand string(this, node->child1());
11495 SpeculateCellOperand regExp(this, node->child2());
11496 GPRReg stringGPR = string.gpr();
11497 GPRReg regExpGPR = regExp.gpr();
11498 speculateString(node->child1(), stringGPR);
11499 speculateRegExpObject(node->child2(), regExpGPR);
11500
11501 flushRegisters();
11502 GPRFlushedCallResult result(this);
11503 callOperation(operationStringProtoFuncReplaceRegExpEmptyStr, result.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), stringGPR, regExpGPR);
11504 m_jit.exceptionCheck();
11505 cellResult(result.gpr(), node);
11506 if (sample)
11507 m_jit.decrementSuperSamplerCount();
11508 return;
11509 }
11510 }
11511
11512 SpeculateCellOperand string(this, node->child1());
11513 SpeculateCellOperand regExp(this, node->child2());
11514 SpeculateCellOperand replace(this, node->child3());
11515 GPRReg stringGPR = string.gpr();
11516 GPRReg regExpGPR = regExp.gpr();
11517 GPRReg replaceGPR = replace.gpr();
11518 speculateString(node->child1(), stringGPR);
11519 speculateRegExpObject(node->child2(), regExpGPR);
11520 speculateString(node->child3(), replaceGPR);
11521
11522 flushRegisters();
11523 GPRFlushedCallResult result(this);
11524 callOperation(operationStringProtoFuncReplaceRegExpString, result.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), stringGPR, regExpGPR, replaceGPR);
11525 m_jit.exceptionCheck();
11526 cellResult(result.gpr(), node);
11527 if (sample)
11528 m_jit.decrementSuperSamplerCount();
11529 return;
11530 }
11531
11532 // If we fixed up the edge of child2, we inserted a Check(@child2, String).
11533 OperandSpeculationMode child2SpeculationMode = AutomaticOperandSpeculation;
11534 if (node->child2().useKind() == StringUse)
11535 child2SpeculationMode = ManualOperandSpeculation;
11536
11537 JSValueOperand string(this, node->child1());
11538 JSValueOperand search(this, node->child2(), child2SpeculationMode);
11539 JSValueOperand replace(this, node->child3());
11540 JSValueRegs stringRegs = string.jsValueRegs();
11541 JSValueRegs searchRegs = search.jsValueRegs();
11542 JSValueRegs replaceRegs = replace.jsValueRegs();
11543
11544 flushRegisters();
11545 GPRFlushedCallResult result(this);
11546 callOperation(operationStringProtoFuncReplaceGeneric, result.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), stringRegs, searchRegs, replaceRegs);
11547 m_jit.exceptionCheck();
11548 cellResult(result.gpr(), node);
11549 if (sample)
11550 m_jit.decrementSuperSamplerCount();
11551}
11552
11553void SpeculativeJIT::compileRegExpExecNonGlobalOrSticky(Node* node)
11554{
11555 SpeculateCellOperand globalObject(this, node->child1());
11556 SpeculateCellOperand argument(this, node->child2());
11557 GPRReg globalObjectGPR = globalObject.gpr();
11558 GPRReg argumentGPR = argument.gpr();
11559
11560 speculateString(node->child2(), argumentGPR);
11561
11562 flushRegisters();
11563 JSValueRegsFlushedCallResult result(this);
11564 JSValueRegs resultRegs = result.regs();
11565 callOperation(
11566 operationRegExpExecNonGlobalOrSticky, resultRegs,
11567 globalObjectGPR, TrustedImmPtr(node->cellOperand()), argumentGPR);
11568 m_jit.exceptionCheck();
11569
11570 jsValueResult(resultRegs, node);
11571}
11572
11573void SpeculativeJIT::compileRegExpMatchFastGlobal(Node* node)
11574{
11575 SpeculateCellOperand globalObject(this, node->child1());
11576 SpeculateCellOperand argument(this, node->child2());
11577 GPRReg globalObjectGPR = globalObject.gpr();
11578 GPRReg argumentGPR = argument.gpr();
11579
11580 speculateString(node->child2(), argumentGPR);
11581
11582 flushRegisters();
11583 JSValueRegsFlushedCallResult result(this);
11584 JSValueRegs resultRegs = result.regs();
11585 callOperation(
11586 operationRegExpMatchFastGlobalString, resultRegs,
11587 globalObjectGPR, TrustedImmPtr(node->cellOperand()), argumentGPR);
11588 m_jit.exceptionCheck();
11589
11590 jsValueResult(resultRegs, node);
11591}
11592
11593void SpeculativeJIT::compileRegExpMatchFast(Node* node)
11594{
11595 SpeculateCellOperand globalObject(this, node->child1());
11596 SpeculateCellOperand base(this, node->child2());
11597 SpeculateCellOperand argument(this, node->child3());
11598 GPRReg globalObjectGPR = globalObject.gpr();
11599 GPRReg baseGPR = base.gpr();
11600 GPRReg argumentGPR = argument.gpr();
11601 speculateRegExpObject(node->child2(), baseGPR);
11602 speculateString(node->child3(), argumentGPR);
11603
11604 flushRegisters();
11605 JSValueRegsFlushedCallResult result(this);
11606 JSValueRegs resultRegs = result.regs();
11607 callOperation(
11608 operationRegExpMatchFastString, resultRegs,
11609 globalObjectGPR, baseGPR, argumentGPR);
11610 m_jit.exceptionCheck();
11611
11612 jsValueResult(resultRegs, node);
11613}
11614
11615void SpeculativeJIT::compileLazyJSConstant(Node* node)
11616{
11617 JSValueRegsTemporary result(this);
11618 JSValueRegs resultRegs = result.regs();
11619 node->lazyJSValue().emit(m_jit, resultRegs);
11620 jsValueResult(resultRegs, node);
11621}
11622
11623void SpeculativeJIT::compileMaterializeNewObject(Node* node)
11624{
11625 RegisteredStructure structure = node->structureSet().at(0);
11626 ASSERT(m_jit.graph().varArgChild(node, 0)->dynamicCastConstant<Structure*>(vm()) == structure.get());
11627
11628 ObjectMaterializationData& data = node->objectMaterializationData();
11629
11630 IndexingType indexingType = structure->indexingType();
11631 bool hasIndexingHeader = hasIndexedProperties(indexingType);
11632 int32_t publicLength = 0;
11633 int32_t vectorLength = 0;
11634
11635 if (hasIndexingHeader) {
11636 for (unsigned i = data.m_properties.size(); i--;) {
11637 Edge edge = m_jit.graph().varArgChild(node, 1 + i);
11638 switch (data.m_properties[i].kind()) {
11639 case PublicLengthPLoc:
11640 publicLength = edge->asInt32();
11641 break;
11642 case VectorLengthPLoc:
11643 vectorLength = edge->asInt32();
11644 break;
11645 default:
11646 break;
11647 }
11648 }
11649 }
11650
11651 GPRTemporary result(this);
11652 GPRTemporary storage(this);
11653 GPRReg resultGPR = result.gpr();
11654 GPRReg storageGPR = storage.gpr();
11655
11656 emitAllocateRawObject(resultGPR, structure, storageGPR, 0, vectorLength);
11657
11658 m_jit.store32(
11659 JITCompiler::TrustedImm32(publicLength),
11660 JITCompiler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
11661
11662 for (unsigned i = data.m_properties.size(); i--;) {
11663 Edge edge = m_jit.graph().varArgChild(node, 1 + i);
11664 PromotedLocationDescriptor descriptor = data.m_properties[i];
11665 switch (descriptor.kind()) {
11666 case IndexedPropertyPLoc: {
11667 JSValueOperand value(this, edge);
11668 m_jit.storeValue(
11669 value.jsValueRegs(),
11670 JITCompiler::Address(storageGPR, sizeof(EncodedJSValue) * descriptor.info()));
11671 break;
11672 }
11673
11674 case NamedPropertyPLoc: {
11675 StringImpl* uid = m_jit.graph().identifiers()[descriptor.info()];
11676 for (PropertyMapEntry entry : structure->getPropertiesConcurrently()) {
11677 if (uid != entry.key)
11678 continue;
11679
11680 JSValueOperand value(this, edge);
11681 GPRReg baseGPR = isInlineOffset(entry.offset) ? resultGPR : storageGPR;
11682 m_jit.storeValue(
11683 value.jsValueRegs(),
11684 JITCompiler::Address(baseGPR, offsetRelativeToBase(entry.offset)));
11685 }
11686 break;
11687 }
11688
11689 default:
11690 break;
11691 }
11692 }
11693
11694 cellResult(resultGPR, node);
11695}
11696
11697void SpeculativeJIT::compileRecordRegExpCachedResult(Node* node)
11698{
11699 Edge globalObjectEdge = m_jit.graph().varArgChild(node, 0);
11700 Edge regExpEdge = m_jit.graph().varArgChild(node, 1);
11701 Edge stringEdge = m_jit.graph().varArgChild(node, 2);
11702 Edge startEdge = m_jit.graph().varArgChild(node, 3);
11703 Edge endEdge = m_jit.graph().varArgChild(node, 4);
11704
11705 SpeculateCellOperand globalObject(this, globalObjectEdge);
11706 SpeculateCellOperand regExp(this, regExpEdge);
11707 SpeculateCellOperand string(this, stringEdge);
11708 SpeculateInt32Operand start(this, startEdge);
11709 SpeculateInt32Operand end(this, endEdge);
11710
11711 GPRReg globalObjectGPR = globalObject.gpr();
11712 GPRReg regExpGPR = regExp.gpr();
11713 GPRReg stringGPR = string.gpr();
11714 GPRReg startGPR = start.gpr();
11715 GPRReg endGPR = end.gpr();
11716
11717 ptrdiff_t offset = JSGlobalObject::regExpGlobalDataOffset() + RegExpGlobalData::offsetOfCachedResult();
11718
11719 m_jit.storePtr(
11720 regExpGPR,
11721 JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfLastRegExp()));
11722 m_jit.storePtr(
11723 stringGPR,
11724 JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfLastInput()));
11725 m_jit.store32(
11726 startGPR,
11727 JITCompiler::Address(
11728 globalObjectGPR,
11729 offset + RegExpCachedResult::offsetOfResult() + OBJECT_OFFSETOF(MatchResult, start)));
11730 m_jit.store32(
11731 endGPR,
11732 JITCompiler::Address(
11733 globalObjectGPR,
11734 offset + RegExpCachedResult::offsetOfResult() + OBJECT_OFFSETOF(MatchResult, end)));
11735 m_jit.store8(
11736 TrustedImm32(0),
11737 JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfReified()));
11738
11739 noResult(node);
11740}
11741
11742void SpeculativeJIT::compileDefineDataProperty(Node* node)
11743{
11744#if USE(JSVALUE64)
11745 static_assert(GPRInfo::numberOfRegisters >= 5, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
11746#else
11747 static_assert(GPRInfo::numberOfRegisters >= 6, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
11748#endif
11749
11750 SpeculateCellOperand base(this, m_jit.graph().varArgChild(node, 0));
11751 GPRReg baseGPR = base.gpr();
11752
11753 JSValueOperand value(this, m_jit.graph().varArgChild(node, 2));
11754 JSValueRegs valueRegs = value.jsValueRegs();
11755
11756 SpeculateInt32Operand attributes(this, m_jit.graph().varArgChild(node, 3));
11757 GPRReg attributesGPR = attributes.gpr();
11758
11759 Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
11760 switch (propertyEdge.useKind()) {
11761 case StringUse: {
11762 SpeculateCellOperand property(this, propertyEdge);
11763 GPRReg propertyGPR = property.gpr();
11764 speculateString(propertyEdge, propertyGPR);
11765
11766 useChildren(node);
11767
11768 flushRegisters();
11769 callOperation(operationDefineDataPropertyString, NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyGPR, valueRegs, attributesGPR);
11770 m_jit.exceptionCheck();
11771 break;
11772 }
11773 case StringIdentUse: {
11774 SpeculateCellOperand property(this, propertyEdge);
11775 GPRTemporary ident(this);
11776
11777 GPRReg propertyGPR = property.gpr();
11778 GPRReg identGPR = ident.gpr();
11779
11780 speculateString(propertyEdge, propertyGPR);
11781 speculateStringIdentAndLoadStorage(propertyEdge, propertyGPR, identGPR);
11782
11783 useChildren(node);
11784
11785 flushRegisters();
11786 callOperation(operationDefineDataPropertyStringIdent, NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, identGPR, valueRegs, attributesGPR);
11787 m_jit.exceptionCheck();
11788 break;
11789 }
11790 case SymbolUse: {
11791 SpeculateCellOperand property(this, propertyEdge);
11792 GPRReg propertyGPR = property.gpr();
11793 speculateSymbol(propertyEdge, propertyGPR);
11794
11795 useChildren(node);
11796
11797 flushRegisters();
11798 callOperation(operationDefineDataPropertySymbol, NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyGPR, valueRegs, attributesGPR);
11799 m_jit.exceptionCheck();
11800 break;
11801 }
11802 case UntypedUse: {
11803 JSValueOperand property(this, propertyEdge);
11804 JSValueRegs propertyRegs = property.jsValueRegs();
11805
11806 useChildren(node);
11807
11808 flushRegisters();
11809 callOperation(operationDefineDataProperty, NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyRegs, valueRegs, attributesGPR);
11810 m_jit.exceptionCheck();
11811 break;
11812 }
11813 default:
11814 RELEASE_ASSERT_NOT_REACHED();
11815 }
11816
11817 noResult(node, UseChildrenCalledExplicitly);
11818}
11819
11820void SpeculativeJIT::compileDefineAccessorProperty(Node* node)
11821{
11822#if USE(JSVALUE64)
11823 static_assert(GPRInfo::numberOfRegisters >= 5, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
11824#else
11825 static_assert(GPRInfo::numberOfRegisters >= 6, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
11826#endif
11827
11828 SpeculateCellOperand base(this, m_jit.graph().varArgChild(node, 0));
11829 GPRReg baseGPR = base.gpr();
11830
11831 SpeculateCellOperand getter(this, m_jit.graph().varArgChild(node, 2));
11832 GPRReg getterGPR = getter.gpr();
11833
11834 SpeculateCellOperand setter(this, m_jit.graph().varArgChild(node, 3));
11835 GPRReg setterGPR = setter.gpr();
11836
11837 SpeculateInt32Operand attributes(this, m_jit.graph().varArgChild(node, 4));
11838 GPRReg attributesGPR = attributes.gpr();
11839
11840 Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
11841 switch (propertyEdge.useKind()) {
11842 case StringUse: {
11843 SpeculateCellOperand property(this, propertyEdge);
11844 GPRReg propertyGPR = property.gpr();
11845 speculateString(propertyEdge, propertyGPR);
11846
11847 useChildren(node);
11848
11849 flushRegisters();
11850 callOperation(operationDefineAccessorPropertyString, NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyGPR, getterGPR, setterGPR, attributesGPR);
11851 m_jit.exceptionCheck();
11852 break;
11853 }
11854 case StringIdentUse: {
11855 SpeculateCellOperand property(this, propertyEdge);
11856 GPRTemporary ident(this);
11857
11858 GPRReg propertyGPR = property.gpr();
11859 GPRReg identGPR = ident.gpr();
11860
11861 speculateString(propertyEdge, propertyGPR);
11862 speculateStringIdentAndLoadStorage(propertyEdge, propertyGPR, identGPR);
11863
11864 useChildren(node);
11865
11866 flushRegisters();
11867 callOperation(operationDefineAccessorPropertyStringIdent, NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, identGPR, getterGPR, setterGPR, attributesGPR);
11868 m_jit.exceptionCheck();
11869 break;
11870 }
11871 case SymbolUse: {
11872 SpeculateCellOperand property(this, propertyEdge);
11873 GPRReg propertyGPR = property.gpr();
11874 speculateSymbol(propertyEdge, propertyGPR);
11875
11876 useChildren(node);
11877
11878 flushRegisters();
11879 callOperation(operationDefineAccessorPropertySymbol, NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyGPR, getterGPR, setterGPR, attributesGPR);
11880 m_jit.exceptionCheck();
11881 break;
11882 }
11883 case UntypedUse: {
11884 JSValueOperand property(this, propertyEdge);
11885 JSValueRegs propertyRegs = property.jsValueRegs();
11886
11887 useChildren(node);
11888
11889 flushRegisters();
11890 callOperation(operationDefineAccessorProperty, NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyRegs, getterGPR, setterGPR, attributesGPR);
11891 m_jit.exceptionCheck();
11892 break;
11893 }
11894 default:
11895 RELEASE_ASSERT_NOT_REACHED();
11896 }
11897
11898 noResult(node, UseChildrenCalledExplicitly);
11899}
11900
11901void SpeculativeJIT::emitAllocateButterfly(GPRReg storageResultGPR, GPRReg sizeGPR, GPRReg scratch1, GPRReg scratch2, GPRReg scratch3, MacroAssembler::JumpList& slowCases)
11902{
11903 RELEASE_ASSERT(RegisterSet(storageResultGPR, sizeGPR, scratch1, scratch2, scratch3).numberOfSetGPRs() == 5);
11904 ASSERT((1 << 3) == sizeof(JSValue));
11905 m_jit.zeroExtend32ToPtr(sizeGPR, scratch1);
11906 m_jit.lshift32(TrustedImm32(3), scratch1);
11907 m_jit.add32(TrustedImm32(sizeof(IndexingHeader)), scratch1, scratch2);
11908#if !ASSERT_DISABLED
11909 MacroAssembler::Jump didNotOverflow = m_jit.branch32(MacroAssembler::AboveOrEqual, scratch2, sizeGPR);
11910 m_jit.abortWithReason(UncheckedOverflow);
11911 didNotOverflow.link(&m_jit);
11912#endif
11913 m_jit.emitAllocateVariableSized(
11914 storageResultGPR, vm().jsValueGigacageAuxiliarySpace, scratch2, scratch1, scratch3, slowCases);
11915 m_jit.addPtr(TrustedImm32(sizeof(IndexingHeader)), storageResultGPR);
11916
11917 m_jit.store32(sizeGPR, MacroAssembler::Address(storageResultGPR, Butterfly::offsetOfPublicLength()));
11918 m_jit.store32(sizeGPR, MacroAssembler::Address(storageResultGPR, Butterfly::offsetOfVectorLength()));
11919}
11920
11921void SpeculativeJIT::compileNormalizeMapKey(Node* node)
11922{
11923 ASSERT(node->child1().useKind() == UntypedUse);
11924 JSValueOperand key(this, node->child1());
11925 JSValueRegsTemporary result(this, Reuse, key);
11926 GPRTemporary scratch(this);
11927 FPRTemporary doubleValue(this);
11928 FPRTemporary temp(this);
11929
11930 JSValueRegs keyRegs = key.jsValueRegs();
11931 JSValueRegs resultRegs = result.regs();
11932 GPRReg scratchGPR = scratch.gpr();
11933 FPRReg doubleValueFPR = doubleValue.fpr();
11934 FPRReg tempFPR = temp.fpr();
11935
11936 CCallHelpers::JumpList passThroughCases;
11937 CCallHelpers::JumpList doneCases;
11938
11939 passThroughCases.append(m_jit.branchIfNotNumber(keyRegs, scratchGPR));
11940 passThroughCases.append(m_jit.branchIfInt32(keyRegs));
11941
11942#if USE(JSVALUE64)
11943 m_jit.unboxDoubleWithoutAssertions(keyRegs.gpr(), scratchGPR, doubleValueFPR);
11944#else
11945 unboxDouble(keyRegs.tagGPR(), keyRegs.payloadGPR(), doubleValueFPR, tempFPR);
11946#endif
11947 auto notNaN = m_jit.branchIfNotNaN(doubleValueFPR);
11948 m_jit.moveTrustedValue(jsNaN(), resultRegs);
11949 doneCases.append(m_jit.jump());
11950
11951 notNaN.link(&m_jit);
11952 m_jit.truncateDoubleToInt32(doubleValueFPR, scratchGPR);
11953 m_jit.convertInt32ToDouble(scratchGPR, tempFPR);
11954 passThroughCases.append(m_jit.branchDouble(JITCompiler::DoubleNotEqual, doubleValueFPR, tempFPR));
11955
11956 m_jit.boxInt32(scratchGPR, resultRegs);
11957 doneCases.append(m_jit.jump());
11958
11959 passThroughCases.link(&m_jit);
11960 m_jit.moveValueRegs(keyRegs, resultRegs);
11961
11962 doneCases.link(&m_jit);
11963 jsValueResult(resultRegs, node);
11964}
11965
11966void SpeculativeJIT::compileGetMapBucketHead(Node* node)
11967{
11968 SpeculateCellOperand map(this, node->child1());
11969 GPRTemporary bucket(this);
11970
11971 GPRReg mapGPR = map.gpr();
11972 GPRReg bucketGPR = bucket.gpr();
11973
11974 if (node->child1().useKind() == MapObjectUse)
11975 speculateMapObject(node->child1(), mapGPR);
11976 else if (node->child1().useKind() == SetObjectUse)
11977 speculateSetObject(node->child1(), mapGPR);
11978 else
11979 RELEASE_ASSERT_NOT_REACHED();
11980
11981 ASSERT(HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfHead() == HashMapImpl<HashMapBucket<HashMapBucketDataKeyValue>>::offsetOfHead());
11982 m_jit.loadPtr(MacroAssembler::Address(mapGPR, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfHead()), bucketGPR);
11983 cellResult(bucketGPR, node);
11984}
11985
11986void SpeculativeJIT::compileGetMapBucketNext(Node* node)
11987{
11988 SpeculateCellOperand bucket(this, node->child1());
11989 GPRTemporary result(this);
11990
11991 GPRReg bucketGPR = bucket.gpr();
11992 GPRReg resultGPR = result.gpr();
11993
11994 ASSERT(HashMapBucket<HashMapBucketDataKey>::offsetOfNext() == HashMapBucket<HashMapBucketDataKeyValue>::offsetOfNext());
11995 ASSERT(HashMapBucket<HashMapBucketDataKey>::offsetOfKey() == HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey());
11996 m_jit.loadPtr(MacroAssembler::Address(bucketGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfNext()), resultGPR);
11997
11998 MacroAssembler::Label loop = m_jit.label();
11999 auto notBucket = m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR);
12000#if USE(JSVALUE32_64)
12001 auto done = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::Address(resultGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey() + TagOffset), TrustedImm32(JSValue::EmptyValueTag));
12002#else
12003 auto done = m_jit.branchTest64(MacroAssembler::NonZero, MacroAssembler::Address(resultGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey()));
12004#endif
12005 m_jit.loadPtr(MacroAssembler::Address(resultGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfNext()), resultGPR);
12006 m_jit.jump().linkTo(loop, &m_jit);
12007
12008 notBucket.link(&m_jit);
12009 JSCell* sentinel = nullptr;
12010 if (node->bucketOwnerType() == BucketOwnerType::Map)
12011 sentinel = vm().sentinelMapBucket();
12012 else {
12013 ASSERT(node->bucketOwnerType() == BucketOwnerType::Set);
12014 sentinel = vm().sentinelSetBucket();
12015 }
12016 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), sentinel), resultGPR);
12017 done.link(&m_jit);
12018
12019 cellResult(resultGPR, node);
12020}
12021
12022void SpeculativeJIT::compileLoadKeyFromMapBucket(Node* node)
12023{
12024 SpeculateCellOperand bucket(this, node->child1());
12025 JSValueRegsTemporary result(this);
12026
12027 GPRReg bucketGPR = bucket.gpr();
12028 JSValueRegs resultRegs = result.regs();
12029
12030 m_jit.loadValue(MacroAssembler::Address(bucketGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey()), resultRegs);
12031 jsValueResult(resultRegs, node);
12032}
12033
12034void SpeculativeJIT::compileLoadValueFromMapBucket(Node* node)
12035{
12036 SpeculateCellOperand bucket(this, node->child1());
12037 JSValueRegsTemporary result(this);
12038
12039 GPRReg bucketGPR = bucket.gpr();
12040 JSValueRegs resultRegs = result.regs();
12041
12042 m_jit.loadValue(MacroAssembler::Address(bucketGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfValue()), resultRegs);
12043 jsValueResult(resultRegs, node);
12044}
12045
12046void SpeculativeJIT::compileExtractValueFromWeakMapGet(Node* node)
12047{
12048 JSValueOperand value(this, node->child1());
12049 JSValueRegsTemporary result(this, Reuse, value);
12050
12051 JSValueRegs valueRegs = value.jsValueRegs();
12052 JSValueRegs resultRegs = result.regs();
12053
12054#if USE(JSVALUE64)
12055 m_jit.moveValueRegs(valueRegs, resultRegs);
12056 auto done = m_jit.branchTestPtr(CCallHelpers::NonZero, resultRegs.payloadGPR());
12057 m_jit.moveValue(jsUndefined(), resultRegs);
12058 done.link(&m_jit);
12059#else
12060 auto isEmpty = m_jit.branchIfEmpty(valueRegs.tagGPR());
12061 m_jit.moveValueRegs(valueRegs, resultRegs);
12062 auto done = m_jit.jump();
12063
12064 isEmpty.link(&m_jit);
12065 m_jit.moveValue(jsUndefined(), resultRegs);
12066
12067 done.link(&m_jit);
12068#endif
12069
12070 jsValueResult(resultRegs, node, DataFormatJS);
12071}
12072
12073void SpeculativeJIT::compileThrow(Node* node)
12074{
12075 JSValueOperand value(this, node->child1());
12076 JSValueRegs valueRegs = value.jsValueRegs();
12077 flushRegisters();
12078 callOperation(operationThrowDFG, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueRegs);
12079 m_jit.exceptionCheck();
12080 m_jit.breakpoint();
12081 noResult(node);
12082}
12083
12084void SpeculativeJIT::compileThrowStaticError(Node* node)
12085{
12086 SpeculateCellOperand message(this, node->child1());
12087 GPRReg messageGPR = message.gpr();
12088 speculateString(node->child1(), messageGPR);
12089 flushRegisters();
12090 callOperation(operationThrowStaticError, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), messageGPR, node->errorType());
12091 m_jit.exceptionCheck();
12092 m_jit.breakpoint();
12093 noResult(node);
12094}
12095
12096void SpeculativeJIT::compileGetEnumerableLength(Node* node)
12097{
12098 SpeculateCellOperand enumerator(this, node->child1());
12099 GPRFlushedCallResult result(this);
12100 GPRReg resultGPR = result.gpr();
12101
12102 m_jit.load32(MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::indexedLengthOffset()), resultGPR);
12103 int32Result(resultGPR, node);
12104}
12105
12106void SpeculativeJIT::compileHasGenericProperty(Node* node)
12107{
12108 JSValueOperand base(this, node->child1());
12109 SpeculateCellOperand property(this, node->child2());
12110
12111 JSValueRegs baseRegs = base.jsValueRegs();
12112 GPRReg propertyGPR = property.gpr();
12113
12114 flushRegisters();
12115 JSValueRegsFlushedCallResult result(this);
12116 JSValueRegs resultRegs = result.regs();
12117 callOperation(operationHasGenericProperty, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseRegs, propertyGPR);
12118 m_jit.exceptionCheck();
12119 blessedBooleanResult(resultRegs.payloadGPR(), node);
12120}
12121
12122void SpeculativeJIT::compileToIndexString(Node* node)
12123{
12124 SpeculateInt32Operand index(this, node->child1());
12125 GPRReg indexGPR = index.gpr();
12126
12127 flushRegisters();
12128 GPRFlushedCallResult result(this);
12129 GPRReg resultGPR = result.gpr();
12130 callOperation(operationToIndexString, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), indexGPR);
12131 m_jit.exceptionCheck();
12132 cellResult(resultGPR, node);
12133}
12134
12135void SpeculativeJIT::compilePutByIdFlush(Node* node)
12136{
12137 SpeculateCellOperand base(this, node->child1());
12138 JSValueOperand value(this, node->child2());
12139 GPRTemporary scratch(this);
12140
12141 GPRReg baseGPR = base.gpr();
12142 JSValueRegs valueRegs = value.jsValueRegs();
12143 GPRReg scratchGPR = scratch.gpr();
12144 flushRegisters();
12145
12146 cachedPutById(node->origin.semantic, baseGPR, valueRegs, scratchGPR, node->identifierNumber(), NotDirect, MacroAssembler::Jump(), DontSpill);
12147
12148 noResult(node);
12149}
12150
12151void SpeculativeJIT::compilePutById(Node* node)
12152{
12153 SpeculateCellOperand base(this, node->child1());
12154 JSValueOperand value(this, node->child2());
12155 GPRTemporary scratch(this);
12156
12157 GPRReg baseGPR = base.gpr();
12158 JSValueRegs valueRegs = value.jsValueRegs();
12159 GPRReg scratchGPR = scratch.gpr();
12160
12161 cachedPutById(node->origin.semantic, baseGPR, valueRegs, scratchGPR, node->identifierNumber(), NotDirect);
12162
12163 noResult(node);
12164}
12165
12166void SpeculativeJIT::compilePutByIdDirect(Node* node)
12167{
12168 SpeculateCellOperand base(this, node->child1());
12169 JSValueOperand value(this, node->child2());
12170 GPRTemporary scratch(this);
12171
12172 GPRReg baseGPR = base.gpr();
12173 JSValueRegs valueRegs = value.jsValueRegs();
12174 GPRReg scratchGPR = scratch.gpr();
12175
12176 cachedPutById(node->origin.semantic, baseGPR, valueRegs, scratchGPR, node->identifierNumber(), Direct);
12177
12178 noResult(node);
12179}
12180
12181void SpeculativeJIT::compilePutByIdWithThis(Node* node)
12182{
12183 JSValueOperand base(this, node->child1());
12184 JSValueRegs baseRegs = base.jsValueRegs();
12185 JSValueOperand thisValue(this, node->child2());
12186 JSValueRegs thisRegs = thisValue.jsValueRegs();
12187 JSValueOperand value(this, node->child3());
12188 JSValueRegs valueRegs = value.jsValueRegs();
12189
12190 flushRegisters();
12191 callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByIdWithThisStrict : operationPutByIdWithThis,
12192 NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseRegs, thisRegs, valueRegs, identifierUID(node->identifierNumber()));
12193 m_jit.exceptionCheck();
12194
12195 noResult(node);
12196}
12197
12198void SpeculativeJIT::compileGetByOffset(Node* node)
12199{
12200 StorageOperand storage(this, node->child1());
12201 JSValueRegsTemporary result(this, Reuse, storage);
12202
12203 GPRReg storageGPR = storage.gpr();
12204 JSValueRegs resultRegs = result.regs();
12205
12206 StorageAccessData& storageAccessData = node->storageAccessData();
12207
12208 m_jit.loadValue(JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset)), resultRegs);
12209
12210 jsValueResult(resultRegs, node);
12211}
12212
12213void SpeculativeJIT::compilePutByOffset(Node* node)
12214{
12215 StorageOperand storage(this, node->child1());
12216 JSValueOperand value(this, node->child3());
12217
12218 GPRReg storageGPR = storage.gpr();
12219 JSValueRegs valueRegs = value.jsValueRegs();
12220
12221 speculate(node, node->child2());
12222
12223 StorageAccessData& storageAccessData = node->storageAccessData();
12224
12225 m_jit.storeValue(valueRegs, JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset)));
12226
12227 noResult(node);
12228}
12229
12230void SpeculativeJIT::compileMatchStructure(Node* node)
12231{
12232 SpeculateCellOperand base(this, node->child1());
12233 GPRTemporary temp(this);
12234 GPRReg baseGPR = base.gpr();
12235 GPRReg tempGPR = temp.gpr();
12236
12237 m_jit.load32(JITCompiler::Address(baseGPR, JSCell::structureIDOffset()), tempGPR);
12238
12239 auto& variants = node->matchStructureData().variants;
12240 Vector<int64_t> cases;
12241 for (MatchStructureVariant& variant : variants)
12242 cases.append(bitwise_cast<int32_t>(variant.structure->id()));
12243
12244 BinarySwitch binarySwitch(tempGPR, cases, BinarySwitch::Int32);
12245 JITCompiler::JumpList done;
12246 while (binarySwitch.advance(m_jit)) {
12247 m_jit.boxBooleanPayload(variants[binarySwitch.caseIndex()].result, tempGPR);
12248 done.append(m_jit.jump());
12249 }
12250 speculationCheck(BadCache, JSValueRegs(), node, binarySwitch.fallThrough());
12251
12252 done.link(&m_jit);
12253
12254 blessedBooleanResult(tempGPR, node);
12255}
12256
12257void SpeculativeJIT::compileHasStructureProperty(Node* node)
12258{
12259 JSValueOperand base(this, node->child1());
12260 SpeculateCellOperand property(this, node->child2());
12261 SpeculateCellOperand enumerator(this, node->child3());
12262 JSValueRegsTemporary result(this);
12263
12264 JSValueRegs baseRegs = base.jsValueRegs();
12265 GPRReg propertyGPR = property.gpr();
12266 JSValueRegs resultRegs = result.regs();
12267
12268 CCallHelpers::JumpList wrongStructure;
12269
12270 wrongStructure.append(m_jit.branchIfNotCell(baseRegs));
12271
12272 m_jit.load32(MacroAssembler::Address(baseRegs.payloadGPR(), JSCell::structureIDOffset()), resultRegs.payloadGPR());
12273 wrongStructure.append(m_jit.branch32(MacroAssembler::NotEqual,
12274 resultRegs.payloadGPR(),
12275 MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::cachedStructureIDOffset())));
12276
12277 moveTrueTo(resultRegs.payloadGPR());
12278 MacroAssembler::Jump done = m_jit.jump();
12279
12280 done.link(&m_jit);
12281
12282 addSlowPathGenerator(slowPathCall(wrongStructure, this, operationHasGenericProperty, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseRegs, propertyGPR));
12283 blessedBooleanResult(resultRegs.payloadGPR(), node);
12284}
12285
12286void SpeculativeJIT::compileGetPropertyEnumerator(Node* node)
12287{
12288 if (node->child1().useKind() == CellUse) {
12289 SpeculateCellOperand base(this, node->child1());
12290 GPRReg baseGPR = base.gpr();
12291
12292 flushRegisters();
12293 GPRFlushedCallResult result(this);
12294 GPRReg resultGPR = result.gpr();
12295 callOperation(operationGetPropertyEnumeratorCell, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR);
12296 m_jit.exceptionCheck();
12297 cellResult(resultGPR, node);
12298 return;
12299 }
12300
12301 JSValueOperand base(this, node->child1());
12302 JSValueRegs baseRegs = base.jsValueRegs();
12303
12304 flushRegisters();
12305 GPRFlushedCallResult result(this);
12306 GPRReg resultGPR = result.gpr();
12307 callOperation(operationGetPropertyEnumerator, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseRegs);
12308 m_jit.exceptionCheck();
12309 cellResult(resultGPR, node);
12310}
12311
12312void SpeculativeJIT::compileGetEnumeratorPname(Node* node)
12313{
12314 ASSERT(node->op() == GetEnumeratorStructurePname || node->op() == GetEnumeratorGenericPname);
12315 SpeculateCellOperand enumerator(this, node->child1());
12316 SpeculateStrictInt32Operand index(this, node->child2());
12317 GPRTemporary scratch(this);
12318 JSValueRegsTemporary result(this);
12319
12320 GPRReg enumeratorGPR = enumerator.gpr();
12321 GPRReg indexGPR = index.gpr();
12322 GPRReg scratchGPR = scratch.gpr();
12323 JSValueRegs resultRegs = result.regs();
12324
12325 MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, indexGPR,
12326 MacroAssembler::Address(enumeratorGPR, (node->op() == GetEnumeratorStructurePname)
12327 ? JSPropertyNameEnumerator::endStructurePropertyIndexOffset()
12328 : JSPropertyNameEnumerator::endGenericPropertyIndexOffset()));
12329
12330 m_jit.moveValue(jsNull(), resultRegs);
12331
12332 MacroAssembler::Jump done = m_jit.jump();
12333 inBounds.link(&m_jit);
12334
12335 m_jit.loadPtr(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), scratchGPR);
12336 m_jit.loadPtr(MacroAssembler::BaseIndex(scratchGPR, indexGPR, MacroAssembler::ScalePtr), resultRegs.payloadGPR());
12337#if USE(JSVALUE32_64)
12338 m_jit.move(MacroAssembler::TrustedImm32(JSValue::CellTag), resultRegs.tagGPR());
12339#endif
12340
12341 done.link(&m_jit);
12342 jsValueResult(resultRegs, node);
12343}
12344
12345void SpeculativeJIT::compileGetExecutable(Node* node)
12346{
12347 SpeculateCellOperand function(this, node->child1());
12348 GPRTemporary result(this, Reuse, function);
12349 GPRReg functionGPR = function.gpr();
12350 GPRReg resultGPR = result.gpr();
12351 speculateCellType(node->child1(), functionGPR, SpecFunction, JSFunctionType);
12352 m_jit.loadPtr(JITCompiler::Address(functionGPR, JSFunction::offsetOfExecutable()), resultGPR);
12353 cellResult(resultGPR, node);
12354}
12355
12356void SpeculativeJIT::compileGetGetter(Node* node)
12357{
12358 SpeculateCellOperand op1(this, node->child1());
12359 GPRTemporary result(this, Reuse, op1);
12360
12361 GPRReg op1GPR = op1.gpr();
12362 GPRReg resultGPR = result.gpr();
12363
12364 m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfGetter()), resultGPR);
12365
12366 cellResult(resultGPR, node);
12367}
12368
12369void SpeculativeJIT::compileGetSetter(Node* node)
12370{
12371 SpeculateCellOperand op1(this, node->child1());
12372 GPRTemporary result(this, Reuse, op1);
12373
12374 GPRReg op1GPR = op1.gpr();
12375 GPRReg resultGPR = result.gpr();
12376
12377 m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfSetter()), resultGPR);
12378
12379 cellResult(resultGPR, node);
12380}
12381
12382void SpeculativeJIT::compileGetCallee(Node* node)
12383{
12384 GPRTemporary result(this);
12385 m_jit.loadPtr(JITCompiler::payloadFor(CallFrameSlot::callee), result.gpr());
12386 cellResult(result.gpr(), node);
12387}
12388
12389void SpeculativeJIT::compileSetCallee(Node* node)
12390{
12391 SpeculateCellOperand callee(this, node->child1());
12392 m_jit.storeCell(callee.gpr(), JITCompiler::payloadFor(CallFrameSlot::callee));
12393 noResult(node);
12394}
12395
12396void SpeculativeJIT::compileGetArgumentCountIncludingThis(Node* node)
12397{
12398 GPRTemporary result(this);
12399 VirtualRegister argumentCountRegister;
12400 if (InlineCallFrame* inlineCallFrame = node->argumentsInlineCallFrame())
12401 argumentCountRegister = inlineCallFrame->argumentCountRegister;
12402 else
12403 argumentCountRegister = VirtualRegister(CallFrameSlot::argumentCount);
12404 m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), result.gpr());
12405 int32Result(result.gpr(), node);
12406}
12407
12408void SpeculativeJIT::compileSetArgumentCountIncludingThis(Node* node)
12409{
12410 m_jit.store32(TrustedImm32(node->argumentCountIncludingThis()), JITCompiler::payloadFor(CallFrameSlot::argumentCount));
12411 noResult(node);
12412}
12413
12414void SpeculativeJIT::compileStrCat(Node* node)
12415{
12416 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
12417 JSValueOperand op2(this, node->child2(), ManualOperandSpeculation);
12418 JSValueOperand op3(this, node->child3(), ManualOperandSpeculation);
12419
12420 JSValueRegs op1Regs = op1.jsValueRegs();
12421 JSValueRegs op2Regs = op2.jsValueRegs();
12422 JSValueRegs op3Regs;
12423
12424 if (node->child3())
12425 op3Regs = op3.jsValueRegs();
12426
12427 flushRegisters();
12428
12429 GPRFlushedCallResult result(this);
12430 if (node->child3())
12431 callOperation(operationStrCat3, result.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs, op2Regs, op3Regs);
12432 else
12433 callOperation(operationStrCat2, result.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), op1Regs, op2Regs);
12434 m_jit.exceptionCheck();
12435
12436 cellResult(result.gpr(), node);
12437}
12438
12439void SpeculativeJIT::compileNewArrayBuffer(Node* node)
12440{
12441 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
12442 auto* array = node->castOperand<JSImmutableButterfly*>();
12443
12444 IndexingType indexingMode = node->indexingMode();
12445 RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingMode));
12446
12447 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(indexingMode)) {
12448 GPRTemporary result(this);
12449 GPRTemporary scratch1(this);
12450 GPRTemporary scratch2(this);
12451
12452 GPRReg resultGPR = result.gpr();
12453 GPRReg scratch1GPR = scratch1.gpr();
12454 GPRReg scratch2GPR = scratch2.gpr();
12455
12456 MacroAssembler::JumpList slowCases;
12457
12458 emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), TrustedImmPtr(array->toButterfly()), scratch1GPR, scratch2GPR, slowCases);
12459
12460 addSlowPathGenerator(slowPathCall(slowCases, this, operationNewArrayBuffer, result.gpr(), &vm(), structure, array));
12461
12462 DFG_ASSERT(m_jit.graph(), node, indexingMode & IsArray, indexingMode);
12463 cellResult(resultGPR, node);
12464 return;
12465 }
12466
12467 flushRegisters();
12468 GPRFlushedCallResult result(this);
12469
12470 callOperation(operationNewArrayBuffer, result.gpr(), &vm(), structure, TrustedImmPtr(node->cellOperand()));
12471 m_jit.exceptionCheck();
12472
12473 cellResult(result.gpr(), node);
12474}
12475
12476void SpeculativeJIT::compileNewArrayWithSize(Node* node)
12477{
12478 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
12479 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(node->indexingType())) {
12480 SpeculateStrictInt32Operand size(this, node->child1());
12481 GPRTemporary result(this);
12482
12483 GPRReg sizeGPR = size.gpr();
12484 GPRReg resultGPR = result.gpr();
12485
12486 compileAllocateNewArrayWithSize(globalObject, resultGPR, sizeGPR, node->indexingType());
12487 cellResult(resultGPR, node);
12488 return;
12489 }
12490
12491 SpeculateStrictInt32Operand size(this, node->child1());
12492 GPRReg sizeGPR = size.gpr();
12493 flushRegisters();
12494 GPRFlushedCallResult result(this);
12495 GPRReg resultGPR = result.gpr();
12496 GPRReg structureGPR = AssemblyHelpers::selectScratchGPR(sizeGPR);
12497 MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH));
12498 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()))), structureGPR);
12499 MacroAssembler::Jump done = m_jit.jump();
12500 bigLength.link(&m_jit);
12501 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage))), structureGPR);
12502 done.link(&m_jit);
12503 callOperation(operationNewArrayWithSize, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), structureGPR, sizeGPR, nullptr);
12504 m_jit.exceptionCheck();
12505 cellResult(resultGPR, node);
12506}
12507
12508void SpeculativeJIT::compileNewTypedArray(Node* node)
12509{
12510 switch (node->child1().useKind()) {
12511 case Int32Use:
12512 compileNewTypedArrayWithSize(node);
12513 break;
12514 case UntypedUse: {
12515 JSValueOperand argument(this, node->child1());
12516 JSValueRegs argumentRegs = argument.jsValueRegs();
12517
12518 flushRegisters();
12519
12520 GPRFlushedCallResult result(this);
12521 GPRReg resultGPR = result.gpr();
12522
12523 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
12524 callOperation(
12525 operationNewTypedArrayWithOneArgumentForType(node->typedArrayType()),
12526 resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), m_jit.graph().registerStructure(globalObject->typedArrayStructureConcurrently(node->typedArrayType())), argumentRegs);
12527 m_jit.exceptionCheck();
12528
12529 cellResult(resultGPR, node);
12530 break;
12531 }
12532 default:
12533 RELEASE_ASSERT_NOT_REACHED();
12534 break;
12535 }
12536}
12537
12538void SpeculativeJIT::compileToThis(Node* node)
12539{
12540 ASSERT(node->child1().useKind() == UntypedUse);
12541 JSValueOperand thisValue(this, node->child1());
12542 JSValueRegsTemporary temp(this);
12543
12544 JSValueRegs thisValueRegs = thisValue.jsValueRegs();
12545 JSValueRegs tempRegs = temp.regs();
12546
12547 MacroAssembler::JumpList slowCases;
12548 slowCases.append(m_jit.branchIfNotCell(thisValueRegs));
12549 slowCases.append(
12550 m_jit.branchTest8(
12551 MacroAssembler::NonZero,
12552 MacroAssembler::Address(thisValueRegs.payloadGPR(), JSCell::typeInfoFlagsOffset()),
12553 MacroAssembler::TrustedImm32(OverridesToThis)));
12554 m_jit.moveValueRegs(thisValueRegs, tempRegs);
12555
12556 J_JITOperation_GJ function;
12557 if (m_jit.isStrictModeFor(node->origin.semantic))
12558 function = operationToThisStrict;
12559 else
12560 function = operationToThis;
12561 addSlowPathGenerator(slowPathCall(slowCases, this, function, tempRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), thisValueRegs));
12562
12563 jsValueResult(tempRegs, node);
12564}
12565
12566void SpeculativeJIT::compileObjectKeys(Node* node)
12567{
12568 switch (node->child1().useKind()) {
12569 case ObjectUse: {
12570 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
12571 SpeculateCellOperand object(this, node->child1());
12572 GPRTemporary structure(this);
12573 GPRTemporary scratch(this);
12574 GPRTemporary scratch2(this);
12575 GPRTemporary scratch3(this);
12576 GPRTemporary result(this);
12577
12578 GPRReg objectGPR = object.gpr();
12579 GPRReg structureGPR = structure.gpr();
12580 GPRReg scratchGPR = scratch.gpr();
12581 GPRReg scratch2GPR = scratch2.gpr();
12582 GPRReg scratch3GPR = scratch3.gpr();
12583 GPRReg resultGPR = result.gpr();
12584
12585 speculateObject(node->child1(), objectGPR);
12586
12587 CCallHelpers::JumpList slowCases;
12588 m_jit.emitLoadStructure(vm(), objectGPR, structureGPR, scratchGPR);
12589 m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::previousOrRareDataOffset()), scratchGPR);
12590
12591 slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR));
12592 slowCases.append(m_jit.branch32(CCallHelpers::Equal, CCallHelpers::Address(scratchGPR, JSCell::structureIDOffset()), TrustedImm32(bitwise_cast<int32_t>(vm().structureStructure->structureID()))));
12593
12594 m_jit.loadPtr(CCallHelpers::Address(scratchGPR, StructureRareData::offsetOfCachedOwnKeys()), scratchGPR);
12595
12596 ASSERT(bitwise_cast<uintptr_t>(StructureRareData::cachedOwnKeysSentinel()) == 1);
12597 slowCases.append(m_jit.branchPtr(CCallHelpers::BelowOrEqual, scratchGPR, TrustedImmPtr(bitwise_cast<void*>(StructureRareData::cachedOwnKeysSentinel()))));
12598
12599 MacroAssembler::JumpList slowButArrayBufferCases;
12600
12601 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
12602 RegisteredStructure arrayStructure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous));
12603
12604 m_jit.move(scratchGPR, scratch3GPR);
12605 m_jit.addPtr(TrustedImmPtr(JSImmutableButterfly::offsetOfData()), scratchGPR);
12606
12607 emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(arrayStructure), scratchGPR, structureGPR, scratch2GPR, slowButArrayBufferCases);
12608
12609 addSlowPathGenerator(slowPathCall(slowButArrayBufferCases, this, operationNewArrayBuffer, resultGPR, &vm(), arrayStructure, scratch3GPR));
12610
12611 addSlowPathGenerator(slowPathCall(slowCases, this, operationObjectKeysObject, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), objectGPR));
12612
12613 cellResult(resultGPR, node);
12614 break;
12615 }
12616
12617 SpeculateCellOperand object(this, node->child1());
12618
12619 GPRReg objectGPR = object.gpr();
12620
12621 speculateObject(node->child1(), objectGPR);
12622
12623 flushRegisters();
12624 GPRFlushedCallResult result(this);
12625 GPRReg resultGPR = result.gpr();
12626 callOperation(operationObjectKeysObject, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), objectGPR);
12627 m_jit.exceptionCheck();
12628
12629 cellResult(resultGPR, node);
12630 break;
12631 }
12632
12633 case UntypedUse: {
12634 JSValueOperand object(this, node->child1());
12635
12636 JSValueRegs objectRegs = object.jsValueRegs();
12637
12638 flushRegisters();
12639 GPRFlushedCallResult result(this);
12640 GPRReg resultGPR = result.gpr();
12641 callOperation(operationObjectKeys, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), objectRegs);
12642 m_jit.exceptionCheck();
12643
12644 cellResult(resultGPR, node);
12645 break;
12646 }
12647
12648 default:
12649 RELEASE_ASSERT_NOT_REACHED();
12650 break;
12651 }
12652}
12653
12654void SpeculativeJIT::compileObjectCreate(Node* node)
12655{
12656 switch (node->child1().useKind()) {
12657 case ObjectUse: {
12658 SpeculateCellOperand prototype(this, node->child1());
12659
12660 GPRReg prototypeGPR = prototype.gpr();
12661
12662 speculateObject(node->child1(), prototypeGPR);
12663
12664 flushRegisters();
12665 GPRFlushedCallResult result(this);
12666 GPRReg resultGPR = result.gpr();
12667 callOperation(operationObjectCreateObject, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), prototypeGPR);
12668 m_jit.exceptionCheck();
12669
12670 cellResult(resultGPR, node);
12671 break;
12672 }
12673
12674 case UntypedUse: {
12675 JSValueOperand prototype(this, node->child1());
12676
12677 JSValueRegs prototypeRegs = prototype.jsValueRegs();
12678
12679 flushRegisters();
12680 GPRFlushedCallResult result(this);
12681 GPRReg resultGPR = result.gpr();
12682 callOperation(operationObjectCreate, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), prototypeRegs);
12683 m_jit.exceptionCheck();
12684
12685 cellResult(resultGPR, node);
12686 break;
12687 }
12688
12689 default:
12690 RELEASE_ASSERT_NOT_REACHED();
12691 break;
12692 }
12693}
12694
12695void SpeculativeJIT::compileCreateThis(Node* node)
12696{
12697 // Note that there is not so much profit to speculate here. The only things we
12698 // speculate on are (1) that it's a cell, since that eliminates cell checks
12699 // later if the proto is reused, and (2) if we have a FinalObject prediction
12700 // then we speculate because we want to get recompiled if it isn't (since
12701 // otherwise we'd start taking slow path a lot).
12702
12703 SpeculateCellOperand callee(this, node->child1());
12704 GPRTemporary result(this);
12705 GPRTemporary allocator(this);
12706 GPRTemporary structure(this);
12707 GPRTemporary scratch(this);
12708
12709 GPRReg calleeGPR = callee.gpr();
12710 GPRReg resultGPR = result.gpr();
12711 GPRReg allocatorGPR = allocator.gpr();
12712 GPRReg structureGPR = structure.gpr();
12713 GPRReg scratchGPR = scratch.gpr();
12714 // Rare data is only used to access the allocator & structure
12715 // We can avoid using an additional GPR this way
12716 GPRReg rareDataGPR = structureGPR;
12717 GPRReg inlineCapacityGPR = rareDataGPR;
12718
12719 MacroAssembler::JumpList slowPath;
12720
12721 slowPath.append(m_jit.branchIfNotFunction(calleeGPR));
12722 m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfRareData()), rareDataGPR);
12723 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, rareDataGPR));
12724 m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfileWithPrototype::offsetOfAllocator()), allocatorGPR);
12725 m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfileWithPrototype::offsetOfStructure()), structureGPR);
12726
12727 auto butterfly = TrustedImmPtr(nullptr);
12728 emitAllocateJSObject(resultGPR, JITAllocator::variable(), allocatorGPR, structureGPR, butterfly, scratchGPR, slowPath);
12729
12730 m_jit.load8(JITCompiler::Address(structureGPR, Structure::inlineCapacityOffset()), inlineCapacityGPR);
12731 m_jit.emitInitializeInlineStorage(resultGPR, inlineCapacityGPR);
12732 m_jit.mutatorFence(vm());
12733
12734 addSlowPathGenerator(slowPathCall(slowPath, this, operationCreateThis, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), calleeGPR, node->inlineCapacity()));
12735
12736 cellResult(resultGPR, node);
12737}
12738
12739void SpeculativeJIT::compileCreatePromise(Node* node)
12740{
12741 JSGlobalObject* globalObject = m_jit.globalObjectFor(node->origin.semantic);
12742
12743 SpeculateCellOperand callee(this, node->child1());
12744 GPRTemporary result(this);
12745 GPRTemporary structure(this);
12746 GPRTemporary scratch1(this);
12747 GPRTemporary scratch2(this);
12748
12749 GPRReg calleeGPR = callee.gpr();
12750 GPRReg resultGPR = result.gpr();
12751 GPRReg structureGPR = structure.gpr();
12752 GPRReg scratch1GPR = scratch1.gpr();
12753 GPRReg scratch2GPR = scratch2.gpr();
12754 // Rare data is only used to access the allocator & structure
12755 // We can avoid using an additional GPR this way
12756 GPRReg rareDataGPR = structureGPR;
12757
12758 m_jit.move(TrustedImmPtr(m_jit.graph().registerStructure(node->isInternalPromise() ? globalObject->internalPromiseStructure() : globalObject->promiseStructure())), structureGPR);
12759 auto fastPromisePath = m_jit.branchPtr(CCallHelpers::Equal, calleeGPR, TrustedImmPtr::weakPointer(m_jit.graph(), node->isInternalPromise() ? globalObject->internalPromiseConstructor() : globalObject->promiseConstructor()));
12760
12761 MacroAssembler::JumpList slowCases;
12762
12763 slowCases.append(m_jit.branchIfNotFunction(calleeGPR));
12764 m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfRareData()), rareDataGPR);
12765 slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, rareDataGPR));
12766 m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfInternalFunctionAllocationProfile() + InternalFunctionAllocationProfile::offsetOfStructure()), structureGPR);
12767 slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, structureGPR));
12768 m_jit.move(TrustedImmPtr(node->isInternalPromise() ? JSInternalPromise::info() : JSPromise::info()), scratch1GPR);
12769 slowCases.append(m_jit.branchPtr(CCallHelpers::NotEqual, scratch1GPR, CCallHelpers::Address(structureGPR, Structure::classInfoOffset())));
12770 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), globalObject), scratch1GPR);
12771 slowCases.append(m_jit.branchPtr(CCallHelpers::NotEqual, scratch1GPR, CCallHelpers::Address(structureGPR, Structure::globalObjectOffset())));
12772
12773 fastPromisePath.link(&m_jit);
12774 auto butterfly = TrustedImmPtr(nullptr);
12775 if (node->isInternalPromise())
12776 emitAllocateJSObjectWithKnownSize<JSInternalPromise>(resultGPR, structureGPR, butterfly, scratch1GPR, scratch2GPR, slowCases, sizeof(JSInternalPromise));
12777 else
12778 emitAllocateJSObjectWithKnownSize<JSPromise>(resultGPR, structureGPR, butterfly, scratch1GPR, scratch2GPR, slowCases, sizeof(JSPromise));
12779 m_jit.storeTrustedValue(jsNumber(static_cast<unsigned>(JSPromise::Status::Pending)), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSPromise::Field::Flags))));
12780 m_jit.storeTrustedValue(jsUndefined(), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSPromise::Field::ReactionsOrResult))));
12781 m_jit.mutatorFence(m_jit.vm());
12782
12783 addSlowPathGenerator(slowPathCall(slowCases, this, node->isInternalPromise() ? operationCreateInternalPromise : operationCreatePromise, resultGPR, TrustedImmPtr::weakPointer(m_jit.graph(), globalObject), calleeGPR));
12784
12785 cellResult(resultGPR, node);
12786}
12787
12788
12789template<typename JSClass, typename Operation>
12790void SpeculativeJIT::compileCreateInternalFieldObject(Node* node, Operation operation)
12791{
12792 JSGlobalObject* globalObject = m_jit.globalObjectFor(node->origin.semantic);
12793
12794 SpeculateCellOperand callee(this, node->child1());
12795 GPRTemporary result(this);
12796 GPRTemporary structure(this);
12797 GPRTemporary scratch1(this);
12798 GPRTemporary scratch2(this);
12799
12800 GPRReg calleeGPR = callee.gpr();
12801 GPRReg resultGPR = result.gpr();
12802 GPRReg structureGPR = structure.gpr();
12803 GPRReg scratch1GPR = scratch1.gpr();
12804 GPRReg scratch2GPR = scratch2.gpr();
12805 // Rare data is only used to access the allocator & structure
12806 // We can avoid using an additional GPR this way
12807 GPRReg rareDataGPR = structureGPR;
12808
12809 MacroAssembler::JumpList slowCases;
12810
12811 slowCases.append(m_jit.branchIfNotFunction(calleeGPR));
12812 m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfRareData()), rareDataGPR);
12813 slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, rareDataGPR));
12814 m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfInternalFunctionAllocationProfile() + InternalFunctionAllocationProfile::offsetOfStructure()), structureGPR);
12815 slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, structureGPR));
12816 m_jit.move(TrustedImmPtr(JSClass::info()), scratch1GPR);
12817 slowCases.append(m_jit.branchPtr(CCallHelpers::NotEqual, scratch1GPR, CCallHelpers::Address(structureGPR, Structure::classInfoOffset())));
12818 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), globalObject), scratch1GPR);
12819 slowCases.append(m_jit.branchPtr(CCallHelpers::NotEqual, scratch1GPR, CCallHelpers::Address(structureGPR, Structure::globalObjectOffset())));
12820
12821 auto butterfly = TrustedImmPtr(nullptr);
12822 emitAllocateJSObjectWithKnownSize<JSClass>(resultGPR, structureGPR, butterfly, scratch1GPR, scratch2GPR, slowCases, sizeof(JSClass));
12823 auto initialValues = JSClass::initialValues();
12824 ASSERT(initialValues.size() == JSClass::numberOfInternalFields);
12825 for (unsigned index = 0; index < initialValues.size(); ++index)
12826 m_jit.storeTrustedValue(initialValues[index], CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(index)));
12827 m_jit.mutatorFence(m_jit.vm());
12828
12829 addSlowPathGenerator(slowPathCall(slowCases, this, operation, resultGPR, TrustedImmPtr::weakPointer(m_jit.graph(), globalObject), calleeGPR));
12830
12831 cellResult(resultGPR, node);
12832}
12833
12834void SpeculativeJIT::compileCreateGenerator(Node* node)
12835{
12836 compileCreateInternalFieldObject<JSGenerator>(node, operationCreateGenerator);
12837}
12838
12839void SpeculativeJIT::compileCreateAsyncGenerator(Node* node)
12840{
12841 compileCreateInternalFieldObject<JSAsyncGenerator>(node, operationCreateAsyncGenerator);
12842}
12843
12844void SpeculativeJIT::compileNewObject(Node* node)
12845{
12846 GPRTemporary result(this);
12847 GPRTemporary allocator(this);
12848 GPRTemporary scratch(this);
12849
12850 GPRReg resultGPR = result.gpr();
12851 GPRReg allocatorGPR = allocator.gpr();
12852 GPRReg scratchGPR = scratch.gpr();
12853
12854 MacroAssembler::JumpList slowPath;
12855
12856 RegisteredStructure structure = node->structure();
12857 size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity());
12858 Allocator allocatorValue = allocatorForNonVirtualConcurrently<JSFinalObject>(vm(), allocationSize, AllocatorForMode::AllocatorIfExists);
12859 if (!allocatorValue)
12860 slowPath.append(m_jit.jump());
12861 else {
12862 auto butterfly = TrustedImmPtr(nullptr);
12863 emitAllocateJSObject(resultGPR, JITAllocator::constant(allocatorValue), allocatorGPR, TrustedImmPtr(structure), butterfly, scratchGPR, slowPath);
12864 m_jit.emitInitializeInlineStorage(resultGPR, structure->inlineCapacity());
12865 m_jit.mutatorFence(vm());
12866 }
12867
12868 addSlowPathGenerator(slowPathCall(slowPath, this, operationNewObject, resultGPR, &vm(), structure));
12869
12870 cellResult(resultGPR, node);
12871}
12872
12873void SpeculativeJIT::compileNewPromise(Node* node)
12874{
12875 GPRTemporary result(this);
12876 GPRTemporary scratch1(this);
12877 GPRTemporary scratch2(this);
12878
12879 GPRReg resultGPR = result.gpr();
12880 GPRReg scratch1GPR = scratch1.gpr();
12881 GPRReg scratch2GPR = scratch2.gpr();
12882
12883 MacroAssembler::JumpList slowCases;
12884
12885 FrozenValue* structure = m_graph.freezeStrong(node->structure().get());
12886 auto butterfly = TrustedImmPtr(nullptr);
12887 if (node->isInternalPromise())
12888 emitAllocateJSObjectWithKnownSize<JSInternalPromise>(resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR, slowCases, sizeof(JSInternalPromise));
12889 else
12890 emitAllocateJSObjectWithKnownSize<JSPromise>(resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR, slowCases, sizeof(JSPromise));
12891 m_jit.storeTrustedValue(jsNumber(static_cast<unsigned>(JSPromise::Status::Pending)), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSPromise::Field::Flags))));
12892 m_jit.storeTrustedValue(jsUndefined(), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSPromise::Field::ReactionsOrResult))));
12893 m_jit.mutatorFence(m_jit.vm());
12894
12895 addSlowPathGenerator(slowPathCall(slowCases, this, node->isInternalPromise() ? operationNewInternalPromise : operationNewPromise, resultGPR, TrustedImmPtr(&vm()), TrustedImmPtr(structure)));
12896
12897 cellResult(resultGPR, node);
12898}
12899
12900template<typename JSClass, typename Operation>
12901void SpeculativeJIT::compileNewInternalFieldObject(Node* node, Operation operation)
12902{
12903 GPRTemporary result(this);
12904 GPRTemporary scratch1(this);
12905 GPRTemporary scratch2(this);
12906
12907 GPRReg resultGPR = result.gpr();
12908 GPRReg scratch1GPR = scratch1.gpr();
12909 GPRReg scratch2GPR = scratch2.gpr();
12910
12911 MacroAssembler::JumpList slowCases;
12912
12913 FrozenValue* structure = m_graph.freezeStrong(node->structure().get());
12914 auto butterfly = TrustedImmPtr(nullptr);
12915 emitAllocateJSObjectWithKnownSize<JSClass>(resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR, slowCases, sizeof(JSClass));
12916 auto initialValues = JSClass::initialValues();
12917 ASSERT(initialValues.size() == JSClass::numberOfInternalFields);
12918 for (unsigned index = 0; index < initialValues.size(); ++index)
12919 m_jit.storeTrustedValue(initialValues[index], CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(index)));
12920 m_jit.mutatorFence(m_jit.vm());
12921
12922 addSlowPathGenerator(slowPathCall(slowCases, this, operation, resultGPR, &vm(), TrustedImmPtr(structure)));
12923
12924 cellResult(resultGPR, node);
12925}
12926
12927void SpeculativeJIT::compileNewGenerator(Node* node)
12928{
12929 compileNewInternalFieldObject<JSGenerator>(node, operationNewGenerator);
12930}
12931
12932void SpeculativeJIT::compileNewAsyncGenerator(Node* node)
12933{
12934 compileNewInternalFieldObject<JSAsyncGenerator>(node, operationNewAsyncGenerator);
12935}
12936
12937void SpeculativeJIT::compileToPrimitive(Node* node)
12938{
12939 DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse, node->child1().useKind());
12940 JSValueOperand argument(this, node->child1());
12941 JSValueRegsTemporary result(this, Reuse, argument);
12942
12943 JSValueRegs argumentRegs = argument.jsValueRegs();
12944 JSValueRegs resultRegs = result.regs();
12945
12946 argument.use();
12947
12948 MacroAssembler::Jump alreadyPrimitive = m_jit.branchIfNotCell(argumentRegs);
12949 MacroAssembler::Jump notPrimitive = m_jit.branchIfObject(argumentRegs.payloadGPR());
12950
12951 alreadyPrimitive.link(&m_jit);
12952 m_jit.moveValueRegs(argumentRegs, resultRegs);
12953
12954 addSlowPathGenerator(slowPathCall(notPrimitive, this, operationToPrimitive, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), argumentRegs));
12955
12956 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
12957}
12958
12959void SpeculativeJIT::compileToNumeric(Node* node)
12960{
12961 DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse, node->child1().useKind());
12962 JSValueOperand argument(this, node->child1());
12963 JSValueRegsTemporary result(this);
12964 GPRTemporary temp(this);
12965
12966 JSValueRegs argumentRegs = argument.jsValueRegs();
12967 JSValueRegs resultRegs = result.regs();
12968 GPRReg scratch = temp.gpr();
12969
12970 MacroAssembler::JumpList slowCases;
12971
12972 MacroAssembler::Jump notCell = m_jit.branchIfNotCell(argumentRegs);
12973 slowCases.append(m_jit.branchIfNotBigInt(argumentRegs.payloadGPR()));
12974 MacroAssembler::Jump isBigInt = m_jit.jump();
12975
12976 notCell.link(&m_jit);
12977 slowCases.append(m_jit.branchIfNotNumber(argumentRegs, scratch));
12978
12979 isBigInt.link(&m_jit);
12980 m_jit.moveValueRegs(argumentRegs, resultRegs);
12981
12982 addSlowPathGenerator(slowPathCall(slowCases, this, operationToNumeric, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), argumentRegs));
12983
12984 jsValueResult(resultRegs, node, DataFormatJS);
12985}
12986
12987void SpeculativeJIT::compileLogShadowChickenPrologue(Node* node)
12988{
12989 flushRegisters();
12990 prepareForExternalCall();
12991 m_jit.emitStoreCodeOrigin(node->origin.semantic);
12992
12993 GPRTemporary scratch1(this, GPRInfo::nonArgGPR0); // This must be a non-argument GPR.
12994 GPRReg scratch1Reg = scratch1.gpr();
12995 GPRTemporary scratch2(this);
12996 GPRReg scratch2Reg = scratch2.gpr();
12997 GPRTemporary shadowPacket(this);
12998 GPRReg shadowPacketReg = shadowPacket.gpr();
12999
13000 m_jit.ensureShadowChickenPacket(vm(), shadowPacketReg, scratch1Reg, scratch2Reg);
13001
13002 SpeculateCellOperand scope(this, node->child1());
13003 GPRReg scopeReg = scope.gpr();
13004
13005 m_jit.logShadowChickenProloguePacket(shadowPacketReg, scratch1Reg, scopeReg);
13006 noResult(node);
13007}
13008
13009void SpeculativeJIT::compileLogShadowChickenTail(Node* node)
13010{
13011 flushRegisters();
13012 prepareForExternalCall();
13013 CallSiteIndex callSiteIndex = m_jit.emitStoreCodeOrigin(node->origin.semantic);
13014
13015 GPRTemporary scratch1(this, GPRInfo::nonArgGPR0); // This must be a non-argument GPR.
13016 GPRReg scratch1Reg = scratch1.gpr();
13017 GPRTemporary scratch2(this);
13018 GPRReg scratch2Reg = scratch2.gpr();
13019 GPRTemporary shadowPacket(this);
13020 GPRReg shadowPacketReg = shadowPacket.gpr();
13021
13022 m_jit.ensureShadowChickenPacket(vm(), shadowPacketReg, scratch1Reg, scratch2Reg);
13023
13024 JSValueOperand thisValue(this, node->child1());
13025 JSValueRegs thisRegs = thisValue.jsValueRegs();
13026 SpeculateCellOperand scope(this, node->child2());
13027 GPRReg scopeReg = scope.gpr();
13028
13029 m_jit.logShadowChickenTailPacket(shadowPacketReg, thisRegs, scopeReg, m_jit.codeBlock(), callSiteIndex);
13030 noResult(node);
13031}
13032
13033void SpeculativeJIT::compileSetAdd(Node* node)
13034{
13035 SpeculateCellOperand set(this, node->child1());
13036 JSValueOperand key(this, node->child2());
13037 SpeculateInt32Operand hash(this, node->child3());
13038
13039 GPRReg setGPR = set.gpr();
13040 JSValueRegs keyRegs = key.jsValueRegs();
13041 GPRReg hashGPR = hash.gpr();
13042
13043 speculateSetObject(node->child1(), setGPR);
13044
13045 flushRegisters();
13046 GPRFlushedCallResult result(this);
13047 GPRReg resultGPR = result.gpr();
13048 callOperation(operationSetAdd, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), setGPR, keyRegs, hashGPR);
13049 m_jit.exceptionCheck();
13050 cellResult(resultGPR, node);
13051}
13052
13053void SpeculativeJIT::compileMapSet(Node* node)
13054{
13055 SpeculateCellOperand map(this, m_jit.graph().varArgChild(node, 0));
13056 JSValueOperand key(this, m_jit.graph().varArgChild(node, 1));
13057 JSValueOperand value(this, m_jit.graph().varArgChild(node, 2));
13058 SpeculateInt32Operand hash(this, m_jit.graph().varArgChild(node, 3));
13059
13060 GPRReg mapGPR = map.gpr();
13061 JSValueRegs keyRegs = key.jsValueRegs();
13062 JSValueRegs valueRegs = value.jsValueRegs();
13063 GPRReg hashGPR = hash.gpr();
13064
13065 speculateMapObject(m_jit.graph().varArgChild(node, 0), mapGPR);
13066
13067 flushRegisters();
13068 GPRFlushedCallResult result(this);
13069 GPRReg resultGPR = result.gpr();
13070 callOperation(operationMapSet, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), mapGPR, keyRegs, valueRegs, hashGPR);
13071 m_jit.exceptionCheck();
13072 cellResult(resultGPR, node);
13073}
13074
13075void SpeculativeJIT::compileWeakMapGet(Node* node)
13076{
13077 GPRTemporary mask(this);
13078 GPRTemporary buffer(this);
13079 JSValueRegsTemporary result(this);
13080
13081 GPRReg maskGPR = mask.gpr();
13082 GPRReg bufferGPR = buffer.gpr();
13083 JSValueRegs resultRegs = result.regs();
13084
13085 GPRTemporary index;
13086 GPRReg indexGPR { InvalidGPRReg };
13087 {
13088 SpeculateInt32Operand hash(this, node->child3());
13089 GPRReg hashGPR = hash.gpr();
13090 index = GPRTemporary(this, Reuse, hash);
13091 indexGPR = index.gpr();
13092 m_jit.move(hashGPR, indexGPR);
13093 }
13094
13095 {
13096 SpeculateCellOperand weakMap(this, node->child1());
13097 GPRReg weakMapGPR = weakMap.gpr();
13098 if (node->child1().useKind() == WeakMapObjectUse)
13099 speculateWeakMapObject(node->child1(), weakMapGPR);
13100 else
13101 speculateWeakSetObject(node->child1(), weakMapGPR);
13102
13103 ASSERT(WeakMapImpl<WeakMapBucket<WeakMapBucketDataKey>>::offsetOfCapacity() == WeakMapImpl<WeakMapBucket<WeakMapBucketDataKeyValue>>::offsetOfCapacity());
13104 ASSERT(WeakMapImpl<WeakMapBucket<WeakMapBucketDataKey>>::offsetOfBuffer() == WeakMapImpl<WeakMapBucket<WeakMapBucketDataKeyValue>>::offsetOfBuffer());
13105 m_jit.load32(MacroAssembler::Address(weakMapGPR, WeakMapImpl<WeakMapBucket<WeakMapBucketDataKey>>::offsetOfCapacity()), maskGPR);
13106 m_jit.loadPtr(MacroAssembler::Address(weakMapGPR, WeakMapImpl<WeakMapBucket<WeakMapBucketDataKey>>::offsetOfBuffer()), bufferGPR);
13107 }
13108
13109 SpeculateCellOperand key(this, node->child2());
13110 GPRReg keyGPR = key.gpr();
13111 speculateObject(node->child2(), keyGPR);
13112
13113#if USE(JSVALUE32_64)
13114 GPRReg bucketGPR = resultRegs.tagGPR();
13115#else
13116 GPRTemporary bucket(this);
13117 GPRReg bucketGPR = bucket.gpr();
13118#endif
13119
13120 m_jit.sub32(TrustedImm32(1), maskGPR);
13121
13122 MacroAssembler::Label loop = m_jit.label();
13123 m_jit.and32(maskGPR, indexGPR);
13124 if (node->child1().useKind() == WeakSetObjectUse) {
13125 static_assert(sizeof(WeakMapBucket<WeakMapBucketDataKey>) == sizeof(void*), "");
13126 m_jit.zeroExtend32ToPtr(indexGPR, bucketGPR);
13127 m_jit.lshiftPtr(MacroAssembler::Imm32(sizeof(void*) == 4 ? 2 : 3), bucketGPR);
13128 m_jit.addPtr(bufferGPR, bucketGPR);
13129 } else {
13130 ASSERT(node->child1().useKind() == WeakMapObjectUse);
13131 static_assert(sizeof(WeakMapBucket<WeakMapBucketDataKeyValue>) == 16, "");
13132 m_jit.zeroExtend32ToPtr(indexGPR, bucketGPR);
13133 m_jit.lshiftPtr(MacroAssembler::Imm32(4), bucketGPR);
13134 m_jit.addPtr(bufferGPR, bucketGPR);
13135 }
13136
13137 m_jit.loadPtr(MacroAssembler::Address(bucketGPR, WeakMapBucket<WeakMapBucketDataKeyValue>::offsetOfKey()), resultRegs.payloadGPR());
13138
13139 // They're definitely the same value, we found the bucket we were looking for!
13140 // The deleted key comparison is also done with this.
13141 auto found = m_jit.branchPtr(MacroAssembler::Equal, resultRegs.payloadGPR(), keyGPR);
13142
13143 auto notPresentInTable = m_jit.branchTestPtr(MacroAssembler::Zero, resultRegs.payloadGPR());
13144
13145 m_jit.add32(TrustedImm32(1), indexGPR);
13146 m_jit.jump().linkTo(loop, &m_jit);
13147
13148#if USE(JSVALUE32_64)
13149 notPresentInTable.link(&m_jit);
13150 m_jit.moveValue(JSValue(), resultRegs);
13151 auto notPresentInTableDone = m_jit.jump();
13152
13153 found.link(&m_jit);
13154 if (node->child1().useKind() == WeakSetObjectUse)
13155 m_jit.move(TrustedImm32(JSValue::CellTag), resultRegs.tagGPR());
13156 else
13157 m_jit.loadValue(MacroAssembler::Address(bucketGPR, WeakMapBucket<WeakMapBucketDataKeyValue>::offsetOfValue()), resultRegs);
13158
13159 notPresentInTableDone.link(&m_jit);
13160#else
13161 notPresentInTable.link(&m_jit);
13162 found.link(&m_jit);
13163
13164 // In 64bit environment, Empty bucket has JSEmpty value. Empty key is JSEmpty.
13165 // If empty bucket is found, we can use the same path used for the case of finding a bucket.
13166 if (node->child1().useKind() == WeakMapObjectUse)
13167 m_jit.loadValue(MacroAssembler::Address(bucketGPR, WeakMapBucket<WeakMapBucketDataKeyValue>::offsetOfValue()), resultRegs);
13168#endif
13169
13170 jsValueResult(resultRegs, node);
13171}
13172
13173void SpeculativeJIT::compileWeakSetAdd(Node* node)
13174{
13175 SpeculateCellOperand set(this, node->child1());
13176 SpeculateCellOperand key(this, node->child2());
13177 SpeculateInt32Operand hash(this, node->child3());
13178
13179 GPRReg setGPR = set.gpr();
13180 GPRReg keyGPR = key.gpr();
13181 GPRReg hashGPR = hash.gpr();
13182
13183 speculateWeakSetObject(node->child1(), setGPR);
13184 speculateObject(node->child2(), keyGPR);
13185
13186 flushRegisters();
13187 callOperation(operationWeakSetAdd, &vm(), setGPR, keyGPR, hashGPR);
13188 m_jit.exceptionCheck();
13189 noResult(node);
13190}
13191
13192void SpeculativeJIT::compileWeakMapSet(Node* node)
13193{
13194 SpeculateCellOperand map(this, m_jit.graph().varArgChild(node, 0));
13195 SpeculateCellOperand key(this, m_jit.graph().varArgChild(node, 1));
13196 JSValueOperand value(this, m_jit.graph().varArgChild(node, 2));
13197 SpeculateInt32Operand hash(this, m_jit.graph().varArgChild(node, 3));
13198
13199 GPRReg mapGPR = map.gpr();
13200 GPRReg keyGPR = key.gpr();
13201 JSValueRegs valueRegs = value.jsValueRegs();
13202 GPRReg hashGPR = hash.gpr();
13203
13204 speculateWeakMapObject(m_jit.graph().varArgChild(node, 0), mapGPR);
13205 speculateObject(m_jit.graph().varArgChild(node, 1), keyGPR);
13206
13207 flushRegisters();
13208 callOperation(operationWeakMapSet, &vm(), mapGPR, keyGPR, valueRegs, hashGPR);
13209 m_jit.exceptionCheck();
13210 noResult(node);
13211}
13212
13213void SpeculativeJIT::compileGetPrototypeOf(Node* node)
13214{
13215 switch (node->child1().useKind()) {
13216 case ArrayUse:
13217 case FunctionUse:
13218 case FinalObjectUse: {
13219 SpeculateCellOperand object(this, node->child1());
13220 GPRTemporary temp(this);
13221 GPRTemporary temp2(this);
13222
13223 GPRReg objectGPR = object.gpr();
13224 GPRReg tempGPR = temp.gpr();
13225 GPRReg temp2GPR = temp2.gpr();
13226
13227 switch (node->child1().useKind()) {
13228 case ArrayUse:
13229 speculateArray(node->child1(), objectGPR);
13230 break;
13231 case FunctionUse:
13232 speculateFunction(node->child1(), objectGPR);
13233 break;
13234 case FinalObjectUse:
13235 speculateFinalObject(node->child1(), objectGPR);
13236 break;
13237 default:
13238 RELEASE_ASSERT_NOT_REACHED();
13239 break;
13240 }
13241
13242 m_jit.emitLoadStructure(vm(), objectGPR, tempGPR, temp2GPR);
13243
13244 AbstractValue& value = m_state.forNode(node->child1());
13245 if ((value.m_type && !(value.m_type & ~SpecObject)) && value.m_structure.isFinite()) {
13246 bool hasPolyProto = false;
13247 bool hasMonoProto = false;
13248 value.m_structure.forEach([&] (RegisteredStructure structure) {
13249 if (structure->hasPolyProto())
13250 hasPolyProto = true;
13251 else
13252 hasMonoProto = true;
13253 });
13254
13255 if (hasMonoProto && !hasPolyProto) {
13256#if USE(JSVALUE64)
13257 m_jit.load64(MacroAssembler::Address(tempGPR, Structure::prototypeOffset()), tempGPR);
13258 jsValueResult(tempGPR, node);
13259#else
13260 m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + TagOffset), temp2GPR);
13261 m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + PayloadOffset), tempGPR);
13262 jsValueResult(temp2GPR, tempGPR, node);
13263#endif
13264 return;
13265 }
13266
13267 if (hasPolyProto && !hasMonoProto) {
13268#if USE(JSVALUE64)
13269 m_jit.load64(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset)), tempGPR);
13270 jsValueResult(tempGPR, node);
13271#else
13272 m_jit.load32(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset) + TagOffset), temp2GPR);
13273 m_jit.load32(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset) + PayloadOffset), tempGPR);
13274 jsValueResult(temp2GPR, tempGPR, node);
13275#endif
13276 return;
13277 }
13278 }
13279
13280#if USE(JSVALUE64)
13281 m_jit.load64(MacroAssembler::Address(tempGPR, Structure::prototypeOffset()), tempGPR);
13282 auto hasMonoProto = m_jit.branchIfNotEmpty(tempGPR);
13283 m_jit.load64(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset)), tempGPR);
13284 hasMonoProto.link(&m_jit);
13285 jsValueResult(tempGPR, node);
13286#else
13287 m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + TagOffset), temp2GPR);
13288 m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + PayloadOffset), tempGPR);
13289 auto hasMonoProto = m_jit.branchIfNotEmpty(temp2GPR);
13290 m_jit.load32(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset) + TagOffset), temp2GPR);
13291 m_jit.load32(JITCompiler::Address(objectGPR, offsetRelativeToBase(knownPolyProtoOffset) + PayloadOffset), tempGPR);
13292 hasMonoProto.link(&m_jit);
13293 jsValueResult(temp2GPR, tempGPR, node);
13294#endif
13295 return;
13296 }
13297 case ObjectUse: {
13298 SpeculateCellOperand value(this, node->child1());
13299 JSValueRegsTemporary result(this);
13300
13301 GPRReg valueGPR = value.gpr();
13302 JSValueRegs resultRegs = result.regs();
13303
13304 speculateObject(node->child1(), valueGPR);
13305
13306 flushRegisters();
13307 callOperation(operationGetPrototypeOfObject, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueGPR);
13308 m_jit.exceptionCheck();
13309 jsValueResult(resultRegs, node);
13310 return;
13311 }
13312 default: {
13313 JSValueOperand value(this, node->child1());
13314 JSValueRegsTemporary result(this);
13315
13316 JSValueRegs valueRegs = value.jsValueRegs();
13317 JSValueRegs resultRegs = result.regs();
13318
13319 flushRegisters();
13320 callOperation(operationGetPrototypeOf, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), valueRegs);
13321 m_jit.exceptionCheck();
13322 jsValueResult(resultRegs, node);
13323 return;
13324 }
13325 }
13326}
13327
13328void SpeculativeJIT::compileIdentity(Node* node)
13329{
13330 speculate(node, node->child1());
13331 switch (node->child1().useKind()) {
13332#if USE(JSVALUE64)
13333 case DoubleRepAnyIntUse:
13334#endif
13335 case DoubleRepUse:
13336 case DoubleRepRealUse: {
13337 SpeculateDoubleOperand op(this, node->child1());
13338 FPRTemporary scratch(this, op);
13339 m_jit.moveDouble(op.fpr(), scratch.fpr());
13340 doubleResult(scratch.fpr(), node);
13341 break;
13342 }
13343#if USE(JSVALUE64)
13344 case Int52RepUse: {
13345 SpeculateInt52Operand op(this, node->child1());
13346 GPRTemporary result(this, Reuse, op);
13347 m_jit.move(op.gpr(), result.gpr());
13348 int52Result(result.gpr(), node);
13349 break;
13350 }
13351#endif
13352 default: {
13353 JSValueOperand op(this, node->child1(), ManualOperandSpeculation);
13354 JSValueRegsTemporary result(this, Reuse, op);
13355 JSValueRegs opRegs = op.jsValueRegs();
13356 JSValueRegs resultRegs = result.regs();
13357 m_jit.moveValueRegs(opRegs, resultRegs);
13358 jsValueResult(resultRegs, node);
13359 break;
13360 }
13361 }
13362}
13363
13364void SpeculativeJIT::compileMiscStrictEq(Node* node)
13365{
13366 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
13367 JSValueOperand op2(this, node->child2(), ManualOperandSpeculation);
13368 GPRTemporary result(this);
13369
13370 if (node->child1().useKind() == MiscUse)
13371 speculateMisc(node->child1(), op1.jsValueRegs());
13372 if (node->child2().useKind() == MiscUse)
13373 speculateMisc(node->child2(), op2.jsValueRegs());
13374
13375#if USE(JSVALUE64)
13376 m_jit.compare64(JITCompiler::Equal, op1.gpr(), op2.gpr(), result.gpr());
13377#else
13378 m_jit.move(TrustedImm32(0), result.gpr());
13379 JITCompiler::Jump notEqual = m_jit.branch32(JITCompiler::NotEqual, op1.tagGPR(), op2.tagGPR());
13380 m_jit.compare32(JITCompiler::Equal, op1.payloadGPR(), op2.payloadGPR(), result.gpr());
13381 notEqual.link(&m_jit);
13382#endif
13383 unblessedBooleanResult(result.gpr(), node);
13384}
13385
13386void SpeculativeJIT::emitInitializeButterfly(GPRReg storageGPR, GPRReg sizeGPR, JSValueRegs emptyValueRegs, GPRReg scratchGPR)
13387{
13388 m_jit.zeroExtend32ToPtr(sizeGPR, scratchGPR);
13389 MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratchGPR);
13390 MacroAssembler::Label loop = m_jit.label();
13391 m_jit.sub32(TrustedImm32(1), scratchGPR);
13392 m_jit.storeValue(emptyValueRegs, MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight));
13393 m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
13394 done.link(&m_jit);
13395}
13396
13397void SpeculativeJIT::compileAllocateNewArrayWithSize(JSGlobalObject* globalObject, GPRReg resultGPR, GPRReg sizeGPR, IndexingType indexingType, bool shouldConvertLargeSizeToArrayStorage)
13398{
13399 GPRTemporary storage(this);
13400 GPRTemporary scratch(this);
13401 GPRTemporary scratch2(this);
13402
13403 GPRReg storageGPR = storage.gpr();
13404 GPRReg scratchGPR = scratch.gpr();
13405 GPRReg scratch2GPR = scratch2.gpr();
13406
13407 m_jit.move(TrustedImmPtr(nullptr), storageGPR);
13408
13409 MacroAssembler::JumpList slowCases;
13410 if (shouldConvertLargeSizeToArrayStorage)
13411 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)));
13412#if !ASSERT_DISABLED
13413 else {
13414 MacroAssembler::Jump lengthIsWithinLimits;
13415 lengthIsWithinLimits = m_jit.branch32(MacroAssembler::Below, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH));
13416 m_jit.abortWithReason(UncheckedOverflow);
13417 lengthIsWithinLimits.link(&m_jit);
13418 }
13419#endif
13420
13421 // We can use resultGPR as a scratch right now.
13422 emitAllocateButterfly(storageGPR, sizeGPR, scratchGPR, scratch2GPR, resultGPR, slowCases);
13423
13424#if USE(JSVALUE64)
13425 JSValueRegs emptyValueRegs(scratchGPR);
13426 if (hasDouble(indexingType))
13427 m_jit.move(TrustedImm64(bitwise_cast<int64_t>(PNaN)), emptyValueRegs.gpr());
13428 else
13429 m_jit.move(TrustedImm64(JSValue::encode(JSValue())), emptyValueRegs.gpr());
13430#else
13431 JSValueRegs emptyValueRegs(scratchGPR, scratch2GPR);
13432 if (hasDouble(indexingType))
13433 m_jit.moveValue(JSValue(JSValue::EncodeAsDouble, PNaN), emptyValueRegs);
13434 else
13435 m_jit.moveValue(JSValue(), emptyValueRegs);
13436#endif
13437 emitInitializeButterfly(storageGPR, sizeGPR, emptyValueRegs, resultGPR);
13438
13439 RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType));
13440
13441 emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
13442
13443 m_jit.mutatorFence(vm());
13444
13445 addSlowPathGenerator(makeUnique<CallArrayAllocatorWithVariableSizeSlowPathGenerator>(
13446 slowCases, this, operationNewArrayWithSize, resultGPR,
13447 TrustedImmPtr::weakPointer(m_graph, globalObject),
13448 structure,
13449 shouldConvertLargeSizeToArrayStorage ? m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)) : structure,
13450 sizeGPR, storageGPR));
13451}
13452
13453void SpeculativeJIT::compileHasIndexedProperty(Node* node)
13454{
13455 SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
13456 SpeculateStrictInt32Operand index(this, m_graph.varArgChild(node, 1));
13457 GPRTemporary result(this);
13458
13459 GPRReg baseGPR = base.gpr();
13460 GPRReg indexGPR = index.gpr();
13461 GPRReg resultGPR = result.gpr();
13462
13463 MacroAssembler::JumpList slowCases;
13464 ArrayMode mode = node->arrayMode();
13465 switch (mode.type()) {
13466 case Array::Int32:
13467 case Array::Contiguous: {
13468 ASSERT(!!m_graph.varArgChild(node, 2));
13469 StorageOperand storage(this, m_graph.varArgChild(node, 2));
13470 GPRTemporary scratch(this);
13471
13472 GPRReg storageGPR = storage.gpr();
13473 GPRReg scratchGPR = scratch.gpr();
13474
13475 MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
13476 if (mode.isInBounds())
13477 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, outOfBounds);
13478 else
13479 slowCases.append(outOfBounds);
13480
13481#if USE(JSVALUE64)
13482 m_jit.load64(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchGPR);
13483 slowCases.append(m_jit.branchIfEmpty(scratchGPR));
13484#else
13485 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR);
13486 slowCases.append(m_jit.branchIfEmpty(scratchGPR));
13487#endif
13488 m_jit.move(TrustedImm32(1), resultGPR);
13489 break;
13490 }
13491 case Array::Double: {
13492 ASSERT(!!m_graph.varArgChild(node, 2));
13493 StorageOperand storage(this, m_graph.varArgChild(node, 2));
13494 FPRTemporary scratch(this);
13495 FPRReg scratchFPR = scratch.fpr();
13496 GPRReg storageGPR = storage.gpr();
13497
13498 MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
13499 if (mode.isInBounds())
13500 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, outOfBounds);
13501 else
13502 slowCases.append(outOfBounds);
13503
13504 m_jit.loadDouble(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchFPR);
13505 slowCases.append(m_jit.branchIfNaN(scratchFPR));
13506 m_jit.move(TrustedImm32(1), resultGPR);
13507 break;
13508 }
13509 case Array::ArrayStorage: {
13510 ASSERT(!!m_graph.varArgChild(node, 2));
13511 StorageOperand storage(this, m_graph.varArgChild(node, 2));
13512 GPRTemporary scratch(this);
13513
13514 GPRReg storageGPR = storage.gpr();
13515 GPRReg scratchGPR = scratch.gpr();
13516
13517 MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
13518 if (mode.isInBounds())
13519 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, outOfBounds);
13520 else
13521 slowCases.append(outOfBounds);
13522
13523#if USE(JSVALUE64)
13524 m_jit.load64(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()), scratchGPR);
13525 slowCases.append(m_jit.branchIfEmpty(scratchGPR));
13526#else
13527 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR);
13528 slowCases.append(m_jit.branchIfEmpty(scratchGPR));
13529#endif
13530 m_jit.move(TrustedImm32(1), resultGPR);
13531 break;
13532 }
13533 default: {
13534 slowCases.append(m_jit.jump());
13535 break;
13536 }
13537 }
13538
13539 addSlowPathGenerator(slowPathCall(slowCases, this, operationHasIndexedPropertyByInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, indexGPR, static_cast<int32_t>(node->internalMethodType())));
13540
13541 unblessedBooleanResult(resultGPR, node);
13542}
13543
13544void SpeculativeJIT::compileGetDirectPname(Node* node)
13545{
13546 Edge& baseEdge = m_jit.graph().varArgChild(node, 0);
13547 Edge& propertyEdge = m_jit.graph().varArgChild(node, 1);
13548 Edge& indexEdge = m_jit.graph().varArgChild(node, 2);
13549
13550 SpeculateCellOperand base(this, baseEdge);
13551 SpeculateCellOperand property(this, propertyEdge);
13552 GPRReg baseGPR = base.gpr();
13553 GPRReg propertyGPR = property.gpr();
13554
13555 Edge& enumeratorEdge = m_jit.graph().varArgChild(node, 3);
13556 SpeculateStrictInt32Operand index(this, indexEdge);
13557 SpeculateCellOperand enumerator(this, enumeratorEdge);
13558 GPRTemporary scratch(this);
13559 JSValueRegsTemporary result(this);
13560
13561 GPRReg indexGPR = index.gpr();
13562 GPRReg enumeratorGPR = enumerator.gpr();
13563 GPRReg scratchGPR = scratch.gpr();
13564 JSValueRegs resultRegs = result.regs();
13565
13566 MacroAssembler::JumpList slowPath;
13567
13568 // Check the structure
13569 m_jit.load32(MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), scratchGPR);
13570 slowPath.append(
13571 m_jit.branch32(
13572 MacroAssembler::NotEqual,
13573 scratchGPR,
13574 MacroAssembler::Address(
13575 enumeratorGPR, JSPropertyNameEnumerator::cachedStructureIDOffset())));
13576
13577 // Compute the offset
13578 // If index is less than the enumerator's cached inline storage, then it's an inline access
13579 MacroAssembler::Jump outOfLineAccess = m_jit.branch32(MacroAssembler::AboveOrEqual,
13580 indexGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()));
13581
13582 m_jit.loadValue(MacroAssembler::BaseIndex(baseGPR, indexGPR, MacroAssembler::TimesEight, JSObject::offsetOfInlineStorage()), resultRegs);
13583
13584 MacroAssembler::Jump done = m_jit.jump();
13585
13586 // Otherwise it's out of line
13587 outOfLineAccess.link(&m_jit);
13588 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), resultRegs.payloadGPR());
13589 m_jit.move(indexGPR, scratchGPR);
13590 m_jit.sub32(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), scratchGPR);
13591 m_jit.neg32(scratchGPR);
13592 m_jit.signExtend32ToPtr(scratchGPR, scratchGPR);
13593 int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
13594 m_jit.loadValue(MacroAssembler::BaseIndex(resultRegs.payloadGPR(), scratchGPR, MacroAssembler::TimesEight, offsetOfFirstProperty), resultRegs);
13595
13596 done.link(&m_jit);
13597
13598 addSlowPathGenerator(slowPathCall(slowPath, this, operationGetByValCell, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, CCallHelpers::CellValue(propertyGPR)));
13599
13600 jsValueResult(resultRegs, node);
13601}
13602
13603void SpeculativeJIT::compileExtractCatchLocal(Node* node)
13604{
13605 JSValueRegsTemporary result(this);
13606 JSValueRegs resultRegs = result.regs();
13607
13608 JSValue* ptr = &reinterpret_cast<JSValue*>(m_jit.jitCode()->common.catchOSREntryBuffer->dataBuffer())[node->catchOSREntryIndex()];
13609 m_jit.loadValue(ptr, resultRegs);
13610 jsValueResult(resultRegs, node);
13611}
13612
13613void SpeculativeJIT::compileClearCatchLocals(Node* node)
13614{
13615 ScratchBuffer* scratchBuffer = m_jit.jitCode()->common.catchOSREntryBuffer;
13616 ASSERT(scratchBuffer);
13617 GPRTemporary scratch(this);
13618 GPRReg scratchGPR = scratch.gpr();
13619 m_jit.move(TrustedImmPtr(scratchBuffer->addressOfActiveLength()), scratchGPR);
13620 m_jit.storePtr(TrustedImmPtr(nullptr), scratchGPR);
13621 noResult(node);
13622}
13623
13624void SpeculativeJIT::compileProfileType(Node* node)
13625{
13626 JSValueOperand value(this, node->child1());
13627 GPRTemporary scratch1(this);
13628 GPRTemporary scratch2(this);
13629 GPRTemporary scratch3(this);
13630
13631 JSValueRegs valueRegs = value.jsValueRegs();
13632 GPRReg scratch1GPR = scratch1.gpr();
13633 GPRReg scratch2GPR = scratch2.gpr();
13634 GPRReg scratch3GPR = scratch3.gpr();
13635
13636 MacroAssembler::JumpList jumpToEnd;
13637
13638 jumpToEnd.append(m_jit.branchIfEmpty(valueRegs));
13639
13640 TypeLocation* cachedTypeLocation = node->typeLocation();
13641 // Compile in a predictive type check, if possible, to see if we can skip writing to the log.
13642 // These typechecks are inlined to match those of the 64-bit JSValue type checks.
13643 if (cachedTypeLocation->m_lastSeenType == TypeUndefined)
13644 jumpToEnd.append(m_jit.branchIfUndefined(valueRegs));
13645 else if (cachedTypeLocation->m_lastSeenType == TypeNull)
13646 jumpToEnd.append(m_jit.branchIfNull(valueRegs));
13647 else if (cachedTypeLocation->m_lastSeenType == TypeBoolean)
13648 jumpToEnd.append(m_jit.branchIfBoolean(valueRegs, scratch1GPR));
13649 else if (cachedTypeLocation->m_lastSeenType == TypeAnyInt)
13650 jumpToEnd.append(m_jit.branchIfInt32(valueRegs));
13651 else if (cachedTypeLocation->m_lastSeenType == TypeNumber)
13652 jumpToEnd.append(m_jit.branchIfNumber(valueRegs, scratch1GPR));
13653 else if (cachedTypeLocation->m_lastSeenType == TypeString) {
13654 MacroAssembler::Jump isNotCell = m_jit.branchIfNotCell(valueRegs);
13655 jumpToEnd.append(m_jit.branchIfString(valueRegs.payloadGPR()));
13656 isNotCell.link(&m_jit);
13657 }
13658
13659 // Load the TypeProfilerLog into Scratch2.
13660 TypeProfilerLog* cachedTypeProfilerLog = vm().typeProfilerLog();
13661 m_jit.move(TrustedImmPtr(cachedTypeProfilerLog), scratch2GPR);
13662
13663 // Load the next LogEntry into Scratch1.
13664 m_jit.loadPtr(MacroAssembler::Address(scratch2GPR, TypeProfilerLog::currentLogEntryOffset()), scratch1GPR);
13665
13666 // Store the JSValue onto the log entry.
13667 m_jit.storeValue(valueRegs, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::valueOffset()));
13668
13669 // Store the structureID of the cell if valueRegs is a cell, otherwise, store 0 on the log entry.
13670 MacroAssembler::Jump isNotCell = m_jit.branchIfNotCell(valueRegs);
13671 m_jit.load32(MacroAssembler::Address(valueRegs.payloadGPR(), JSCell::structureIDOffset()), scratch3GPR);
13672 m_jit.store32(scratch3GPR, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::structureIDOffset()));
13673 MacroAssembler::Jump skipIsCell = m_jit.jump();
13674 isNotCell.link(&m_jit);
13675 m_jit.store32(TrustedImm32(0), MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::structureIDOffset()));
13676 skipIsCell.link(&m_jit);
13677
13678 // Store the typeLocation on the log entry.
13679 m_jit.move(TrustedImmPtr(cachedTypeLocation), scratch3GPR);
13680 m_jit.storePtr(scratch3GPR, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::locationOffset()));
13681
13682 // Increment the current log entry.
13683 m_jit.addPtr(TrustedImm32(sizeof(TypeProfilerLog::LogEntry)), scratch1GPR);
13684 m_jit.storePtr(scratch1GPR, MacroAssembler::Address(scratch2GPR, TypeProfilerLog::currentLogEntryOffset()));
13685 MacroAssembler::Jump clearLog = m_jit.branchPtr(MacroAssembler::Equal, scratch1GPR, TrustedImmPtr(cachedTypeProfilerLog->logEndPtr()));
13686 addSlowPathGenerator(
13687 slowPathCall(clearLog, this, operationProcessTypeProfilerLogDFG, NoResult, TrustedImmPtr(&vm())));
13688
13689 jumpToEnd.link(&m_jit);
13690
13691 noResult(node);
13692}
13693
13694void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, JSValueRegs valueRegs, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
13695{
13696 RegisterSet usedRegisters = this->usedRegisters();
13697 if (spillMode == DontSpill) {
13698 // We've already flushed registers to the stack, we don't need to spill these.
13699 usedRegisters.set(baseGPR, false);
13700 usedRegisters.set(valueRegs, false);
13701 }
13702 CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
13703 JITPutByIdGenerator gen(
13704 m_jit.codeBlock(), codeOrigin, callSite, usedRegisters,
13705 JSValueRegs::payloadOnly(baseGPR), valueRegs,
13706 scratchGPR, m_jit.ecmaModeFor(codeOrigin), putKind);
13707
13708 gen.generateFastPath(m_jit);
13709
13710 JITCompiler::JumpList slowCases;
13711 if (slowPathTarget.isSet())
13712 slowCases.append(slowPathTarget);
13713 slowCases.append(gen.slowPathJump());
13714
13715 auto slowPath = slowPathCall(
13716 slowCases, this, gen.slowPathFunction(), NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), gen.stubInfo(), valueRegs,
13717 CCallHelpers::CellValue(baseGPR), identifierUID(identifierNumber));
13718
13719 m_jit.addPutById(gen, slowPath.get());
13720 addSlowPathGenerator(WTFMove(slowPath));
13721}
13722
13723void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node* node, MacroAssembler::RelationalCondition cond, S_JITOperation_GJJ helperFunction)
13724{
13725 ASSERT(node->isBinaryUseKind(UntypedUse));
13726 JSValueOperand arg1(this, node->child1());
13727 JSValueOperand arg2(this, node->child2());
13728
13729 JSValueRegs arg1Regs = arg1.jsValueRegs();
13730 JSValueRegs arg2Regs = arg2.jsValueRegs();
13731
13732 JITCompiler::JumpList slowPath;
13733
13734 if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) {
13735 GPRFlushedCallResult result(this);
13736 GPRReg resultGPR = result.gpr();
13737
13738 arg1.use();
13739 arg2.use();
13740
13741 flushRegisters();
13742 callOperation(helperFunction, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1Regs, arg2Regs);
13743 m_jit.exceptionCheck();
13744
13745 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
13746 return;
13747 }
13748
13749 GPRTemporary result(this, Reuse, arg1, TagWord);
13750 GPRReg resultGPR = result.gpr();
13751
13752 arg1.use();
13753 arg2.use();
13754
13755 if (!isKnownInteger(node->child1().node()))
13756 slowPath.append(m_jit.branchIfNotInt32(arg1Regs));
13757 if (!isKnownInteger(node->child2().node()))
13758 slowPath.append(m_jit.branchIfNotInt32(arg2Regs));
13759
13760 m_jit.compare32(cond, arg1Regs.payloadGPR(), arg2Regs.payloadGPR(), resultGPR);
13761
13762 if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node()))
13763 addSlowPathGenerator(slowPathCall(slowPath, this, helperFunction, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1Regs, arg2Regs));
13764
13765 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
13766}
13767
13768void SpeculativeJIT::nonSpeculativePeepholeBranch(Node* node, Node* branchNode, MacroAssembler::RelationalCondition cond, S_JITOperation_GJJ helperFunction)
13769{
13770 BasicBlock* taken = branchNode->branchData()->taken.block;
13771 BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
13772
13773 JITCompiler::ResultCondition callResultCondition = JITCompiler::NonZero;
13774
13775 // The branch instruction will branch to the taken block.
13776 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
13777 if (taken == nextBlock()) {
13778 cond = JITCompiler::invert(cond);
13779 callResultCondition = JITCompiler::Zero;
13780 BasicBlock* tmp = taken;
13781 taken = notTaken;
13782 notTaken = tmp;
13783 }
13784
13785 JSValueOperand arg1(this, node->child1());
13786 JSValueOperand arg2(this, node->child2());
13787 JSValueRegs arg1Regs = arg1.jsValueRegs();
13788 JSValueRegs arg2Regs = arg2.jsValueRegs();
13789
13790 JITCompiler::JumpList slowPath;
13791
13792 if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) {
13793 GPRFlushedCallResult result(this);
13794 GPRReg resultGPR = result.gpr();
13795
13796 arg1.use();
13797 arg2.use();
13798
13799 flushRegisters();
13800 callOperation(helperFunction, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1Regs, arg2Regs);
13801 m_jit.exceptionCheck();
13802
13803 branchTest32(callResultCondition, resultGPR, taken);
13804 } else {
13805 GPRTemporary result(this, Reuse, arg2, TagWord);
13806 GPRReg resultGPR = result.gpr();
13807
13808 arg1.use();
13809 arg2.use();
13810
13811 if (!isKnownInteger(node->child1().node()))
13812 slowPath.append(m_jit.branchIfNotInt32(arg1Regs));
13813 if (!isKnownInteger(node->child2().node()))
13814 slowPath.append(m_jit.branchIfNotInt32(arg2Regs));
13815
13816 branch32(cond, arg1Regs.payloadGPR(), arg2Regs.payloadGPR(), taken);
13817
13818 if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node())) {
13819 jump(notTaken, ForceJump);
13820
13821 slowPath.link(&m_jit);
13822
13823 silentSpillAllRegisters(resultGPR);
13824 callOperation(helperFunction, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1Regs, arg2Regs);
13825 silentFillAllRegisters();
13826 m_jit.exceptionCheck();
13827
13828 branchTest32(callResultCondition, resultGPR, taken);
13829 }
13830 }
13831
13832 jump(notTaken);
13833
13834 m_indexInBlock = m_block->size() - 1;
13835 m_currentNode = branchNode;
13836}
13837
13838void SpeculativeJIT::compileBigIntEquality(Node* node)
13839{
13840 // FIXME: [ESNext][BigInt] Create specialized version of strict equals for BigIntUse
13841 // https://bugs.webkit.org/show_bug.cgi?id=182895
13842 SpeculateCellOperand left(this, node->child1());
13843 SpeculateCellOperand right(this, node->child2());
13844 GPRTemporary result(this, Reuse, left);
13845 GPRReg leftGPR = left.gpr();
13846 GPRReg rightGPR = right.gpr();
13847 GPRReg resultGPR = result.gpr();
13848
13849 left.use();
13850 right.use();
13851
13852 speculateBigInt(node->child1(), leftGPR);
13853 speculateBigInt(node->child2(), rightGPR);
13854
13855 JITCompiler::Jump notEqualCase = m_jit.branchPtr(JITCompiler::NotEqual, leftGPR, rightGPR);
13856
13857 m_jit.move(JITCompiler::TrustedImm32(1), resultGPR);
13858
13859 JITCompiler::Jump done = m_jit.jump();
13860
13861 notEqualCase.link(&m_jit);
13862
13863 silentSpillAllRegisters(resultGPR);
13864 callOperation(operationCompareStrictEqCell, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
13865 silentFillAllRegisters();
13866
13867 done.link(&m_jit);
13868
13869 unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
13870}
13871
13872void SpeculativeJIT::compileMakeRope(Node* node)
13873{
13874 ASSERT(node->child1().useKind() == KnownStringUse);
13875 ASSERT(node->child2().useKind() == KnownStringUse);
13876 ASSERT(!node->child3() || node->child3().useKind() == KnownStringUse);
13877
13878 SpeculateCellOperand op1(this, node->child1());
13879 SpeculateCellOperand op2(this, node->child2());
13880 SpeculateCellOperand op3(this, node->child3());
13881 GPRReg opGPRs[3];
13882 unsigned numOpGPRs;
13883 opGPRs[0] = op1.gpr();
13884 opGPRs[1] = op2.gpr();
13885 if (node->child3()) {
13886 opGPRs[2] = op3.gpr();
13887 numOpGPRs = 3;
13888 } else {
13889 opGPRs[2] = InvalidGPRReg;
13890 numOpGPRs = 2;
13891 }
13892
13893#if CPU(ADDRESS64)
13894 Edge edges[3] = {
13895 node->child1(),
13896 node->child2(),
13897 node->child3()
13898 };
13899
13900 GPRTemporary result(this);
13901 GPRTemporary allocator(this);
13902 GPRTemporary scratch(this);
13903 GPRTemporary scratch2(this);
13904 GPRReg resultGPR = result.gpr();
13905 GPRReg allocatorGPR = allocator.gpr();
13906 GPRReg scratchGPR = scratch.gpr();
13907 GPRReg scratch2GPR = scratch2.gpr();
13908
13909 CCallHelpers::JumpList slowPath;
13910 Allocator allocatorValue = allocatorForNonVirtualConcurrently<JSRopeString>(vm(), sizeof(JSRopeString), AllocatorForMode::AllocatorIfExists);
13911 emitAllocateJSCell(resultGPR, JITAllocator::constant(allocatorValue), allocatorGPR, TrustedImmPtr(m_jit.graph().registerStructure(vm().stringStructure.get())), scratchGPR, slowPath);
13912
13913 // 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.
13914 m_jit.storePtr(TrustedImmPtr(JSString::isRopeInPointer), CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber0()));
13915
13916 {
13917 if (JSString* string = edges[0]->dynamicCastConstant<JSString*>(vm())) {
13918 m_jit.move(TrustedImm32(string->is8Bit() ? StringImpl::flagIs8Bit() : 0), scratchGPR);
13919 m_jit.move(TrustedImm32(string->length()), allocatorGPR);
13920 } else {
13921 bool needsRopeCase = canBeRope(edges[0]);
13922 m_jit.loadPtr(CCallHelpers::Address(opGPRs[0], JSString::offsetOfValue()), scratch2GPR);
13923 CCallHelpers::Jump isRope;
13924 if (needsRopeCase)
13925 isRope = m_jit.branchIfRopeStringImpl(scratch2GPR);
13926
13927 m_jit.load32(CCallHelpers::Address(scratch2GPR, StringImpl::flagsOffset()), scratchGPR);
13928 m_jit.load32(CCallHelpers::Address(scratch2GPR, StringImpl::lengthMemoryOffset()), allocatorGPR);
13929
13930 if (needsRopeCase) {
13931 auto done = m_jit.jump();
13932
13933 isRope.link(&m_jit);
13934 m_jit.load32(CCallHelpers::Address(opGPRs[0], JSRopeString::offsetOfFlags()), scratchGPR);
13935 m_jit.load32(CCallHelpers::Address(opGPRs[0], JSRopeString::offsetOfLength()), allocatorGPR);
13936 done.link(&m_jit);
13937 }
13938 }
13939
13940 if (!ASSERT_DISABLED) {
13941 CCallHelpers::Jump ok = m_jit.branch32(
13942 CCallHelpers::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
13943 m_jit.abortWithReason(DFGNegativeStringLength);
13944 ok.link(&m_jit);
13945 }
13946 }
13947
13948 for (unsigned i = 1; i < numOpGPRs; ++i) {
13949 if (JSString* string = edges[i]->dynamicCastConstant<JSString*>(vm())) {
13950 m_jit.and32(TrustedImm32(string->is8Bit() ? StringImpl::flagIs8Bit() : 0), scratchGPR);
13951 speculationCheck(
13952 Uncountable, JSValueSource(), nullptr,
13953 m_jit.branchAdd32(
13954 CCallHelpers::Overflow,
13955 TrustedImm32(string->length()), allocatorGPR));
13956 } else {
13957 bool needsRopeCase = canBeRope(edges[i]);
13958 m_jit.loadPtr(CCallHelpers::Address(opGPRs[i], JSString::offsetOfValue()), scratch2GPR);
13959 CCallHelpers::Jump isRope;
13960 if (needsRopeCase)
13961 isRope = m_jit.branchIfRopeStringImpl(scratch2GPR);
13962
13963 m_jit.and32(CCallHelpers::Address(scratch2GPR, StringImpl::flagsOffset()), scratchGPR);
13964 speculationCheck(
13965 Uncountable, JSValueSource(), nullptr,
13966 m_jit.branchAdd32(
13967 CCallHelpers::Overflow,
13968 CCallHelpers::Address(scratch2GPR, StringImpl::lengthMemoryOffset()), allocatorGPR));
13969 if (needsRopeCase) {
13970 auto done = m_jit.jump();
13971
13972 isRope.link(&m_jit);
13973 m_jit.and32(CCallHelpers::Address(opGPRs[i], JSRopeString::offsetOfFlags()), scratchGPR);
13974 m_jit.load32(CCallHelpers::Address(opGPRs[i], JSRopeString::offsetOfLength()), scratch2GPR);
13975 speculationCheck(
13976 Uncountable, JSValueSource(), nullptr,
13977 m_jit.branchAdd32(
13978 CCallHelpers::Overflow, scratch2GPR, allocatorGPR));
13979 done.link(&m_jit);
13980 }
13981 }
13982 }
13983
13984 if (!ASSERT_DISABLED) {
13985 CCallHelpers::Jump ok = m_jit.branch32(
13986 CCallHelpers::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
13987 m_jit.abortWithReason(DFGNegativeStringLength);
13988 ok.link(&m_jit);
13989 }
13990
13991 static_assert(StringImpl::flagIs8Bit() == JSRopeString::is8BitInPointer, "");
13992 m_jit.and32(TrustedImm32(StringImpl::flagIs8Bit()), scratchGPR);
13993 m_jit.orPtr(opGPRs[0], scratchGPR);
13994 m_jit.orPtr(TrustedImmPtr(JSString::isRopeInPointer), scratchGPR);
13995 m_jit.storePtr(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber0()));
13996
13997 m_jit.move(opGPRs[1], scratchGPR);
13998 m_jit.lshiftPtr(TrustedImm32(32), scratchGPR);
13999 m_jit.orPtr(allocatorGPR, scratchGPR);
14000 m_jit.storePtr(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber1()));
14001
14002 if (numOpGPRs == 2) {
14003 m_jit.move(opGPRs[1], scratchGPR);
14004 m_jit.rshiftPtr(TrustedImm32(32), scratchGPR);
14005 m_jit.storePtr(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2()));
14006 } else {
14007 m_jit.move(opGPRs[1], scratchGPR);
14008 m_jit.rshiftPtr(TrustedImm32(32), scratchGPR);
14009 m_jit.move(opGPRs[2], scratch2GPR);
14010 m_jit.lshiftPtr(TrustedImm32(16), scratch2GPR);
14011 m_jit.orPtr(scratch2GPR, scratchGPR);
14012 m_jit.storePtr(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2()));
14013 }
14014
14015 auto isNonEmptyString = m_jit.branchTest32(CCallHelpers::NonZero, allocatorGPR);
14016
14017 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.graph().m_vm)), resultGPR);
14018
14019 isNonEmptyString.link(&m_jit);
14020 m_jit.mutatorFence(vm());
14021
14022 switch (numOpGPRs) {
14023 case 2:
14024 addSlowPathGenerator(slowPathCall(
14025 slowPath, this, operationMakeRope2, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), opGPRs[0], opGPRs[1]));
14026 break;
14027 case 3:
14028 addSlowPathGenerator(slowPathCall(
14029 slowPath, this, operationMakeRope3, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), opGPRs[0], opGPRs[1], opGPRs[2]));
14030 break;
14031 default:
14032 RELEASE_ASSERT_NOT_REACHED();
14033 break;
14034 }
14035
14036 cellResult(resultGPR, node);
14037#else
14038 flushRegisters();
14039 GPRFlushedCallResult result(this);
14040 GPRReg resultGPR = result.gpr();
14041 switch (numOpGPRs) {
14042 case 2:
14043 callOperation(operationMakeRope2, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), opGPRs[0], opGPRs[1]);
14044 m_jit.exceptionCheck();
14045 break;
14046 case 3:
14047 callOperation(operationMakeRope3, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), opGPRs[0], opGPRs[1], opGPRs[2]);
14048 m_jit.exceptionCheck();
14049 break;
14050 default:
14051 RELEASE_ASSERT_NOT_REACHED();
14052 break;
14053 }
14054
14055 cellResult(resultGPR, node);
14056#endif
14057}
14058
14059} } // namespace JSC::DFG
14060
14061#endif
14062