f89e1a07749f128943df9747324c4eb06ec6a28c
[WebKit-https.git] / Source / JavaScriptCore / jit / AssemblyHelpers.cpp
1 /*
2  * Copyright (C) 2011-2017 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 "AssemblyHelpers.h"
28
29 #if ENABLE(JIT)
30
31 #include "JITOperations.h"
32 #include "JSCInlines.h"
33 #include "LinkBuffer.h"
34
35 #if ENABLE(WEBASSEMBLY)
36 #include "WasmContext.h"
37 #include "WasmMemoryInformation.h"
38 #endif
39
40 namespace JSC {
41
42 ExecutableBase* AssemblyHelpers::executableFor(const CodeOrigin& codeOrigin)
43 {
44     if (!codeOrigin.inlineCallFrame)
45         return m_codeBlock->ownerExecutable();
46     
47     return codeOrigin.inlineCallFrame->baselineCodeBlock->ownerExecutable();
48 }
49
50 Vector<BytecodeAndMachineOffset>& AssemblyHelpers::decodedCodeMapFor(CodeBlock* codeBlock)
51 {
52     ASSERT(codeBlock == codeBlock->baselineVersion());
53     ASSERT(codeBlock->jitType() == JITCode::BaselineJIT);
54     ASSERT(codeBlock->jitCodeMap());
55     
56     HashMap<CodeBlock*, Vector<BytecodeAndMachineOffset>>::AddResult result = m_decodedCodeMaps.add(codeBlock, Vector<BytecodeAndMachineOffset>());
57     
58     if (result.isNewEntry)
59         codeBlock->jitCodeMap()->decode(result.iterator->value);
60     
61     return result.iterator->value;
62 }
63
64 AssemblyHelpers::JumpList AssemblyHelpers::branchIfNotType(
65     JSValueRegs regs, GPRReg tempGPR, const InferredType::Descriptor& descriptor, TagRegistersMode mode)
66 {
67     AssemblyHelpers::JumpList result;
68
69     switch (descriptor.kind()) {
70     case InferredType::Bottom:
71         result.append(jump());
72         break;
73
74     case InferredType::Boolean:
75         result.append(branchIfNotBoolean(regs, tempGPR));
76         break;
77
78     case InferredType::Other:
79         result.append(branchIfNotOther(regs, tempGPR));
80         break;
81
82     case InferredType::Int32:
83         result.append(branchIfNotInt32(regs, mode));
84         break;
85
86     case InferredType::Number:
87         result.append(branchIfNotNumber(regs, tempGPR, mode));
88         break;
89
90     case InferredType::String:
91         result.append(branchIfNotCell(regs, mode));
92         result.append(branchIfNotString(regs.payloadGPR()));
93         break;
94
95     case InferredType::Symbol:
96         result.append(branchIfNotCell(regs, mode));
97         result.append(branchIfNotSymbol(regs.payloadGPR()));
98         break;
99
100     case InferredType::ObjectWithStructure:
101         result.append(branchIfNotCell(regs, mode));
102         result.append(
103             branchStructure(
104                 NotEqual,
105                 Address(regs.payloadGPR(), JSCell::structureIDOffset()),
106                 descriptor.structure()));
107         break;
108
109     case InferredType::ObjectWithStructureOrOther: {
110         Jump ok = branchIfOther(regs, tempGPR);
111         result.append(branchIfNotCell(regs, mode));
112         result.append(
113             branchStructure(
114                 NotEqual,
115                 Address(regs.payloadGPR(), JSCell::structureIDOffset()),
116                 descriptor.structure()));
117         ok.link(this);
118         break;
119     }
120
121     case InferredType::Object:
122         result.append(branchIfNotCell(regs, mode));
123         result.append(branchIfNotObject(regs.payloadGPR()));
124         break;
125
126     case InferredType::ObjectOrOther: {
127         Jump ok = branchIfOther(regs, tempGPR);
128         result.append(branchIfNotCell(regs, mode));
129         result.append(branchIfNotObject(regs.payloadGPR()));
130         ok.link(this);
131         break;
132     }
133
134     case InferredType::Top:
135         break;
136     }
137
138     return result;
139 }
140
141 AssemblyHelpers::Jump AssemblyHelpers::branchIfFastTypedArray(GPRReg baseGPR)
142 {
143     return branch32(
144         Equal,
145         Address(baseGPR, JSArrayBufferView::offsetOfMode()),
146         TrustedImm32(FastTypedArray));
147 }
148
149 AssemblyHelpers::Jump AssemblyHelpers::branchIfNotFastTypedArray(GPRReg baseGPR)
150 {
151     return branch32(
152         NotEqual,
153         Address(baseGPR, JSArrayBufferView::offsetOfMode()),
154         TrustedImm32(FastTypedArray));
155 }
156
157 void AssemblyHelpers::incrementSuperSamplerCount()
158 {
159     add32(TrustedImm32(1), AbsoluteAddress(bitwise_cast<const void*>(&g_superSamplerCount)));
160 }
161
162 void AssemblyHelpers::decrementSuperSamplerCount()
163 {
164     sub32(TrustedImm32(1), AbsoluteAddress(bitwise_cast<const void*>(&g_superSamplerCount)));
165 }
166     
167 void AssemblyHelpers::purifyNaN(FPRReg fpr)
168 {
169     MacroAssembler::Jump notNaN = branchDouble(DoubleEqual, fpr, fpr);
170     static const double NaN = PNaN;
171     loadDouble(TrustedImmPtr(&NaN), fpr);
172     notNaN.link(this);
173 }
174
175 #if ENABLE(SAMPLING_FLAGS)
176 void AssemblyHelpers::setSamplingFlag(int32_t flag)
177 {
178     ASSERT(flag >= 1);
179     ASSERT(flag <= 32);
180     or32(TrustedImm32(1u << (flag - 1)), AbsoluteAddress(SamplingFlags::addressOfFlags()));
181 }
182
183 void AssemblyHelpers::clearSamplingFlag(int32_t flag)
184 {
185     ASSERT(flag >= 1);
186     ASSERT(flag <= 32);
187     and32(TrustedImm32(~(1u << (flag - 1))), AbsoluteAddress(SamplingFlags::addressOfFlags()));
188 }
189 #endif
190
191 #if !ASSERT_DISABLED
192 #if USE(JSVALUE64)
193 void AssemblyHelpers::jitAssertIsInt32(GPRReg gpr)
194 {
195 #if CPU(X86_64) || CPU(ARM64)
196     Jump checkInt32 = branch64(BelowOrEqual, gpr, TrustedImm64(static_cast<uintptr_t>(0xFFFFFFFFu)));
197     abortWithReason(AHIsNotInt32);
198     checkInt32.link(this);
199 #else
200     UNUSED_PARAM(gpr);
201 #endif
202 }
203
204 void AssemblyHelpers::jitAssertIsJSInt32(GPRReg gpr)
205 {
206     Jump checkJSInt32 = branch64(AboveOrEqual, gpr, GPRInfo::tagTypeNumberRegister);
207     abortWithReason(AHIsNotJSInt32);
208     checkJSInt32.link(this);
209 }
210
211 void AssemblyHelpers::jitAssertIsJSNumber(GPRReg gpr)
212 {
213     Jump checkJSNumber = branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagTypeNumberRegister);
214     abortWithReason(AHIsNotJSNumber);
215     checkJSNumber.link(this);
216 }
217
218 void AssemblyHelpers::jitAssertIsJSDouble(GPRReg gpr)
219 {
220     Jump checkJSInt32 = branch64(AboveOrEqual, gpr, GPRInfo::tagTypeNumberRegister);
221     Jump checkJSNumber = branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagTypeNumberRegister);
222     checkJSInt32.link(this);
223     abortWithReason(AHIsNotJSDouble);
224     checkJSNumber.link(this);
225 }
226
227 void AssemblyHelpers::jitAssertIsCell(GPRReg gpr)
228 {
229     Jump checkCell = branchTest64(MacroAssembler::Zero, gpr, GPRInfo::tagMaskRegister);
230     abortWithReason(AHIsNotCell);
231     checkCell.link(this);
232 }
233
234 void AssemblyHelpers::jitAssertTagsInPlace()
235 {
236     Jump ok = branch64(Equal, GPRInfo::tagTypeNumberRegister, TrustedImm64(TagTypeNumber));
237     abortWithReason(AHTagTypeNumberNotInPlace);
238     breakpoint();
239     ok.link(this);
240     
241     ok = branch64(Equal, GPRInfo::tagMaskRegister, TrustedImm64(TagMask));
242     abortWithReason(AHTagMaskNotInPlace);
243     ok.link(this);
244 }
245 #elif USE(JSVALUE32_64)
246 void AssemblyHelpers::jitAssertIsInt32(GPRReg gpr)
247 {
248     UNUSED_PARAM(gpr);
249 }
250
251 void AssemblyHelpers::jitAssertIsJSInt32(GPRReg gpr)
252 {
253     Jump checkJSInt32 = branch32(Equal, gpr, TrustedImm32(JSValue::Int32Tag));
254     abortWithReason(AHIsNotJSInt32);
255     checkJSInt32.link(this);
256 }
257
258 void AssemblyHelpers::jitAssertIsJSNumber(GPRReg gpr)
259 {
260     Jump checkJSInt32 = branch32(Equal, gpr, TrustedImm32(JSValue::Int32Tag));
261     Jump checkJSDouble = branch32(Below, gpr, TrustedImm32(JSValue::LowestTag));
262     abortWithReason(AHIsNotJSNumber);
263     checkJSInt32.link(this);
264     checkJSDouble.link(this);
265 }
266
267 void AssemblyHelpers::jitAssertIsJSDouble(GPRReg gpr)
268 {
269     Jump checkJSDouble = branch32(Below, gpr, TrustedImm32(JSValue::LowestTag));
270     abortWithReason(AHIsNotJSDouble);
271     checkJSDouble.link(this);
272 }
273
274 void AssemblyHelpers::jitAssertIsCell(GPRReg gpr)
275 {
276     Jump checkCell = branch32(Equal, gpr, TrustedImm32(JSValue::CellTag));
277     abortWithReason(AHIsNotCell);
278     checkCell.link(this);
279 }
280
281 void AssemblyHelpers::jitAssertTagsInPlace()
282 {
283 }
284 #endif // USE(JSVALUE32_64)
285
286 void AssemblyHelpers::jitAssertHasValidCallFrame()
287 {
288     Jump checkCFR = branchTestPtr(Zero, GPRInfo::callFrameRegister, TrustedImm32(7));
289     abortWithReason(AHCallFrameMisaligned);
290     checkCFR.link(this);
291 }
292
293 void AssemblyHelpers::jitAssertIsNull(GPRReg gpr)
294 {
295     Jump checkNull = branchTestPtr(Zero, gpr);
296     abortWithReason(AHIsNotNull);
297     checkNull.link(this);
298 }
299
300 void AssemblyHelpers::jitAssertArgumentCountSane()
301 {
302     Jump ok = branch32(Below, payloadFor(CallFrameSlot::argumentCount), TrustedImm32(10000000));
303     abortWithReason(AHInsaneArgumentCount);
304     ok.link(this);
305 }
306
307 #endif // !ASSERT_DISABLED
308
309 void AssemblyHelpers::jitReleaseAssertNoException(VM& vm)
310 {
311     Jump noException;
312 #if USE(JSVALUE64)
313     noException = branchTest64(Zero, AbsoluteAddress(vm.addressOfException()));
314 #elif USE(JSVALUE32_64)
315     noException = branch32(Equal, AbsoluteAddress(vm.addressOfException()), TrustedImm32(0));
316 #endif
317     abortWithReason(JITUncoughtExceptionAfterCall);
318     noException.link(this);
319 }
320
321 void AssemblyHelpers::callExceptionFuzz(VM& vm)
322 {
323     if (!Options::useExceptionFuzz())
324         return;
325
326     EncodedJSValue* buffer = vm.exceptionFuzzingBuffer(sizeof(EncodedJSValue) * (GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters));
327
328     for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
329 #if USE(JSVALUE64)
330         store64(GPRInfo::toRegister(i), buffer + i);
331 #else
332         store32(GPRInfo::toRegister(i), buffer + i);
333 #endif
334     }
335     for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
336         move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
337         storeDouble(FPRInfo::toRegister(i), Address(GPRInfo::regT0));
338     }
339
340     // Set up one argument.
341 #if CPU(X86)
342     poke(GPRInfo::callFrameRegister, 0);
343 #else
344     move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
345 #endif
346     move(TrustedImmPtr(bitwise_cast<void*>(operationExceptionFuzz)), GPRInfo::nonPreservedNonReturnGPR);
347     call(GPRInfo::nonPreservedNonReturnGPR);
348
349     for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
350         move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
351         loadDouble(Address(GPRInfo::regT0), FPRInfo::toRegister(i));
352     }
353     for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
354 #if USE(JSVALUE64)
355         load64(buffer + i, GPRInfo::toRegister(i));
356 #else
357         load32(buffer + i, GPRInfo::toRegister(i));
358 #endif
359     }
360 }
361
362 AssemblyHelpers::Jump AssemblyHelpers::emitJumpIfException(VM& vm)
363 {
364     return emitExceptionCheck(vm, NormalExceptionCheck);
365 }
366
367 AssemblyHelpers::Jump AssemblyHelpers::emitExceptionCheck(VM& vm, ExceptionCheckKind kind, ExceptionJumpWidth width)
368 {
369     callExceptionFuzz(vm);
370
371     if (width == FarJumpWidth)
372         kind = (kind == NormalExceptionCheck ? InvertedExceptionCheck : NormalExceptionCheck);
373     
374     Jump result;
375 #if USE(JSVALUE64)
376     result = branchTest64(kind == NormalExceptionCheck ? NonZero : Zero, AbsoluteAddress(vm.addressOfException()));
377 #elif USE(JSVALUE32_64)
378     result = branch32(kind == NormalExceptionCheck ? NotEqual : Equal, AbsoluteAddress(vm.addressOfException()), TrustedImm32(0));
379 #endif
380     
381     if (width == NormalJumpWidth)
382         return result;
383
384     PatchableJump realJump = patchableJump();
385     result.link(this);
386     
387     return realJump.m_jump;
388 }
389
390 AssemblyHelpers::Jump AssemblyHelpers::emitNonPatchableExceptionCheck(VM& vm)
391 {
392     callExceptionFuzz(vm);
393
394     Jump result;
395 #if USE(JSVALUE64)
396     result = branchTest64(NonZero, AbsoluteAddress(vm.addressOfException()));
397 #elif USE(JSVALUE32_64)
398     result = branch32(NotEqual, AbsoluteAddress(vm.addressOfException()), TrustedImm32(0));
399 #endif
400     
401     return result;
402 }
403
404 void AssemblyHelpers::emitStoreStructureWithTypeInfo(AssemblyHelpers& jit, TrustedImmPtr structure, RegisterID dest)
405 {
406     const Structure* structurePtr = static_cast<const Structure*>(structure.m_value);
407 #if USE(JSVALUE64)
408     jit.store64(TrustedImm64(structurePtr->idBlob()), MacroAssembler::Address(dest, JSCell::structureIDOffset()));
409     if (!ASSERT_DISABLED) {
410         Jump correctStructure = jit.branch32(Equal, MacroAssembler::Address(dest, JSCell::structureIDOffset()), TrustedImm32(structurePtr->id()));
411         jit.abortWithReason(AHStructureIDIsValid);
412         correctStructure.link(&jit);
413
414         Jump correctIndexingType = jit.branch8(Equal, MacroAssembler::Address(dest, JSCell::indexingTypeAndMiscOffset()), TrustedImm32(structurePtr->indexingTypeIncludingHistory()));
415         jit.abortWithReason(AHIndexingTypeIsValid);
416         correctIndexingType.link(&jit);
417
418         Jump correctType = jit.branch8(Equal, MacroAssembler::Address(dest, JSCell::typeInfoTypeOffset()), TrustedImm32(structurePtr->typeInfo().type()));
419         jit.abortWithReason(AHTypeInfoIsValid);
420         correctType.link(&jit);
421
422         Jump correctFlags = jit.branch8(Equal, MacroAssembler::Address(dest, JSCell::typeInfoFlagsOffset()), TrustedImm32(structurePtr->typeInfo().inlineTypeFlags()));
423         jit.abortWithReason(AHTypeInfoInlineTypeFlagsAreValid);
424         correctFlags.link(&jit);
425     }
426 #else
427     // Do a 32-bit wide store to initialize the cell's fields.
428     jit.store32(TrustedImm32(structurePtr->objectInitializationBlob()), MacroAssembler::Address(dest, JSCell::indexingTypeAndMiscOffset()));
429     jit.storePtr(structure, MacroAssembler::Address(dest, JSCell::structureIDOffset()));
430 #endif
431 }
432
433 void AssemblyHelpers::loadProperty(GPRReg object, GPRReg offset, JSValueRegs result)
434 {
435     Jump isInline = branch32(LessThan, offset, TrustedImm32(firstOutOfLineOffset));
436     
437     loadPtr(Address(object, JSObject::butterflyOffset()), result.payloadGPR());
438     neg32(offset);
439     signExtend32ToPtr(offset, offset);
440     Jump ready = jump();
441     
442     isInline.link(this);
443     addPtr(
444         TrustedImm32(
445             static_cast<int32_t>(sizeof(JSObject)) -
446             (static_cast<int32_t>(firstOutOfLineOffset) - 2) * static_cast<int32_t>(sizeof(EncodedJSValue))),
447         object, result.payloadGPR());
448     
449     ready.link(this);
450     
451     loadValue(
452         BaseIndex(
453             result.payloadGPR(), offset, TimesEight, (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)),
454         result);
455 }
456
457 void AssemblyHelpers::emitLoadStructure(VM& vm, RegisterID source, RegisterID dest, RegisterID scratch)
458 {
459 #if USE(JSVALUE64)
460     ASSERT(dest != scratch);
461     load32(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
462     loadPtr(vm.heap.structureIDTable().base(), scratch);
463     loadPtr(MacroAssembler::BaseIndex(scratch, dest, MacroAssembler::TimesEight), dest);
464 #else
465     UNUSED_PARAM(scratch);
466     UNUSED_PARAM(vm);
467     loadPtr(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
468 #endif
469 }
470
471 void AssemblyHelpers::makeSpaceOnStackForCCall()
472 {
473     unsigned stackOffset = WTF::roundUpToMultipleOf(stackAlignmentBytes(), maxFrameExtentForSlowPathCall);
474     if (stackOffset)
475         subPtr(TrustedImm32(stackOffset), stackPointerRegister);
476 }
477
478 void AssemblyHelpers::reclaimSpaceOnStackForCCall()
479 {
480     unsigned stackOffset = WTF::roundUpToMultipleOf(stackAlignmentBytes(), maxFrameExtentForSlowPathCall);
481     if (stackOffset)
482         addPtr(TrustedImm32(stackOffset), stackPointerRegister);
483 }
484
485 #if USE(JSVALUE64)
486 template<typename LoadFromHigh, typename StoreToHigh, typename LoadFromLow, typename StoreToLow>
487 void emitRandomThunkImpl(AssemblyHelpers& jit, GPRReg scratch0, GPRReg scratch1, GPRReg scratch2, FPRReg result, const LoadFromHigh& loadFromHigh, const StoreToHigh& storeToHigh, const LoadFromLow& loadFromLow, const StoreToLow& storeToLow)
488 {
489     // Inlined WeakRandom::advance().
490     // uint64_t x = m_low;
491     loadFromLow(scratch0);
492     // uint64_t y = m_high;
493     loadFromHigh(scratch1);
494     // m_low = y;
495     storeToLow(scratch1);
496
497     // x ^= x << 23;
498     jit.move(scratch0, scratch2);
499     jit.lshift64(AssemblyHelpers::TrustedImm32(23), scratch2);
500     jit.xor64(scratch2, scratch0);
501
502     // x ^= x >> 17;
503     jit.move(scratch0, scratch2);
504     jit.rshift64(AssemblyHelpers::TrustedImm32(17), scratch2);
505     jit.xor64(scratch2, scratch0);
506
507     // x ^= y ^ (y >> 26);
508     jit.move(scratch1, scratch2);
509     jit.rshift64(AssemblyHelpers::TrustedImm32(26), scratch2);
510     jit.xor64(scratch1, scratch2);
511     jit.xor64(scratch2, scratch0);
512
513     // m_high = x;
514     storeToHigh(scratch0);
515
516     // return x + y;
517     jit.add64(scratch1, scratch0);
518
519     // Extract random 53bit. [0, 53] bit is safe integer number ranges in double representation.
520     jit.move(AssemblyHelpers::TrustedImm64((1ULL << 53) - 1), scratch1);
521     jit.and64(scratch1, scratch0);
522     // Now, scratch0 is always in range of int64_t. Safe to convert it to double with cvtsi2sdq.
523     jit.convertInt64ToDouble(scratch0, result);
524
525     // Convert `(53bit double integer value) / (1 << 53)` to `(53bit double integer value) * (1.0 / (1 << 53))`.
526     // In latter case, `1.0 / (1 << 53)` will become a double value represented as (mantissa = 0 & exp = 970, it means 1e-(2**54)).
527     static const double scale = 1.0 / (1ULL << 53);
528
529     // Multiplying 1e-(2**54) with the double integer does not change anything of the mantissa part of the double integer.
530     // It just reduces the exp part of the given 53bit double integer.
531     // (Except for 0.0. This is specially handled and in this case, exp just becomes 0.)
532     // Now we get 53bit precision random double value in [0, 1).
533     jit.move(AssemblyHelpers::TrustedImmPtr(&scale), scratch1);
534     jit.mulDouble(AssemblyHelpers::Address(scratch1), result);
535 }
536
537 void AssemblyHelpers::emitRandomThunk(JSGlobalObject* globalObject, GPRReg scratch0, GPRReg scratch1, GPRReg scratch2, FPRReg result)
538 {
539     void* lowAddress = reinterpret_cast<uint8_t*>(globalObject) + JSGlobalObject::weakRandomOffset() + WeakRandom::lowOffset();
540     void* highAddress = reinterpret_cast<uint8_t*>(globalObject) + JSGlobalObject::weakRandomOffset() + WeakRandom::highOffset();
541
542     auto loadFromHigh = [&](GPRReg high) {
543         load64(highAddress, high);
544     };
545     auto storeToHigh = [&](GPRReg high) {
546         store64(high, highAddress);
547     };
548     auto loadFromLow = [&](GPRReg low) {
549         load64(lowAddress, low);
550     };
551     auto storeToLow = [&](GPRReg low) {
552         store64(low, lowAddress);
553     };
554
555     emitRandomThunkImpl(*this, scratch0, scratch1, scratch2, result, loadFromHigh, storeToHigh, loadFromLow, storeToLow);
556 }
557
558 void AssemblyHelpers::emitRandomThunk(VM& vm, GPRReg scratch0, GPRReg scratch1, GPRReg scratch2, GPRReg scratch3, FPRReg result)
559 {
560     emitGetFromCallFrameHeaderPtr(CallFrameSlot::callee, scratch3);
561     emitLoadStructure(vm, scratch3, scratch3, scratch0);
562     loadPtr(Address(scratch3, Structure::globalObjectOffset()), scratch3);
563     // Now, scratch3 holds JSGlobalObject*.
564
565     auto loadFromHigh = [&](GPRReg high) {
566         load64(Address(scratch3, JSGlobalObject::weakRandomOffset() + WeakRandom::highOffset()), high);
567     };
568     auto storeToHigh = [&](GPRReg high) {
569         store64(high, Address(scratch3, JSGlobalObject::weakRandomOffset() + WeakRandom::highOffset()));
570     };
571     auto loadFromLow = [&](GPRReg low) {
572         load64(Address(scratch3, JSGlobalObject::weakRandomOffset() + WeakRandom::lowOffset()), low);
573     };
574     auto storeToLow = [&](GPRReg low) {
575         store64(low, Address(scratch3, JSGlobalObject::weakRandomOffset() + WeakRandom::lowOffset()));
576     };
577
578     emitRandomThunkImpl(*this, scratch0, scratch1, scratch2, result, loadFromHigh, storeToHigh, loadFromLow, storeToLow);
579 }
580 #endif
581
582 void AssemblyHelpers::restoreCalleeSavesFromVMEntryFrameCalleeSavesBuffer(VM& vm)
583 {
584 #if NUMBER_OF_CALLEE_SAVES_REGISTERS > 0
585     RegisterAtOffsetList* allCalleeSaves = VM::getAllCalleeSaveRegisterOffsets();
586     RegisterSet dontRestoreRegisters = RegisterSet::stackRegisters();
587     unsigned registerCount = allCalleeSaves->size();
588
589     GPRReg scratch = InvalidGPRReg;
590     unsigned scratchGPREntryIndex = 0;
591
592     // Use the first GPR entry's register as our scratch.
593     for (unsigned i = 0; i < registerCount; i++) {
594         RegisterAtOffset entry = allCalleeSaves->at(i);
595         if (dontRestoreRegisters.get(entry.reg()))
596             continue;
597         if (entry.reg().isGPR()) {
598             scratchGPREntryIndex = i;
599             scratch = entry.reg().gpr();
600             break;
601         }
602     }
603     ASSERT(scratch != InvalidGPRReg);
604
605     loadPtr(&vm.topVMEntryFrame, scratch);
606     addPtr(TrustedImm32(VMEntryFrame::calleeSaveRegistersBufferOffset()), scratch);
607
608     // Restore all callee saves except for the scratch.
609     for (unsigned i = 0; i < registerCount; i++) {
610         RegisterAtOffset entry = allCalleeSaves->at(i);
611         if (dontRestoreRegisters.get(entry.reg()))
612             continue;
613         if (entry.reg().isGPR()) {
614             if (i != scratchGPREntryIndex)
615                 loadPtr(Address(scratch, entry.offset()), entry.reg().gpr());
616         } else
617             loadDouble(Address(scratch, entry.offset()), entry.reg().fpr());
618     }
619
620     // Restore the callee save value of the scratch.
621     RegisterAtOffset entry = allCalleeSaves->at(scratchGPREntryIndex);
622     ASSERT(!dontRestoreRegisters.get(entry.reg()));
623     ASSERT(entry.reg().isGPR());
624     ASSERT(scratch == entry.reg().gpr());
625     loadPtr(Address(scratch, entry.offset()), scratch);
626 #else
627     UNUSED_PARAM(vm);
628 #endif
629 }
630
631 void AssemblyHelpers::emitDumbVirtualCall(VM& vm, CallLinkInfo* info)
632 {
633     move(TrustedImmPtr(info), GPRInfo::regT2);
634     Call call = nearCall();
635     addLinkTask(
636         [=, &vm] (LinkBuffer& linkBuffer) {
637             MacroAssemblerCodeRef virtualThunk = virtualThunkFor(&vm, *info);
638             info->setSlowStub(createJITStubRoutine(virtualThunk, vm, nullptr, true));
639             linkBuffer.link(call, CodeLocationLabel(virtualThunk.code()));
640         });
641 }
642
643 #if USE(JSVALUE64)
644 void AssemblyHelpers::wangsInt64Hash(GPRReg inputAndResult, GPRReg scratch)
645 {
646     GPRReg input = inputAndResult;
647     // key += ~(key << 32);
648     move(input, scratch);
649     lshift64(TrustedImm32(32), scratch);
650     not64(scratch);
651     add64(scratch, input);
652     // key ^= (key >> 22);
653     move(input, scratch);
654     urshift64(TrustedImm32(22), scratch);
655     xor64(scratch, input);
656     // key += ~(key << 13);
657     move(input, scratch);
658     lshift64(TrustedImm32(13), scratch);
659     not64(scratch);
660     add64(scratch, input);
661     // key ^= (key >> 8);
662     move(input, scratch);
663     urshift64(TrustedImm32(8), scratch);
664     xor64(scratch, input);
665     // key += (key << 3);
666     move(input, scratch);
667     lshift64(TrustedImm32(3), scratch);
668     add64(scratch, input);
669     // key ^= (key >> 15);
670     move(input, scratch);
671     urshift64(TrustedImm32(15), scratch);
672     xor64(scratch, input);
673     // key += ~(key << 27);
674     move(input, scratch);
675     lshift64(TrustedImm32(27), scratch);
676     not64(scratch);
677     add64(scratch, input);
678     // key ^= (key >> 31);
679     move(input, scratch);
680     urshift64(TrustedImm32(31), scratch);
681     xor64(scratch, input);
682
683     // return static_cast<unsigned>(result)
684     void* mask = bitwise_cast<void*>(static_cast<uintptr_t>(UINT_MAX));
685     and64(TrustedImmPtr(mask), inputAndResult);
686 }
687 #endif // USE(JSVALUE64)
688
689 void AssemblyHelpers::emitConvertValueToBoolean(VM& vm, JSValueRegs value, GPRReg result, GPRReg scratch, FPRReg valueAsFPR, FPRReg tempFPR, bool shouldCheckMasqueradesAsUndefined, JSGlobalObject* globalObject, bool negateResult)
690 {
691     // Implements the following control flow structure:
692     // if (value is boolean) {
693     //     result = value === true
694     // } else if (value is integer) {
695     //     result = value !== 0
696     // } else if (value is double) {
697     //     result = value !== 0.0 && !isNaN(value);
698     // } else if (value is cell) {
699     //     if (value is string) {
700     //          result = value.length() !== 0;
701     //     } else {
702     //          do crazy things for masquerades as undefined
703     //     }
704     // } else {
705     //     result = false;
706     // }
707     //
708     // if (negateResult)
709     //     result = !result;
710
711     JumpList done;
712     auto notBoolean = branchIfNotBoolean(value, result);
713 #if USE(JSVALUE64)
714     compare32(negateResult ? NotEqual : Equal, value.gpr(), TrustedImm32(ValueTrue), result);
715 #else
716     compare32(negateResult ? Equal : NotEqual, value.payloadGPR(), TrustedImm32(0), result);
717 #endif
718     done.append(jump());
719
720     notBoolean.link(this);
721 #if USE(JSVALUE64)
722     auto isNotNumber = branchIfNotNumber(value.gpr());
723 #else
724     ASSERT(scratch != InvalidGPRReg);
725     auto isNotNumber = branchIfNotNumber(value, scratch);
726 #endif
727     auto isDouble = branchIfNotInt32(value);
728
729     // It's an int32.
730     compare32(negateResult ? Equal : NotEqual, value.payloadGPR(), TrustedImm32(0), result);
731     done.append(jump());
732
733     isDouble.link(this);
734 #if USE(JSVALUE64)
735     unboxDouble(value.gpr(), result, valueAsFPR);
736 #else
737     unboxDouble(value, valueAsFPR, tempFPR);
738 #endif
739     auto isZeroOrNaN = branchDoubleZeroOrNaN(valueAsFPR, tempFPR);
740     move(negateResult ? TrustedImm32(0) : TrustedImm32(1), result);
741     done.append(jump());
742     isZeroOrNaN.link(this);
743     move(negateResult ? TrustedImm32(1) : TrustedImm32(0), result);
744     done.append(jump());
745
746     isNotNumber.link(this);
747     auto isNotCellAndIsNotNumberAndIsNotBoolean = branchIfNotCell(value);
748     auto isCellButNotString = branch8(NotEqual,
749         Address(value.payloadGPR(), JSCell::typeInfoTypeOffset()), TrustedImm32(StringType));
750     load32(Address(value.payloadGPR(), JSString::offsetOfLength()), result);
751     compare32(negateResult ? Equal : NotEqual, result, TrustedImm32(0), result);
752     done.append(jump());
753
754     isCellButNotString.link(this);
755     if (shouldCheckMasqueradesAsUndefined) {
756         ASSERT(scratch != InvalidGPRReg);
757         JumpList isNotMasqueradesAsUndefined;
758         isNotMasqueradesAsUndefined.append(branchTest8(Zero, Address(value.payloadGPR(), JSCell::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)));
759         emitLoadStructure(vm, value.payloadGPR(), result, scratch);
760         move(TrustedImmPtr(globalObject), scratch);
761         isNotMasqueradesAsUndefined.append(branchPtr(NotEqual, Address(result, Structure::globalObjectOffset()), scratch));
762         // We act like we are "undefined" here.
763         move(negateResult ? TrustedImm32(1) : TrustedImm32(0), result);
764         done.append(jump());
765         isNotMasqueradesAsUndefined.link(this);
766     }
767     move(negateResult ? TrustedImm32(0) : TrustedImm32(1), result);
768     done.append(jump());
769
770     // null or undefined.
771     isNotCellAndIsNotNumberAndIsNotBoolean.link(this); 
772     move(negateResult ? TrustedImm32(1) : TrustedImm32(0), result);
773
774     done.link(this);
775 }
776
777 #if ENABLE(WEBASSEMBLY)
778 void AssemblyHelpers::loadWasmContext(GPRReg dst)
779 {
780 #if ENABLE(FAST_TLS_JIT)
781     if (Wasm::useFastTLSForContext()) {
782         loadFromTLSPtr(fastTLSOffsetForKey(WTF_WASM_CONTEXT_KEY), dst);
783         return;
784     }
785 #endif
786     move(Wasm::PinnedRegisterInfo::get().wasmContextPointer, dst);
787 }
788
789 void AssemblyHelpers::storeWasmContext(GPRReg src)
790 {
791 #if ENABLE(FAST_TLS_JIT)
792     if (Wasm::useFastTLSForContext()) {
793         storeToTLSPtr(src, fastTLSOffsetForKey(WTF_WASM_CONTEXT_KEY));
794         return;
795     }
796 #endif
797     move(src, Wasm::PinnedRegisterInfo::get().wasmContextPointer);
798 }
799
800 bool AssemblyHelpers::loadWasmContextNeedsMacroScratchRegister()
801 {
802 #if ENABLE(FAST_TLS_JIT)
803     if (Wasm::useFastTLSForContext())
804         return loadFromTLSPtrNeedsMacroScratchRegister();
805 #endif
806     return false;
807 }
808
809 bool AssemblyHelpers::storeWasmContextNeedsMacroScratchRegister()
810 {
811 #if ENABLE(FAST_TLS_JIT)
812     if (Wasm::useFastTLSForContext())
813         return storeToTLSPtrNeedsMacroScratchRegister();
814 #endif
815     return false;
816 }
817
818 #endif // ENABLE(WEBASSEMBLY)
819
820 void AssemblyHelpers::debugCall(VM& vm, V_DebugOperation_EPP function, void* argument)
821 {
822     size_t scratchSize = sizeof(EncodedJSValue) * (GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters);
823     ScratchBuffer* scratchBuffer = vm.scratchBufferForSize(scratchSize);
824     EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
825
826     for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
827 #if USE(JSVALUE64)
828         store64(GPRInfo::toRegister(i), buffer + i);
829 #else
830         store32(GPRInfo::toRegister(i), buffer + i);
831 #endif
832     }
833
834     for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
835         move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
836         storeDouble(FPRInfo::toRegister(i), GPRInfo::regT0);
837     }
838
839     // Tell GC mark phase how much of the scratch buffer is active during call.
840     move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
841     storePtr(TrustedImmPtr(scratchSize), GPRInfo::regT0);
842
843 #if CPU(X86_64) || CPU(ARM) || CPU(ARM64) || CPU(MIPS)
844     move(TrustedImmPtr(buffer), GPRInfo::argumentGPR2);
845     move(TrustedImmPtr(argument), GPRInfo::argumentGPR1);
846     move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
847     GPRReg scratch = selectScratchGPR(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::argumentGPR2);
848 #elif CPU(X86)
849     poke(GPRInfo::callFrameRegister, 0);
850     poke(TrustedImmPtr(argument), 1);
851     poke(TrustedImmPtr(buffer), 2);
852     GPRReg scratch = GPRInfo::regT0;
853 #else
854 #error "JIT not supported on this platform."
855 #endif
856     move(TrustedImmPtr(reinterpret_cast<void*>(function)), scratch);
857     call(scratch);
858
859     move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
860     storePtr(TrustedImmPtr(0), GPRInfo::regT0);
861
862     for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
863         move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
864         loadDouble(GPRInfo::regT0, FPRInfo::toRegister(i));
865     }
866     for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
867 #if USE(JSVALUE64)
868         load64(buffer + i, GPRInfo::toRegister(i));
869 #else
870         load32(buffer + i, GPRInfo::toRegister(i));
871 #endif
872     }
873 }
874
875 void AssemblyHelpers::copyCalleeSavesToVMEntryFrameCalleeSavesBufferImpl(GPRReg calleeSavesBuffer)
876 {
877 #if NUMBER_OF_CALLEE_SAVES_REGISTERS > 0
878     addPtr(TrustedImm32(VMEntryFrame::calleeSaveRegistersBufferOffset()), calleeSavesBuffer);
879
880     RegisterAtOffsetList* allCalleeSaves = VM::getAllCalleeSaveRegisterOffsets();
881     RegisterSet dontCopyRegisters = RegisterSet::stackRegisters();
882     unsigned registerCount = allCalleeSaves->size();
883     
884     for (unsigned i = 0; i < registerCount; i++) {
885         RegisterAtOffset entry = allCalleeSaves->at(i);
886         if (dontCopyRegisters.get(entry.reg()))
887             continue;
888         if (entry.reg().isGPR())
889             storePtr(entry.reg().gpr(), Address(calleeSavesBuffer, entry.offset()));
890         else
891             storeDouble(entry.reg().fpr(), Address(calleeSavesBuffer, entry.offset()));
892     }
893 #else
894     UNUSED_PARAM(calleeSavesBuffer);
895 #endif
896 }
897
898 } // namespace JSC
899
900 #endif // ENABLE(JIT)
901