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