[JSC] Remove gcc warnings on mips and armv7
[WebKit-https.git] / Source / JavaScriptCore / assembler / testmasm.cpp
1 /*
2  * Copyright (C) 2017-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
28 #include "CCallHelpers.h"
29 #include "CPU.h"
30 #include "FPRInfo.h"
31 #include "GPRInfo.h"
32 #include "InitializeThreading.h"
33 #include "LinkBuffer.h"
34 #include "ProbeContext.h"
35 #include "StackAlignment.h"
36 #include <limits>
37 #include <wtf/Compiler.h>
38 #include <wtf/DataLog.h>
39 #include <wtf/Function.h>
40 #include <wtf/Lock.h>
41 #include <wtf/NumberOfCores.h>
42 #include <wtf/Threading.h>
43
44 // We don't have a NO_RETURN_DUE_TO_EXIT, nor should we. That's ridiculous.
45 static bool hiddenTruthBecauseNoReturnIsStupid() { return true; }
46
47 static void usage()
48 {
49     dataLog("Usage: testmasm [<filter>]\n");
50     if (hiddenTruthBecauseNoReturnIsStupid())
51         exit(1);
52 }
53
54 #if ENABLE(JIT)
55
56 #if ENABLE(MASM_PROBE)
57 namespace WTF {
58
59 static void printInternal(PrintStream& out, void* value)
60 {
61     out.printf("%p", value);
62 }
63
64 } // namespace WTF
65 #endif // ENABLE(MASM_PROBE)
66
67 namespace JSC {
68 namespace Probe {
69
70 JS_EXPORT_PRIVATE void* probeStateForContext(Probe::Context&);
71
72 } // namespace Probe
73 } // namespace JSC
74
75 using namespace JSC;
76
77 namespace {
78
79 #if ENABLE(MASM_PROBE)
80 using CPUState = Probe::CPUState;
81 #endif
82
83 Lock crashLock;
84
85 typedef WTF::Function<void(CCallHelpers&)> Generator;
86
87 template<typename T> T nextID(T id) { return static_cast<T>(id + 1); }
88
89 #define TESTWORD64 0x0c0defefebeef000
90 #define TESTWORD32 0x0beef000
91
92 #define testWord32(x) (TESTWORD32 + static_cast<uint32_t>(x))
93 #define testWord64(x) (TESTWORD64 + static_cast<uint64_t>(x))
94
95 #if USE(JSVALUE64)
96 #define testWord(x) testWord64(x)
97 #else
98 #define testWord(x) testWord32(x)
99 #endif
100
101 // Nothing fancy for now; we just use the existing WTF assertion machinery.
102 #define CHECK_EQ(_actual, _expected) do {                               \
103         if ((_actual) == (_expected))                                   \
104             break;                                                      \
105         crashLock.lock();                                               \
106         dataLog("FAILED while testing " #_actual ": expected: ", _expected, ", actual: ", _actual, "\n"); \
107         WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, "CHECK_EQ("#_actual ", " #_expected ")"); \
108         CRASH();                                                        \
109     } while (false)
110
111 #if ENABLE(MASM_PROBE)
112 bool isPC(MacroAssembler::RegisterID id)
113 {
114 #if CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
115     return id == ARMRegisters::pc;
116 #else
117     UNUSED_PARAM(id);
118     return false;
119 #endif
120 }
121
122 bool isSP(MacroAssembler::RegisterID id)
123 {
124     return id == MacroAssembler::stackPointerRegister;
125 }
126
127 bool isFP(MacroAssembler::RegisterID id)
128 {
129     return id == MacroAssembler::framePointerRegister;
130 }
131
132 bool isSpecialGPR(MacroAssembler::RegisterID id)
133 {
134     if (isPC(id) || isSP(id) || isFP(id))
135         return true;
136 #if CPU(ARM64)
137     if (id == ARM64Registers::x18)
138         return true;
139 #elif CPU(MIPS)
140     if (id == MIPSRegisters::zero || id == MIPSRegisters::k0 || id == MIPSRegisters::k1)
141         return true;
142 #endif
143     return false;
144 }
145 #endif // ENABLE(MASM_PROBE)
146
147 MacroAssemblerCodeRef<JSEntryPtrTag> compile(Generator&& generate)
148 {
149     CCallHelpers jit;
150     generate(jit);
151     LinkBuffer linkBuffer(jit, nullptr);
152     return FINALIZE_CODE(linkBuffer, JSEntryPtrTag, "testmasm compilation");
153 }
154
155 template<typename T, typename... Arguments>
156 T invoke(MacroAssemblerCodeRef<JSEntryPtrTag> code, Arguments... arguments)
157 {
158     void* executableAddress = untagCFunctionPtr<JSEntryPtrTag>(code.code().executableAddress());
159     T (*function)(Arguments...) = bitwise_cast<T(*)(Arguments...)>(executableAddress);
160     return function(arguments...);
161 }
162
163 template<typename T, typename... Arguments>
164 T compileAndRun(Generator&& generator, Arguments... arguments)
165 {
166     return invoke<T>(compile(WTFMove(generator)), arguments...);
167 }
168
169 void testSimple()
170 {
171     CHECK_EQ(compileAndRun<int>([] (CCallHelpers& jit) {
172         jit.emitFunctionPrologue();
173         jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR);
174         jit.emitFunctionEpilogue();
175         jit.ret();
176     }), 42);
177 }
178
179 void testGetEffectiveAddress(size_t pointer, ptrdiff_t length, int32_t offset, CCallHelpers::Scale scale)
180 {
181     CHECK_EQ(compileAndRun<size_t>([=] (CCallHelpers& jit) {
182         jit.emitFunctionPrologue();
183         jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(pointer)), GPRInfo::regT0);
184         jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(length)), GPRInfo::regT1);
185         jit.getEffectiveAddress(CCallHelpers::BaseIndex(GPRInfo::regT0, GPRInfo::regT1, scale, offset), GPRInfo::returnValueGPR);
186         jit.emitFunctionEpilogue();
187         jit.ret();
188     }), pointer + offset + (static_cast<size_t>(1) << static_cast<int>(scale)) * length);
189 }
190
191 // branchTruncateDoubleToInt32(), when encountering Infinity, -Infinity or a
192 // Nan, should either yield 0 in dest or fail.
193 void testBranchTruncateDoubleToInt32(double val, int32_t expected)
194 {
195     const uint64_t valAsUInt = *reinterpret_cast<uint64_t*>(&val);
196 #if CPU(BIG_ENDIAN)
197     const bool isBigEndian = true;
198 #else
199     const bool isBigEndian = false;
200 #endif
201     CHECK_EQ(compileAndRun<int>([&] (CCallHelpers& jit) {
202         jit.emitFunctionPrologue();
203         jit.subPtr(CCallHelpers::TrustedImm32(stackAlignmentBytes()), MacroAssembler::stackPointerRegister);
204         if (isBigEndian) {
205             jit.store32(CCallHelpers::TrustedImm32(valAsUInt >> 32),
206                 MacroAssembler::stackPointerRegister);
207             jit.store32(CCallHelpers::TrustedImm32(valAsUInt & 0xffffffff),
208                 MacroAssembler::Address(MacroAssembler::stackPointerRegister, 4));
209         } else {
210             jit.store32(CCallHelpers::TrustedImm32(valAsUInt & 0xffffffff),
211                 MacroAssembler::stackPointerRegister);
212             jit.store32(CCallHelpers::TrustedImm32(valAsUInt >> 32),
213                 MacroAssembler::Address(MacroAssembler::stackPointerRegister, 4));
214         }
215         jit.loadDouble(MacroAssembler::stackPointerRegister, FPRInfo::fpRegT0);
216
217         MacroAssembler::Jump done;
218         done = jit.branchTruncateDoubleToInt32(FPRInfo::fpRegT0, GPRInfo::returnValueGPR, MacroAssembler::BranchIfTruncateSuccessful);
219
220         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
221
222         done.link(&jit);
223         jit.addPtr(CCallHelpers::TrustedImm32(stackAlignmentBytes()), MacroAssembler::stackPointerRegister);
224         jit.emitFunctionEpilogue();
225         jit.ret();
226     }), expected);
227 }
228
229
230 static Vector<double> doubleOperands()
231 {
232     return Vector<double> {
233         0,
234         -0,
235         1,
236         -1,
237         42,
238         -42,
239         std::numeric_limits<double>::max(),
240         std::numeric_limits<double>::min(),
241         std::numeric_limits<double>::lowest(),
242         std::numeric_limits<double>::quiet_NaN(),
243         std::numeric_limits<double>::infinity(),
244         -std::numeric_limits<double>::infinity(),
245     };
246 }
247
248
249 static Vector<float> UNUSED_FUNCTION floatOperands()
250 {
251     return Vector<float> {
252         0,
253         -0,
254         1,
255         -1,
256         42,
257         -42,
258         std::numeric_limits<float>::max(),
259         std::numeric_limits<float>::min(),
260         std::numeric_limits<float>::lowest(),
261         std::numeric_limits<float>::quiet_NaN(),
262         std::numeric_limits<float>::infinity(),
263         -std::numeric_limits<float>::infinity(),
264     };
265 }
266
267
268 void testCompareDouble(MacroAssembler::DoubleCondition condition)
269 {
270     double arg1 = 0;
271     double arg2 = 0;
272
273     auto compareDouble = compile([&, condition] (CCallHelpers& jit) {
274         jit.emitFunctionPrologue();
275
276         jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
277         jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
278         jit.move(CCallHelpers::TrustedImm32(-1), GPRInfo::returnValueGPR);
279         jit.compareDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1, GPRInfo::returnValueGPR);
280
281         jit.emitFunctionEpilogue();
282         jit.ret();
283     });
284
285     auto compareDoubleGeneric = compile([&, condition] (CCallHelpers& jit) {
286         jit.emitFunctionPrologue();
287
288         jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
289         jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
290         jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR);
291         auto jump = jit.branchDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1);
292         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
293         jump.link(&jit);
294
295         jit.emitFunctionEpilogue();
296         jit.ret();
297     });
298
299     auto operands = doubleOperands();
300     for (auto a : operands) {
301         for (auto b : operands) {
302             arg1 = a;
303             arg2 = b;
304             CHECK_EQ(invoke<int>(compareDouble), invoke<int>(compareDoubleGeneric));
305         }
306     }
307 }
308
309 #if CPU(X86) || CPU(X86_64) || CPU(ARM64)
310 void testCompareFloat(MacroAssembler::DoubleCondition condition)
311 {
312     float arg1 = 0;
313     float arg2 = 0;
314
315     auto compareFloat = compile([&, condition] (CCallHelpers& jit) {
316         jit.emitFunctionPrologue();
317
318         jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
319         jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
320         jit.move(CCallHelpers::TrustedImm32(-1), GPRInfo::returnValueGPR);
321         jit.compareFloat(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1, GPRInfo::returnValueGPR);
322
323         jit.emitFunctionEpilogue();
324         jit.ret();
325     });
326
327     auto compareFloatGeneric = compile([&, condition] (CCallHelpers& jit) {
328         jit.emitFunctionPrologue();
329
330         jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
331         jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
332         jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR);
333         auto jump = jit.branchFloat(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1);
334         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
335         jump.link(&jit);
336
337         jit.emitFunctionEpilogue();
338         jit.ret();
339     });
340
341     auto operands = floatOperands();
342     for (auto a : operands) {
343         for (auto b : operands) {
344             arg1 = a;
345             arg2 = b;
346             CHECK_EQ(invoke<int>(compareFloat), invoke<int>(compareFloatGeneric));
347         }
348     }
349 }
350 #endif
351
352 #if ENABLE(MASM_PROBE)
353 void testProbeReadsArgumentRegisters()
354 {
355     bool probeWasCalled = false;
356     compileAndRun<void>([&] (CCallHelpers& jit) {
357         jit.emitFunctionPrologue();
358
359         jit.pushPair(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1);
360         jit.pushPair(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3);
361
362         jit.move(CCallHelpers::TrustedImm32(testWord32(0)), GPRInfo::argumentGPR0);
363         jit.convertInt32ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT0);
364         jit.move(CCallHelpers::TrustedImm32(testWord32(1)), GPRInfo::argumentGPR0);
365         jit.convertInt32ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT1);
366 #if USE(JSVALUE64)
367         jit.move(CCallHelpers::TrustedImm64(testWord(0)), GPRInfo::argumentGPR0);
368         jit.move(CCallHelpers::TrustedImm64(testWord(1)), GPRInfo::argumentGPR1);
369         jit.move(CCallHelpers::TrustedImm64(testWord(2)), GPRInfo::argumentGPR2);
370         jit.move(CCallHelpers::TrustedImm64(testWord(3)), GPRInfo::argumentGPR3);
371 #else
372         jit.move(CCallHelpers::TrustedImm32(testWord(0)), GPRInfo::argumentGPR0);
373         jit.move(CCallHelpers::TrustedImm32(testWord(1)), GPRInfo::argumentGPR1);
374         jit.move(CCallHelpers::TrustedImm32(testWord(2)), GPRInfo::argumentGPR2);
375         jit.move(CCallHelpers::TrustedImm32(testWord(3)), GPRInfo::argumentGPR3);
376 #endif
377
378         jit.probe([&] (Probe::Context& context) {
379             auto& cpu = context.cpu;
380             probeWasCalled = true;
381             CHECK_EQ(cpu.gpr(GPRInfo::argumentGPR0), testWord(0));
382             CHECK_EQ(cpu.gpr(GPRInfo::argumentGPR1), testWord(1));
383             CHECK_EQ(cpu.gpr(GPRInfo::argumentGPR2), testWord(2));
384             CHECK_EQ(cpu.gpr(GPRInfo::argumentGPR3), testWord(3));
385
386             CHECK_EQ(cpu.fpr(FPRInfo::fpRegT0), testWord32(0));
387             CHECK_EQ(cpu.fpr(FPRInfo::fpRegT1), testWord32(1));
388         });
389
390         jit.popPair(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3);
391         jit.popPair(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1);
392
393         jit.emitFunctionEpilogue();
394         jit.ret();
395     });
396     CHECK_EQ(probeWasCalled, true);
397 }
398
399 void testProbeWritesArgumentRegisters()
400 {
401     // This test relies on testProbeReadsArgumentRegisters() having already validated
402     // that we can read from argument registers. We'll use that ability to validate
403     // that our writes did take effect.
404     unsigned probeCallCount = 0;
405     compileAndRun<void>([&] (CCallHelpers& jit) {
406         jit.emitFunctionPrologue();
407
408         jit.pushPair(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1);
409         jit.pushPair(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3);
410
411         // Pre-initialize with non-expected values.
412 #if USE(JSVALUE64)
413         jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::argumentGPR0);
414         jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::argumentGPR1);
415         jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::argumentGPR2);
416         jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::argumentGPR3);
417 #else
418         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::argumentGPR0);
419         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::argumentGPR1);
420         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::argumentGPR2);
421         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::argumentGPR3);
422 #endif
423         jit.convertInt32ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT0);
424         jit.convertInt32ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT1);
425
426         // Write expected values.
427         jit.probe([&] (Probe::Context& context) {
428             auto& cpu = context.cpu;
429             probeCallCount++;
430             cpu.gpr(GPRInfo::argumentGPR0) = testWord(0);
431             cpu.gpr(GPRInfo::argumentGPR1) = testWord(1);
432             cpu.gpr(GPRInfo::argumentGPR2) = testWord(2);
433             cpu.gpr(GPRInfo::argumentGPR3) = testWord(3);
434             
435             cpu.fpr(FPRInfo::fpRegT0) = bitwise_cast<double>(testWord64(0));
436             cpu.fpr(FPRInfo::fpRegT1) = bitwise_cast<double>(testWord64(1));
437         });
438
439         // Validate that expected values were written.
440         jit.probe([&] (Probe::Context& context) {
441             auto& cpu = context.cpu;
442             probeCallCount++;
443             CHECK_EQ(cpu.gpr(GPRInfo::argumentGPR0), testWord(0));
444             CHECK_EQ(cpu.gpr(GPRInfo::argumentGPR1), testWord(1));
445             CHECK_EQ(cpu.gpr(GPRInfo::argumentGPR2), testWord(2));
446             CHECK_EQ(cpu.gpr(GPRInfo::argumentGPR3), testWord(3));
447
448             CHECK_EQ(cpu.fpr<uint64_t>(FPRInfo::fpRegT0), testWord64(0));
449             CHECK_EQ(cpu.fpr<uint64_t>(FPRInfo::fpRegT1), testWord64(1));
450         });
451
452         jit.popPair(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3);
453         jit.popPair(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1);
454
455         jit.emitFunctionEpilogue();
456         jit.ret();
457     });
458     CHECK_EQ(probeCallCount, 2);
459 }
460
461 static NEVER_INLINE NOT_TAIL_CALLED int testFunctionToTrashGPRs(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j)
462 {
463     if (j > 0)
464         return testFunctionToTrashGPRs(a + 1, b + a, c + b, d + 5, e - a, f * 1.5, g ^ a, h - b, i, j - 1);
465     return a + 1;
466 }
467 static NEVER_INLINE NOT_TAIL_CALLED double testFunctionToTrashFPRs(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j)
468 {
469     if (j > 0)
470         return testFunctionToTrashFPRs(a + 1, b + a, c + b, d + 5, e - a, f * 1.5, pow(g, a), h - b, i, j - 1);
471     return a + 1;
472 }
473
474 void testProbePreservesGPRS()
475 {
476     // This test relies on testProbeReadsArgumentRegisters() and testProbeWritesArgumentRegisters()
477     // having already validated that we can read and write from registers. We'll use these abilities
478     // to validate that the probe preserves register values.
479     unsigned probeCallCount = 0;
480     CPUState originalState;
481
482     compileAndRun<void>([&] (CCallHelpers& jit) {
483         jit.emitFunctionPrologue();
484
485         // Write expected values into the registers (except for sp, fp, and pc).
486         jit.probe([&] (Probe::Context& context) {
487             auto& cpu = context.cpu;
488             probeCallCount++;
489             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
490                 originalState.gpr(id) = cpu.gpr(id);
491                 if (isSpecialGPR(id))
492                     continue;
493                 cpu.gpr(id) = testWord(static_cast<int>(id));
494             }
495             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id)) {
496                 originalState.fpr(id) = cpu.fpr(id);
497                 cpu.fpr(id) = bitwise_cast<double>(testWord64(id));
498             }
499         });
500
501         // Invoke the probe to call a lot of functions and trash register values.
502         jit.probe([&] (Probe::Context&) {
503             probeCallCount++;
504             CHECK_EQ(testFunctionToTrashGPRs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), 10);
505             CHECK_EQ(testFunctionToTrashFPRs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), 10);
506         });
507
508         // Validate that the registers have the expected values.
509         jit.probe([&] (Probe::Context& context) {
510             auto& cpu = context.cpu;
511             probeCallCount++;
512             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
513                 if (isSP(id) || isFP(id)) {
514                     CHECK_EQ(cpu.gpr(id), originalState.gpr(id));
515                     continue;
516                 }
517                 if (isSpecialGPR(id))
518                     continue;
519                 CHECK_EQ(cpu.gpr(id), testWord(id));
520             }
521             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
522 #if CPU(MIPS)
523                 if (!(id & 1))
524 #endif
525                 CHECK_EQ(cpu.fpr<uint64_t>(id), testWord64(id));
526         });
527
528         // Restore the original state.
529         jit.probe([&] (Probe::Context& context) {
530             auto& cpu = context.cpu;
531             probeCallCount++;
532             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
533                 if (isSpecialGPR(id))
534                     continue;
535                 cpu.gpr(id) = originalState.gpr(id);
536             }
537             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
538                 cpu.fpr(id) = originalState.fpr(id);
539         });
540
541         // Validate that the original state was restored.
542         jit.probe([&] (Probe::Context& context) {
543             auto& cpu = context.cpu;
544             probeCallCount++;
545             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
546                 if (isSpecialGPR(id))
547                     continue;
548                 CHECK_EQ(cpu.gpr(id), originalState.gpr(id));
549             }
550             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
551 #if CPU(MIPS)
552                 if (!(id & 1))
553 #endif
554                 CHECK_EQ(cpu.fpr<uint64_t>(id), originalState.fpr<uint64_t>(id));
555         });
556
557         jit.emitFunctionEpilogue();
558         jit.ret();
559     });
560     CHECK_EQ(probeCallCount, 5);
561 }
562
563 void testProbeModifiesStackPointer(WTF::Function<void*(Probe::Context&)> computeModifiedStackPointer)
564 {
565     unsigned probeCallCount = 0;
566     CPUState originalState;
567     void* originalSP { nullptr };
568     void* modifiedSP { nullptr };
569 #if !(CPU(MIPS))
570     uintptr_t modifiedFlags { 0 };
571 #endif
572     
573 #if CPU(X86) || CPU(X86_64)
574     auto flagsSPR = X86Registers::eflags;
575     uintptr_t flagsMask = 0xc5;
576 #elif CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
577     auto flagsSPR = ARMRegisters::apsr;
578     uintptr_t flagsMask = 0xf8000000;
579 #elif CPU(ARM64)
580     auto flagsSPR = ARM64Registers::nzcv;
581     uintptr_t flagsMask = 0xf0000000;
582 #endif
583
584     compileAndRun<void>([&] (CCallHelpers& jit) {
585         jit.emitFunctionPrologue();
586
587         // Preserve original stack pointer and modify the sp, and
588         // write expected values into other registers (except for fp, and pc).
589         jit.probe([&] (Probe::Context& context) {
590             auto& cpu = context.cpu;
591             probeCallCount++;
592             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
593                 originalState.gpr(id) = cpu.gpr(id);
594                 if (isSpecialGPR(id))
595                     continue;
596                 cpu.gpr(id) = testWord(static_cast<int>(id));
597             }
598             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id)) {
599                 originalState.fpr(id) = cpu.fpr(id);
600                 cpu.fpr(id) = bitwise_cast<double>(testWord64(id));
601             }
602
603 #if !(CPU(MIPS))
604             originalState.spr(flagsSPR) = cpu.spr(flagsSPR);
605             modifiedFlags = originalState.spr(flagsSPR) ^ flagsMask;
606             cpu.spr(flagsSPR) = modifiedFlags;
607 #endif
608
609             originalSP = cpu.sp();
610             modifiedSP = computeModifiedStackPointer(context);
611             cpu.sp() = modifiedSP;
612         });
613
614         // Validate that the registers have the expected values.
615         jit.probe([&] (Probe::Context& context) {
616             auto& cpu = context.cpu;
617             probeCallCount++;
618             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
619                 if (isFP(id)) {
620                     CHECK_EQ(cpu.gpr(id), originalState.gpr(id));
621                     continue;
622                 }
623                 if (isSpecialGPR(id))
624                     continue;
625                 CHECK_EQ(cpu.gpr(id), testWord(id));
626             }
627             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
628 #if CPU(MIPS)
629                 if (!(id & 1))
630 #endif
631                 CHECK_EQ(cpu.fpr<uint64_t>(id), testWord64(id));
632 #if !(CPU(MIPS))
633             CHECK_EQ(cpu.spr(flagsSPR) & flagsMask, modifiedFlags & flagsMask);
634 #endif
635             CHECK_EQ(cpu.sp(), modifiedSP);
636         });
637
638         // Restore the original state.
639         jit.probe([&] (Probe::Context& context) {
640             auto& cpu = context.cpu;
641             probeCallCount++;
642             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
643                 if (isSpecialGPR(id))
644                     continue;
645                 cpu.gpr(id) = originalState.gpr(id);
646             }
647             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
648                 cpu.fpr(id) = originalState.fpr(id);
649 #if !(CPU(MIPS))
650             cpu.spr(flagsSPR) = originalState.spr(flagsSPR);
651 #endif
652             cpu.sp() = originalSP;
653         });
654
655         // Validate that the original state was restored.
656         jit.probe([&] (Probe::Context& context) {
657             auto& cpu = context.cpu;
658             probeCallCount++;
659             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
660                 if (isSpecialGPR(id))
661                     continue;
662                 CHECK_EQ(cpu.gpr(id), originalState.gpr(id));
663             }
664             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
665 #if CPU(MIPS)
666                 if (!(id & 1))
667 #endif
668                 CHECK_EQ(cpu.fpr<uint64_t>(id), originalState.fpr<uint64_t>(id));
669 #if !(CPU(MIPS))
670             CHECK_EQ(cpu.spr(flagsSPR) & flagsMask, originalState.spr(flagsSPR) & flagsMask);
671 #endif
672             CHECK_EQ(cpu.sp(), originalSP);
673         });
674
675         jit.emitFunctionEpilogue();
676         jit.ret();
677     });
678     CHECK_EQ(probeCallCount, 4);
679 }
680
681 void testProbeModifiesStackPointerToInsideProbeStateOnStack()
682 {
683     size_t increment = sizeof(uintptr_t);
684 #if CPU(ARM64)
685     // The ARM64 probe uses ldp and stp which require 16 byte alignment.
686     increment = 2 * sizeof(uintptr_t);
687 #endif
688     for (size_t offset = 0; offset < sizeof(Probe::State); offset += increment) {
689         testProbeModifiesStackPointer([=] (Probe::Context& context) -> void* {
690             return reinterpret_cast<uint8_t*>(probeStateForContext(context)) + offset;
691
692         });
693     }
694 }
695
696 void testProbeModifiesStackPointerToNBytesBelowSP()
697 {
698     size_t increment = sizeof(uintptr_t);
699 #if CPU(ARM64)
700     // The ARM64 probe uses ldp and stp which require 16 byte alignment.
701     increment = 2 * sizeof(uintptr_t);
702 #endif
703     for (size_t offset = 0; offset < 1 * KB; offset += increment) {
704         testProbeModifiesStackPointer([=] (Probe::Context& context) -> void* {
705             return context.cpu.sp<uint8_t*>() - offset;
706         });
707     }
708 }
709
710 void testProbeModifiesProgramCounter()
711 {
712     // This test relies on testProbeReadsArgumentRegisters() and testProbeWritesArgumentRegisters()
713     // having already validated that we can read and write from registers. We'll use these abilities
714     // to validate that the probe preserves register values.
715     unsigned probeCallCount = 0;
716     bool continuationWasReached = false;
717
718     MacroAssemblerCodeRef<JSEntryPtrTag> continuation = compile([&] (CCallHelpers& jit) {
719         // Validate that we reached the continuation.
720         jit.probe([&] (Probe::Context&) {
721             probeCallCount++;
722             continuationWasReached = true;
723         });
724
725         jit.emitFunctionEpilogue();
726         jit.ret();
727     });
728
729     compileAndRun<void>([&] (CCallHelpers& jit) {
730         jit.emitFunctionPrologue();
731
732         // Write expected values into the registers.
733         jit.probe([&] (Probe::Context& context) {
734             probeCallCount++;
735             context.cpu.pc() = untagCodePtr(continuation.code().executableAddress(), JSEntryPtrTag);
736         });
737
738         jit.breakpoint(); // We should never get here.
739     });
740     CHECK_EQ(probeCallCount, 2);
741     CHECK_EQ(continuationWasReached, true);
742 }
743
744 void testProbeModifiesStackValues()
745 {
746     unsigned probeCallCount = 0;
747     CPUState originalState;
748     void* originalSP { nullptr };
749     void* newSP { nullptr };
750 #if !(CPU(MIPS))
751     uintptr_t modifiedFlags { 0 };
752 #endif
753     size_t numberOfExtraEntriesToWrite { 10 }; // ARM64 requires that this be 2 word aligned.
754
755 #if CPU(X86) || CPU(X86_64)
756     MacroAssembler::SPRegisterID flagsSPR = X86Registers::eflags;
757     uintptr_t flagsMask = 0xc5;
758 #elif CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
759     MacroAssembler::SPRegisterID flagsSPR = ARMRegisters::apsr;
760     uintptr_t flagsMask = 0xf8000000;
761 #elif CPU(ARM64)
762     MacroAssembler::SPRegisterID flagsSPR = ARM64Registers::nzcv;
763     uintptr_t flagsMask = 0xf0000000;
764 #endif
765
766     compileAndRun<void>([&] (CCallHelpers& jit) {
767         jit.emitFunctionPrologue();
768
769         // Write expected values into the registers.
770         jit.probe([&] (Probe::Context& context) {
771             auto& cpu = context.cpu;
772             auto& stack = context.stack();
773             probeCallCount++;
774
775             // Preserve the original CPU state.
776             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
777                 originalState.gpr(id) = cpu.gpr(id);
778                 if (isSpecialGPR(id))
779                     continue;
780                 cpu.gpr(id) = testWord(static_cast<int>(id));
781             }
782             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id)) {
783                 originalState.fpr(id) = cpu.fpr(id);
784                 cpu.fpr(id) = bitwise_cast<double>(testWord64(id));
785             }
786 #if !(CPU(MIPS))
787             originalState.spr(flagsSPR) = cpu.spr(flagsSPR);
788             modifiedFlags = originalState.spr(flagsSPR) ^ flagsMask;
789             cpu.spr(flagsSPR) = modifiedFlags;
790 #endif
791
792             // Ensure that we'll be writing over the regions of the stack where the Probe::State is.
793             originalSP = cpu.sp();
794             newSP = reinterpret_cast<uintptr_t*>(probeStateForContext(context)) - numberOfExtraEntriesToWrite;
795             cpu.sp() = newSP;
796
797             // Fill the stack with values.
798             uintptr_t* p = reinterpret_cast<uintptr_t*>(newSP);
799             int count = 0;
800             stack.set<double>(p++, 1.234567);
801             if (is32Bit())
802                 p++; // On 32-bit targets, a double takes up 2 uintptr_t.
803             while (p < reinterpret_cast<uintptr_t*>(originalSP))
804                 stack.set<uintptr_t>(p++, testWord(count++));
805         });
806
807         // Validate that the registers and stack have the expected values.
808         jit.probe([&] (Probe::Context& context) {
809             auto& cpu = context.cpu;
810             auto& stack = context.stack();
811             probeCallCount++;
812
813             // Validate the register values.
814             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
815                 if (isFP(id)) {
816                     CHECK_EQ(cpu.gpr(id), originalState.gpr(id));
817                     continue;
818                 }
819                 if (isSpecialGPR(id))
820                     continue;
821                 CHECK_EQ(cpu.gpr(id), testWord(id));
822             }
823             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
824 #if CPU(MIPS)
825                 if (!(id & 1))
826 #endif
827                 CHECK_EQ(cpu.fpr<uint64_t>(id), testWord64(id));
828 #if !(CPU(MIPS))
829             CHECK_EQ(cpu.spr(flagsSPR) & flagsMask, modifiedFlags & flagsMask);
830 #endif
831             CHECK_EQ(cpu.sp(), newSP);
832
833             // Validate the stack values.
834             uintptr_t* p = reinterpret_cast<uintptr_t*>(newSP);
835             int count = 0;
836             CHECK_EQ(stack.get<double>(p++), 1.234567);
837             if (is32Bit())
838                 p++; // On 32-bit targets, a double takes up 2 uintptr_t.
839             while (p < reinterpret_cast<uintptr_t*>(originalSP))
840                 CHECK_EQ(stack.get<uintptr_t>(p++), testWord(count++));
841         });
842
843         // Restore the original state.
844         jit.probe([&] (Probe::Context& context) {
845             auto& cpu = context.cpu;
846             probeCallCount++;
847             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
848                 if (isSpecialGPR(id))
849                     continue;
850                 cpu.gpr(id) = originalState.gpr(id);
851             }
852             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
853                 cpu.fpr(id) = originalState.fpr(id);
854 #if !(CPU(MIPS))
855             cpu.spr(flagsSPR) = originalState.spr(flagsSPR);
856 #endif
857             cpu.sp() = originalSP;
858         });
859
860         jit.emitFunctionEpilogue();
861         jit.ret();
862     });
863
864     CHECK_EQ(probeCallCount, 3);
865 }
866 #endif // ENABLE(MASM_PROBE)
867
868 void testByteSwap()
869 {
870 #if CPU(X86_64) || CPU(ARM64)
871     auto byteSwap16 = compile([] (CCallHelpers& jit) {
872         jit.emitFunctionPrologue();
873         jit.move(GPRInfo::argumentGPR0, GPRInfo::returnValueGPR);
874         jit.byteSwap16(GPRInfo::returnValueGPR);
875         jit.emitFunctionEpilogue();
876         jit.ret();
877     });
878     CHECK_EQ(invoke<uint64_t>(byteSwap16, 0xaabbccddee001122), static_cast<uint64_t>(0x2211));
879     CHECK_EQ(invoke<uint64_t>(byteSwap16, 0xaabbccddee00ffaa), static_cast<uint64_t>(0xaaff));
880
881     auto byteSwap32 = compile([] (CCallHelpers& jit) {
882         jit.emitFunctionPrologue();
883         jit.move(GPRInfo::argumentGPR0, GPRInfo::returnValueGPR);
884         jit.byteSwap32(GPRInfo::returnValueGPR);
885         jit.emitFunctionEpilogue();
886         jit.ret();
887     });
888     CHECK_EQ(invoke<uint64_t>(byteSwap32, 0xaabbccddee001122), static_cast<uint64_t>(0x221100ee));
889     CHECK_EQ(invoke<uint64_t>(byteSwap32, 0xaabbccddee00ffaa), static_cast<uint64_t>(0xaaff00ee));
890
891     auto byteSwap64 = compile([] (CCallHelpers& jit) {
892         jit.emitFunctionPrologue();
893         jit.move(GPRInfo::argumentGPR0, GPRInfo::returnValueGPR);
894         jit.byteSwap64(GPRInfo::returnValueGPR);
895         jit.emitFunctionEpilogue();
896         jit.ret();
897     });
898     CHECK_EQ(invoke<uint64_t>(byteSwap64, 0xaabbccddee001122), static_cast<uint64_t>(0x221100eeddccbbaa));
899     CHECK_EQ(invoke<uint64_t>(byteSwap64, 0xaabbccddee00ffaa), static_cast<uint64_t>(0xaaff00eeddccbbaa));
900 #endif
901 }
902
903 #define RUN(test) do {                          \
904         if (!shouldRun(#test))                  \
905             break;                              \
906         numberOfTests++;                        \
907         tasks.append(                           \
908             createSharedTask<void()>(           \
909                 [&] () {                        \
910                     dataLog(#test "...\n");     \
911                     test;                       \
912                     dataLog(#test ": OK!\n");   \
913                 }));                            \
914     } while (false);
915
916 void run(const char* filter)
917 {
918     JSC::initializeThreading();
919     unsigned numberOfTests = 0;
920
921     Deque<RefPtr<SharedTask<void()>>> tasks;
922
923     auto shouldRun = [&] (const char* testName) -> bool {
924 #if OS(UNIX)
925         return !filter || !!strcasestr(testName, filter);
926 #else
927         return !filter || !!strstr(testName, filter);
928 #endif
929     };
930
931     RUN(testSimple());
932     RUN(testGetEffectiveAddress(0xff00, 42, 8, CCallHelpers::TimesEight));
933     RUN(testGetEffectiveAddress(0xff00, -200, -300, CCallHelpers::TimesEight));
934     RUN(testBranchTruncateDoubleToInt32(0, 0));
935     RUN(testBranchTruncateDoubleToInt32(42, 42));
936     RUN(testBranchTruncateDoubleToInt32(42.7, 42));
937     RUN(testBranchTruncateDoubleToInt32(-1234, -1234));
938     RUN(testBranchTruncateDoubleToInt32(-1234.56, -1234));
939     RUN(testBranchTruncateDoubleToInt32(std::numeric_limits<double>::infinity(), 0));
940     RUN(testBranchTruncateDoubleToInt32(-std::numeric_limits<double>::infinity(), 0));
941     RUN(testBranchTruncateDoubleToInt32(std::numeric_limits<double>::quiet_NaN(), 0));
942     RUN(testBranchTruncateDoubleToInt32(std::numeric_limits<double>::signaling_NaN(), 0));
943     RUN(testBranchTruncateDoubleToInt32(std::numeric_limits<double>::max(), 0));
944     RUN(testBranchTruncateDoubleToInt32(-std::numeric_limits<double>::max(), 0));
945     // We run this last one to make sure that we don't use flags that were not
946     // reset to check a conversion result
947     RUN(testBranchTruncateDoubleToInt32(123, 123));
948
949     RUN(testCompareDouble(MacroAssembler::DoubleEqual));
950     RUN(testCompareDouble(MacroAssembler::DoubleNotEqual));
951     RUN(testCompareDouble(MacroAssembler::DoubleGreaterThan));
952     RUN(testCompareDouble(MacroAssembler::DoubleGreaterThanOrEqual));
953     RUN(testCompareDouble(MacroAssembler::DoubleLessThan));
954     RUN(testCompareDouble(MacroAssembler::DoubleLessThanOrEqual));
955     RUN(testCompareDouble(MacroAssembler::DoubleEqualOrUnordered));
956     RUN(testCompareDouble(MacroAssembler::DoubleNotEqualOrUnordered));
957     RUN(testCompareDouble(MacroAssembler::DoubleGreaterThanOrUnordered));
958     RUN(testCompareDouble(MacroAssembler::DoubleGreaterThanOrEqualOrUnordered));
959     RUN(testCompareDouble(MacroAssembler::DoubleLessThanOrUnordered));
960     RUN(testCompareDouble(MacroAssembler::DoubleLessThanOrEqualOrUnordered));
961
962 #if CPU(X86) || CPU(X86_64) || CPU(ARM64)
963     RUN(testCompareFloat(MacroAssembler::DoubleEqual));
964     RUN(testCompareFloat(MacroAssembler::DoubleNotEqual));
965     RUN(testCompareFloat(MacroAssembler::DoubleGreaterThan));
966     RUN(testCompareFloat(MacroAssembler::DoubleGreaterThanOrEqual));
967     RUN(testCompareFloat(MacroAssembler::DoubleLessThan));
968     RUN(testCompareFloat(MacroAssembler::DoubleLessThanOrEqual));
969     RUN(testCompareFloat(MacroAssembler::DoubleEqualOrUnordered));
970     RUN(testCompareFloat(MacroAssembler::DoubleNotEqualOrUnordered));
971     RUN(testCompareFloat(MacroAssembler::DoubleGreaterThanOrUnordered));
972     RUN(testCompareFloat(MacroAssembler::DoubleGreaterThanOrEqualOrUnordered));
973     RUN(testCompareFloat(MacroAssembler::DoubleLessThanOrUnordered));
974     RUN(testCompareFloat(MacroAssembler::DoubleLessThanOrEqualOrUnordered));
975 #endif
976
977 #if ENABLE(MASM_PROBE)
978     RUN(testProbeReadsArgumentRegisters());
979     RUN(testProbeWritesArgumentRegisters());
980     RUN(testProbePreservesGPRS());
981     RUN(testProbeModifiesStackPointerToInsideProbeStateOnStack());
982     RUN(testProbeModifiesStackPointerToNBytesBelowSP());
983     RUN(testProbeModifiesProgramCounter());
984     RUN(testProbeModifiesStackValues());
985 #endif // ENABLE(MASM_PROBE)
986
987     RUN(testByteSwap());
988
989     if (tasks.isEmpty())
990         usage();
991
992     Lock lock;
993
994     Vector<Ref<Thread>> threads;
995     for (unsigned i = filter ? 1 : WTF::numberOfProcessorCores(); i--;) {
996         threads.append(
997             Thread::create(
998                 "testmasm thread",
999                 [&] () {
1000                     for (;;) {
1001                         RefPtr<SharedTask<void()>> task;
1002                         {
1003                             LockHolder locker(lock);
1004                             if (tasks.isEmpty())
1005                                 return;
1006                             task = tasks.takeFirst();
1007                         }
1008
1009                         task->run();
1010                     }
1011                 }));
1012     }
1013
1014     for (auto& thread : threads)
1015         thread->waitForCompletion();
1016     crashLock.lock();
1017     dataLog("Completed ", numberOfTests, " tests\n");
1018 }
1019
1020 } // anonymous namespace
1021
1022 #else // not ENABLE(JIT)
1023
1024 static void run(const char*)
1025 {
1026     dataLog("JIT is not enabled.\n");
1027 }
1028
1029 #endif // ENABLE(JIT)
1030
1031 int main(int argc, char** argv)
1032 {
1033     const char* filter = nullptr;
1034     switch (argc) {
1035     case 1:
1036         break;
1037     case 2:
1038         filter = argv[1];
1039         break;
1040     default:
1041         usage();
1042         break;
1043     }
1044
1045     run(filter);
1046     return 0;
1047 }
1048
1049 #if OS(WINDOWS)
1050 extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
1051 {
1052     return main(argc, const_cast<char**>(argv));
1053 }
1054 #endif