[WPE] Add libepoxy to the Jhbuild moduleset
[WebKit-https.git] / Source / JavaScriptCore / assembler / testmasm.cpp
1 /*
2  * Copyright (C) 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
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 <wtf/Compiler.h>
35 #include <wtf/Lock.h>
36 #include <wtf/NumberOfCores.h>
37 #include <wtf/Threading.h>
38
39 // We don't have a NO_RETURN_DUE_TO_EXIT, nor should we. That's ridiculous.
40 static bool hiddenTruthBecauseNoReturnIsStupid() { return true; }
41
42 static void usage()
43 {
44     dataLog("Usage: testmasm [<filter>]\n");
45     if (hiddenTruthBecauseNoReturnIsStupid())
46         exit(1);
47 }
48
49 #if ENABLE(JIT)
50
51 using namespace JSC;
52
53 namespace {
54
55 StaticLock crashLock;
56
57 typedef std::function<void(CCallHelpers&)> Generator;
58
59 template<typename T> T nextID(T id) { return static_cast<T>(id + 1); }
60
61 #define TESTWORD64 0x0c0defefebeef000
62 #define TESTWORD32 0x0beef000
63
64 #define testWord32(x) (TESTWORD32 + static_cast<uint32_t>(x))
65 #define testWord64(x) (TESTWORD64 + static_cast<uint64_t>(x))
66
67 #if ENABLE(JSVALUE64)
68 #define testWord(x) testWord64(x)
69 #else
70 #define testWord(x) testWord32(x)
71 #endif
72
73 // Nothing fancy for now; we just use the existing WTF assertion machinery.
74 #define CHECK(x) do {                                                   \
75         if (!!(x))                                                      \
76             break;                                                      \
77         crashLock.lock();                                               \
78         WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #x); \
79         CRASH();                                                        \
80     } while (false)
81
82 #if ENABLE(MASM_PROBE)
83 bool isPC(MacroAssembler::RegisterID id)
84 {
85 #if CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
86     return id == ARMRegisters::pc;
87 #else
88     UNUSED_PARAM(id);
89     return false;
90 #endif
91 }
92
93 bool isSP(MacroAssembler::RegisterID id)
94 {
95     return id == MacroAssembler::stackPointerRegister;
96 }
97
98 bool isFP(MacroAssembler::RegisterID id)
99 {
100     return id == MacroAssembler::framePointerRegister;
101 }
102 #endif // ENABLE(MASM_PROBE)
103
104 MacroAssemblerCodeRef compile(Generator generate)
105 {
106     CCallHelpers jit;
107     generate(jit);
108     LinkBuffer linkBuffer(jit, nullptr);
109     return FINALIZE_CODE(linkBuffer, ("testmasm compilation"));
110 }
111
112 template<typename T, typename... Arguments>
113 T invoke(MacroAssemblerCodeRef code, Arguments... arguments)
114 {
115     T (*function)(Arguments...) = bitwise_cast<T(*)(Arguments...)>(code.code().executableAddress());
116     return function(arguments...);
117 }
118
119 template<typename T, typename... Arguments>
120 T compileAndRun(Generator generator, Arguments... arguments)
121 {
122     return invoke<T>(compile(generator), arguments...);
123 }
124
125 void testSimple()
126 {
127     CHECK(compileAndRun<int>([] (CCallHelpers& jit) {
128         jit.emitFunctionPrologue();
129         jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR);
130         jit.emitFunctionEpilogue();
131         jit.ret();
132     }) == 42);
133 }
134
135 #if ENABLE(MASM_PROBE)
136 void testProbeReadsArgumentRegisters()
137 {
138     bool success = true;
139     compileAndRun<void>([&] (CCallHelpers& jit) {
140         jit.emitFunctionPrologue();
141
142         jit.move(CCallHelpers::TrustedImm32(testWord(0)), GPRInfo::argumentGPR0);
143         jit.convertInt32ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT0);
144         jit.move(CCallHelpers::TrustedImm32(testWord(1)), GPRInfo::argumentGPR0);
145         jit.convertInt32ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT1);
146 #if ENABLE(JSVALUE64)
147         jit.move(CCallHelpers::TrustedImm64(testWord(0)), GPRInfo::argumentGPR0);
148         jit.move(CCallHelpers::TrustedImm64(testWord(1)), GPRInfo::argumentGPR1);
149         jit.move(CCallHelpers::TrustedImm64(testWord(2)), GPRInfo::argumentGPR2);
150         jit.move(CCallHelpers::TrustedImm64(testWord(3)), GPRInfo::argumentGPR3);
151 #else
152         jit.move(CCallHelpers::TrustedImm32(testWord(0)), GPRInfo::argumentGPR0);
153         jit.move(CCallHelpers::TrustedImm32(testWord(1)), GPRInfo::argumentGPR1);
154         jit.move(CCallHelpers::TrustedImm32(testWord(2)), GPRInfo::argumentGPR2);
155         jit.move(CCallHelpers::TrustedImm32(testWord(3)), GPRInfo::argumentGPR3);
156 #endif
157
158         jit.probe([&] (ProbeContext* context) {
159             success = success && context->gpr(GPRInfo::argumentGPR0) == testWord(0);
160             success = success && context->gpr(GPRInfo::argumentGPR1) == testWord(1);
161             success = success && context->gpr(GPRInfo::argumentGPR2) == testWord(2);
162             success = success && context->gpr(GPRInfo::argumentGPR3) == testWord(3);
163
164             success = success && context->fpr(FPRInfo::fpRegT0) == testWord32(0);
165             success = success && context->fpr(FPRInfo::fpRegT1) == testWord32(1);
166         });
167         jit.emitFunctionEpilogue();
168         jit.ret();
169     });
170     CHECK(success);
171 }
172
173 void testProbeWritesArgumentRegisters()
174 {
175     // This test relies on testProbeReadsArgumentRegisters() having already validated
176     // that we can read from argument registers. We'll use that ability to validate
177     // that our writes did take effect.
178     bool success = true;
179     compileAndRun<void>([&] (CCallHelpers& jit) {
180         jit.emitFunctionPrologue();
181
182         // Pre-initialize with non-expected values.
183 #if ENABLE(JSVALUE64)
184         jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::argumentGPR0);
185         jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::argumentGPR1);
186         jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::argumentGPR2);
187         jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::argumentGPR3);
188 #else
189         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::argumentGPR0);
190         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::argumentGPR1);
191         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::argumentGPR2);
192         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::argumentGPR3);
193 #endif
194         jit.convertInt32ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT0);
195         jit.convertInt32ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT1);
196
197         // Write expected values.
198         jit.probe([] (ProbeContext* context) {
199             context->gpr(GPRInfo::argumentGPR0) = testWord(0);
200             context->gpr(GPRInfo::argumentGPR1) = testWord(1);
201             context->gpr(GPRInfo::argumentGPR2) = testWord(2);
202             context->gpr(GPRInfo::argumentGPR3) = testWord(3);
203             
204             context->fpr(FPRInfo::fpRegT0) = testWord32(0);
205             context->fpr(FPRInfo::fpRegT1) = testWord32(1);
206         });
207
208         // Validate that expected values were written.
209         jit.probe([&] (ProbeContext* context) {
210             success = success && context->gpr(GPRInfo::argumentGPR0) == testWord(0);
211             success = success && context->gpr(GPRInfo::argumentGPR1) == testWord(1);
212             success = success && context->gpr(GPRInfo::argumentGPR2) == testWord(2);
213             success = success && context->gpr(GPRInfo::argumentGPR3) == testWord(3);
214
215             success = success && context->fpr(FPRInfo::fpRegT0) == testWord32(0);
216             success = success && context->fpr(FPRInfo::fpRegT1) == testWord32(1);
217         });
218
219         jit.emitFunctionEpilogue();
220         jit.ret();
221     });
222     CHECK(success);
223 }
224
225 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)
226 {
227     if (j > 0)
228         return testFunctionToTrashGPRs(a + 1, b + a, c + b, d + 5, e - a, f * 1.5, g ^ a, h - b, i, j - 1);
229     return a + 1;
230 }
231 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)
232 {
233     if (j > 0)
234         return testFunctionToTrashFPRs(a + 1, b + a, c + b, d + 5, e - a, f * 1.5, pow(g, a), h - b, i, j - 1);
235     return a + 1;
236 }
237
238 void testProbePreservesGPRS()
239 {
240     // This test relies on testProbeReadsArgumentRegisters() and testProbeWritesArgumentRegisters()
241     // having already validated that we can read and write from registers. We'll use these abilities
242     // to validate that the probe preserves register values.
243     bool success = true;
244     MacroAssembler::CPUState originalState;
245
246     compileAndRun<void>([&] (CCallHelpers& jit) {
247         jit.emitFunctionPrologue();
248
249         // Write expected values into the registers (except for sp, fp, and pc).
250         jit.probe([&] (ProbeContext* context) {
251             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
252                 originalState.gpr(id) = context->gpr(id);
253                 if (isPC(id) || isSP(id) || isFP(id))
254                     continue;
255                 context->gpr(id) = testWord(static_cast<int>(id));
256             }
257             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id)) {
258                 originalState.fpr(id) = context->fpr(id);
259                 context->fpr(id) = testWord(id);
260             }
261         });
262
263         // Invoke the probe to call a lot of functions and trash register values.
264         jit.probe([&] (ProbeContext*) {
265             success = success && (testFunctionToTrashGPRs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) == 10);
266             success = success && (testFunctionToTrashFPRs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) == 10);
267         });
268
269         // Validate that the registers have the expected values.
270         jit.probe([&] (ProbeContext* context) {
271             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
272                 if (isPC(id))
273                     continue;
274                 if (isSP(id) || isFP(id)) {
275                     success = success && context->gpr(id) == originalState.gpr(id);
276                     continue;
277                 }
278                 success = success && context->gpr(id) == testWord(id);
279             }
280             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
281                 success = success && context->fpr(id) == testWord(id);
282         });
283
284         // Restore the original state.
285         jit.probe([&] (ProbeContext* context) {
286             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
287                 if (isPC(id) || isSP(id) || isFP(id))
288                     continue;
289                 context->gpr(id) = originalState.gpr(id);
290             }
291             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
292                 context->fpr(id) = originalState.fpr(id);
293         });
294
295         jit.emitFunctionEpilogue();
296         jit.ret();
297     });
298     CHECK(success);
299 }
300
301 void testProbeModifiesStackPointer()
302 {
303     bool success = true;
304     uint8_t* originalSP;
305
306     compileAndRun<void>([&] (CCallHelpers& jit) {
307         jit.emitFunctionPrologue();
308
309         // Preserve original stack pointer and modify the sp.
310         jit.probe([&] (ProbeContext* context) {
311             originalSP = reinterpret_cast<uint8_t*>(context->sp());
312             context->sp() = originalSP - 1 * KB;
313         });
314
315         // Validate that the stack pointer has the expected value, and restore the original.
316         jit.probe([&] (ProbeContext* context) {
317             success = (reinterpret_cast<uint8_t*>(context->sp()) == (originalSP - 1 * KB));
318             context->sp() = originalSP;
319         });
320
321         // Validate that the original stack pointer was restored.
322         jit.probe([&] (ProbeContext* context) {
323             success = (context->sp() == originalSP);
324         });
325
326         jit.emitFunctionEpilogue();
327         jit.ret();
328     });
329     CHECK(success);
330 }
331
332 void testProbeModifiesProgramCounter()
333 {
334     // This test relies on testProbeReadsArgumentRegisters() and testProbeWritesArgumentRegisters()
335     // having already validated that we can read and write from registers. We'll use these abilities
336     // to validate that the probe preserves register values.
337     bool success = false;
338
339     MacroAssemblerCodeRef continuation = compile([&] (CCallHelpers& jit) {
340         // Validate that we reached the continuation.
341         jit.probe([&] (ProbeContext*) {
342             success = true;
343         });
344
345         jit.emitFunctionEpilogue();
346         jit.ret();
347     });
348
349     compileAndRun<void>([&] (CCallHelpers& jit) {
350         jit.emitFunctionPrologue();
351
352         // Write expected values into the registers.
353         jit.probe([&] (ProbeContext* context) {
354             context->pc() = continuation.code().executableAddress();
355         });
356
357         jit.breakpoint(); // We should never get here.
358     });
359     CHECK(success);
360 }
361 #endif // ENABLE(MASM_PROBE)
362
363 #define RUN(test) do {                          \
364         if (!shouldRun(#test))                  \
365             break;                              \
366         tasks.append(                           \
367             createSharedTask<void()>(           \
368                 [&] () {                        \
369                     dataLog(#test "...\n");     \
370                     test;                       \
371                     dataLog(#test ": OK!\n");   \
372                 }));                            \
373     } while (false);
374
375 void run(const char* filter)
376 {
377     JSC::initializeThreading();
378
379     Deque<RefPtr<SharedTask<void()>>> tasks;
380
381     auto shouldRun = [&] (const char* testName) -> bool {
382         return !filter || !!strcasestr(testName, filter);
383     };
384
385     RUN(testSimple());
386
387 #if ENABLE(MASM_PROBE)
388     RUN(testProbeReadsArgumentRegisters());
389     RUN(testProbeWritesArgumentRegisters());
390     RUN(testProbePreservesGPRS());
391     RUN(testProbeModifiesStackPointer());
392     RUN(testProbeModifiesProgramCounter());
393 #endif
394
395     if (tasks.isEmpty())
396         usage();
397
398     Lock lock;
399
400     Vector<RefPtr<Thread>> threads;
401     for (unsigned i = filter ? 1 : WTF::numberOfProcessorCores(); i--;) {
402         threads.append(
403             Thread::create(
404                 "testmasm thread",
405                 [&] () {
406                     for (;;) {
407                         RefPtr<SharedTask<void()>> task;
408                         {
409                             LockHolder locker(lock);
410                             if (tasks.isEmpty())
411                                 return;
412                             task = tasks.takeFirst();
413                         }
414
415                         task->run();
416                     }
417                 }));
418     }
419
420     for (RefPtr<Thread> thread : threads)
421         thread->waitForCompletion();
422     crashLock.lock();
423 }
424
425 } // anonymous namespace
426
427 #else // not ENABLE(JIT)
428
429 static void run(const char*)
430 {
431     dataLog("JIT is not enabled.\n");
432 }
433
434 #endif // ENABLE(JIT)
435
436 int main(int argc, char** argv)
437 {
438     const char* filter = nullptr;
439     switch (argc) {
440     case 1:
441         break;
442     case 2:
443         filter = argv[1];
444         break;
445     default:
446         usage();
447         break;
448     }
449
450     run(filter);
451     return 0;
452 }