Fix typo in testmasm.cpp: ENABLE(JSVALUE64) should be USE(JSVALUE64).
[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/DataLog.h>
36 #include <wtf/Function.h>
37 #include <wtf/Lock.h>
38 #include <wtf/NumberOfCores.h>
39 #include <wtf/Threading.h>
40
41 // We don't have a NO_RETURN_DUE_TO_EXIT, nor should we. That's ridiculous.
42 static bool hiddenTruthBecauseNoReturnIsStupid() { return true; }
43
44 static void usage()
45 {
46     dataLog("Usage: testmasm [<filter>]\n");
47     if (hiddenTruthBecauseNoReturnIsStupid())
48         exit(1);
49 }
50
51 #if ENABLE(JIT)
52
53 using namespace JSC;
54
55 namespace {
56
57 StaticLock crashLock;
58
59 typedef WTF::Function<void(CCallHelpers&)> Generator;
60
61 template<typename T> T nextID(T id) { return static_cast<T>(id + 1); }
62
63 #define TESTWORD64 0x0c0defefebeef000
64 #define TESTWORD32 0x0beef000
65
66 #define testWord32(x) (TESTWORD32 + static_cast<uint32_t>(x))
67 #define testWord64(x) (TESTWORD64 + static_cast<uint64_t>(x))
68
69 #if USE(JSVALUE64)
70 #define testWord(x) testWord64(x)
71 #else
72 #define testWord(x) testWord32(x)
73 #endif
74 #define testDoubleWord(x) static_cast<double>(testWord(x))
75
76 // Nothing fancy for now; we just use the existing WTF assertion machinery.
77 #define CHECK(x) do {                                                   \
78         if (!!(x))                                                      \
79             break;                                                      \
80         crashLock.lock();                                               \
81         WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #x); \
82         CRASH();                                                        \
83     } while (false)
84
85 #define CHECK_DOUBLE_BITWISE_EQ(a, b) \
86     CHECK(bitwise_cast<uint64_t>(a) == bitwise_cast<uint64_t>(a))
87
88 #if ENABLE(MASM_PROBE)
89 bool isPC(MacroAssembler::RegisterID id)
90 {
91 #if CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
92     return id == ARMRegisters::pc;
93 #else
94     UNUSED_PARAM(id);
95     return false;
96 #endif
97 }
98
99 bool isSP(MacroAssembler::RegisterID id)
100 {
101     return id == MacroAssembler::stackPointerRegister;
102 }
103
104 bool isFP(MacroAssembler::RegisterID id)
105 {
106     return id == MacroAssembler::framePointerRegister;
107 }
108
109 bool isSpecialGPR(MacroAssembler::RegisterID id)
110 {
111     if (isPC(id) || isSP(id) || isFP(id))
112         return true;
113 #if CPU(ARM64)
114     if (id == ARM64Registers::x18)
115         return true;
116 #endif
117     return false;
118 }
119 #endif // ENABLE(MASM_PROBE)
120
121 MacroAssemblerCodeRef compile(Generator&& generate)
122 {
123     CCallHelpers jit;
124     generate(jit);
125     LinkBuffer linkBuffer(jit, nullptr);
126     return FINALIZE_CODE(linkBuffer, ("testmasm compilation"));
127 }
128
129 template<typename T, typename... Arguments>
130 T invoke(MacroAssemblerCodeRef code, Arguments... arguments)
131 {
132     T (*function)(Arguments...) = bitwise_cast<T(*)(Arguments...)>(code.code().executableAddress());
133     return function(arguments...);
134 }
135
136 template<typename T, typename... Arguments>
137 T compileAndRun(Generator&& generator, Arguments... arguments)
138 {
139     return invoke<T>(compile(WTFMove(generator)), arguments...);
140 }
141
142 void testSimple()
143 {
144     CHECK(compileAndRun<int>([] (CCallHelpers& jit) {
145         jit.emitFunctionPrologue();
146         jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR);
147         jit.emitFunctionEpilogue();
148         jit.ret();
149     }) == 42);
150 }
151
152 #if ENABLE(MASM_PROBE)
153 void testProbeReadsArgumentRegisters()
154 {
155     bool probeWasCalled = false;
156     compileAndRun<void>([&] (CCallHelpers& jit) {
157         jit.emitFunctionPrologue();
158
159         jit.move(CCallHelpers::TrustedImm32(testWord32(0)), GPRInfo::argumentGPR0);
160         jit.convertInt32ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT0);
161         jit.move(CCallHelpers::TrustedImm32(testWord32(1)), GPRInfo::argumentGPR0);
162         jit.convertInt32ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT1);
163 #if USE(JSVALUE64)
164         jit.move(CCallHelpers::TrustedImm64(testWord(0)), GPRInfo::argumentGPR0);
165         jit.move(CCallHelpers::TrustedImm64(testWord(1)), GPRInfo::argumentGPR1);
166         jit.move(CCallHelpers::TrustedImm64(testWord(2)), GPRInfo::argumentGPR2);
167         jit.move(CCallHelpers::TrustedImm64(testWord(3)), GPRInfo::argumentGPR3);
168 #else
169         jit.move(CCallHelpers::TrustedImm32(testWord(0)), GPRInfo::argumentGPR0);
170         jit.move(CCallHelpers::TrustedImm32(testWord(1)), GPRInfo::argumentGPR1);
171         jit.move(CCallHelpers::TrustedImm32(testWord(2)), GPRInfo::argumentGPR2);
172         jit.move(CCallHelpers::TrustedImm32(testWord(3)), GPRInfo::argumentGPR3);
173 #endif
174
175         jit.probe([&] (ProbeContext* context) {
176             probeWasCalled = true;
177             CHECK(context->gpr(GPRInfo::argumentGPR0) == testWord(0));
178             CHECK(context->gpr(GPRInfo::argumentGPR1) == testWord(1));
179             CHECK(context->gpr(GPRInfo::argumentGPR2) == testWord(2));
180             CHECK(context->gpr(GPRInfo::argumentGPR3) == testWord(3));
181
182             CHECK_DOUBLE_BITWISE_EQ(context->fpr(FPRInfo::fpRegT0), static_cast<double>(testWord32(0)));
183             CHECK_DOUBLE_BITWISE_EQ(context->fpr(FPRInfo::fpRegT1),  static_cast<double>(testWord32(1)));
184         });
185         jit.emitFunctionEpilogue();
186         jit.ret();
187     });
188     CHECK(probeWasCalled);
189 }
190
191 void testProbeWritesArgumentRegisters()
192 {
193     // This test relies on testProbeReadsArgumentRegisters() having already validated
194     // that we can read from argument registers. We'll use that ability to validate
195     // that our writes did take effect.
196     unsigned probeCallCount = 0;
197     compileAndRun<void>([&] (CCallHelpers& jit) {
198         jit.emitFunctionPrologue();
199
200         // Pre-initialize with non-expected values.
201 #if USE(JSVALUE64)
202         jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::argumentGPR0);
203         jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::argumentGPR1);
204         jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::argumentGPR2);
205         jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::argumentGPR3);
206 #else
207         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::argumentGPR0);
208         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::argumentGPR1);
209         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::argumentGPR2);
210         jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::argumentGPR3);
211 #endif
212         jit.convertInt32ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT0);
213         jit.convertInt32ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT1);
214
215         // Write expected values.
216         jit.probe([&] (ProbeContext* context) {
217             probeCallCount++;
218             context->gpr(GPRInfo::argumentGPR0) = testWord(0);
219             context->gpr(GPRInfo::argumentGPR1) = testWord(1);
220             context->gpr(GPRInfo::argumentGPR2) = testWord(2);
221             context->gpr(GPRInfo::argumentGPR3) = testWord(3);
222             
223             context->fpr(FPRInfo::fpRegT0) = testWord32(0);
224             context->fpr(FPRInfo::fpRegT1) = testWord32(1);
225         });
226
227         // Validate that expected values were written.
228         jit.probe([&] (ProbeContext* context) {
229             probeCallCount++;
230             CHECK(context->gpr(GPRInfo::argumentGPR0) == testWord(0));
231             CHECK(context->gpr(GPRInfo::argumentGPR1) == testWord(1));
232             CHECK(context->gpr(GPRInfo::argumentGPR2) == testWord(2));
233             CHECK(context->gpr(GPRInfo::argumentGPR3) == testWord(3));
234
235             CHECK_DOUBLE_BITWISE_EQ(context->fpr(FPRInfo::fpRegT0), static_cast<double>(testWord32(0)));
236             CHECK_DOUBLE_BITWISE_EQ(context->fpr(FPRInfo::fpRegT1), static_cast<double>(testWord32(1)));
237         });
238
239         jit.emitFunctionEpilogue();
240         jit.ret();
241     });
242     CHECK(probeCallCount == 2);
243 }
244
245 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)
246 {
247     if (j > 0)
248         return testFunctionToTrashGPRs(a + 1, b + a, c + b, d + 5, e - a, f * 1.5, g ^ a, h - b, i, j - 1);
249     return a + 1;
250 }
251 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)
252 {
253     if (j > 0)
254         return testFunctionToTrashFPRs(a + 1, b + a, c + b, d + 5, e - a, f * 1.5, pow(g, a), h - b, i, j - 1);
255     return a + 1;
256 }
257
258 void testProbePreservesGPRS()
259 {
260     // This test relies on testProbeReadsArgumentRegisters() and testProbeWritesArgumentRegisters()
261     // having already validated that we can read and write from registers. We'll use these abilities
262     // to validate that the probe preserves register values.
263     unsigned probeCallCount = 0;
264     MacroAssembler::CPUState originalState;
265
266     compileAndRun<void>([&] (CCallHelpers& jit) {
267         jit.emitFunctionPrologue();
268
269         // Write expected values into the registers (except for sp, fp, and pc).
270         jit.probe([&] (ProbeContext* context) {
271             probeCallCount++;
272             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
273                 originalState.gpr(id) = context->gpr(id);
274                 if (isSpecialGPR(id))
275                     continue;
276                 context->gpr(id) = testWord(static_cast<int>(id));
277             }
278             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id)) {
279                 originalState.fpr(id) = context->fpr(id);
280                 context->fpr(id) = testDoubleWord(id);
281             }
282         });
283
284         // Invoke the probe to call a lot of functions and trash register values.
285         jit.probe([&] (ProbeContext*) {
286             probeCallCount++;
287             CHECK(testFunctionToTrashGPRs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) == 10);
288             CHECK(testFunctionToTrashFPRs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) == 10);
289         });
290
291         // Validate that the registers have the expected values.
292         jit.probe([&] (ProbeContext* context) {
293             probeCallCount++;
294             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
295                 if (isSP(id) || isFP(id)) {
296                     CHECK(context->gpr(id) == originalState.gpr(id));
297                     continue;
298                 }
299                 if (isSpecialGPR(id))
300                     continue;
301                 CHECK(context->gpr(id) == testWord(id));
302             }
303             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
304                 CHECK_DOUBLE_BITWISE_EQ(context->fpr(id), testDoubleWord(id));
305         });
306
307         // Restore the original state.
308         jit.probe([&] (ProbeContext* context) {
309             probeCallCount++;
310             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
311                 if (isSpecialGPR(id))
312                     continue;
313                 context->gpr(id) = originalState.gpr(id);
314             }
315             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
316                 context->fpr(id) = originalState.fpr(id);
317         });
318
319         // Validate that the original state was restored.
320         jit.probe([&] (ProbeContext* context) {
321             probeCallCount++;
322             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
323                 if (isSpecialGPR(id))
324                     continue;
325                 CHECK(context->gpr(id) == originalState.gpr(id));
326             }
327             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
328                 CHECK_DOUBLE_BITWISE_EQ(context->fpr(id), originalState.fpr(id));
329         });
330
331         jit.emitFunctionEpilogue();
332         jit.ret();
333     });
334     CHECK(probeCallCount == 5);
335 }
336
337 void testProbeModifiesStackPointer(WTF::Function<void*(ProbeContext*)> computeModifiedStack)
338 {
339     unsigned probeCallCount = 0;
340     MacroAssembler::CPUState originalState;
341     uint8_t* originalSP { nullptr };
342     void* modifiedSP { nullptr };
343     uintptr_t modifiedFlags { 0 };
344     
345 #if CPU(X86) || CPU(X86_64)
346     auto flagsSPR = X86Registers::eflags;
347     uintptr_t flagsMask = 0xc5;
348 #elif CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
349     auto flagsSPR = ARMRegisters::apsr;
350     uintptr_t flagsMask = 0xf0000000;
351 #elif CPU(ARM64)
352     auto flagsSPR = ARM64Registers::nzcv;
353     uintptr_t flagsMask = 0xf0000000;
354 #endif
355
356     compileAndRun<void>([&] (CCallHelpers& jit) {
357         jit.emitFunctionPrologue();
358
359         // Preserve original stack pointer and modify the sp, and
360         // write expected values into other registers (except for fp, and pc).
361         jit.probe([&] (ProbeContext* context) {
362             probeCallCount++;
363             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
364                 originalState.gpr(id) = context->gpr(id);
365                 if (isSpecialGPR(id))
366                     continue;
367                 context->gpr(id) = testWord(static_cast<int>(id));
368             }
369             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id)) {
370                 originalState.fpr(id) = context->fpr(id);
371                 context->fpr(id) = testWord(id);
372             }
373
374             originalState.spr(flagsSPR) = context->spr(flagsSPR);
375             modifiedFlags = originalState.spr(flagsSPR) ^ flagsMask;
376             context->spr(flagsSPR) = modifiedFlags;
377
378             originalSP = reinterpret_cast<uint8_t*>(context->sp());
379             modifiedSP = computeModifiedStack(context);
380             context->sp() = modifiedSP;
381         });
382
383         // Validate that the registers have the expected values.
384         jit.probe([&] (ProbeContext* context) {
385             probeCallCount++;
386             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
387                 if (isFP(id)) {
388                     CHECK(context->gpr(id) == originalState.gpr(id));
389                     continue;
390                 }
391                 if (isSpecialGPR(id))
392                     continue;
393                 CHECK(context->gpr(id) == testWord(id));
394             }
395             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
396                 CHECK_DOUBLE_BITWISE_EQ(context->fpr(id), testDoubleWord(id));
397             CHECK(context->spr(flagsSPR) == modifiedFlags);
398             CHECK(context->sp() == modifiedSP);
399         });
400
401         // Restore the original state.
402         jit.probe([&] (ProbeContext* context) {
403             probeCallCount++;
404             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
405                 if (isSpecialGPR(id))
406                     continue;
407                 context->gpr(id) = originalState.gpr(id);
408             }
409             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
410                 context->fpr(id) = originalState.fpr(id);
411             context->spr(flagsSPR) = originalState.spr(flagsSPR);
412             context->sp() = originalSP;
413         });
414
415         // Validate that the original state was restored.
416         jit.probe([&] (ProbeContext* context) {
417             probeCallCount++;
418             for (auto id = CCallHelpers::firstRegister(); id <= CCallHelpers::lastRegister(); id = nextID(id)) {
419                 if (isSpecialGPR(id))
420                     continue;
421                 CHECK(context->gpr(id) == originalState.gpr(id));
422             }
423             for (auto id = CCallHelpers::firstFPRegister(); id <= CCallHelpers::lastFPRegister(); id = nextID(id))
424                 CHECK_DOUBLE_BITWISE_EQ(context->fpr(id),  originalState.fpr(id));
425             CHECK(context->spr(flagsSPR) == originalState.spr(flagsSPR));
426             CHECK(context->sp() == originalSP);
427         });
428
429         jit.emitFunctionEpilogue();
430         jit.ret();
431     });
432     CHECK(probeCallCount == 4);
433 }
434
435 void testProbeModifiesStackPointerToInsideProbeContextOnStack()
436 {
437     size_t increment = sizeof(uintptr_t);
438 #if CPU(ARM64)
439     // The ARM64 probe uses ldp and stp which require 16 byte alignment.
440     increment = 2 * sizeof(uintptr_t);
441 #endif
442     for (size_t offset = 0; offset < sizeof(ProbeContext); offset += increment) {
443         testProbeModifiesStackPointer([=] (ProbeContext* context) -> void* {
444             return reinterpret_cast<uint8_t*>(context) + offset;
445         });
446     }
447 }
448
449 void testProbeModifiesStackPointerToNBytesBelowSP()
450 {
451     size_t increment = sizeof(uintptr_t);
452 #if CPU(ARM64)
453     // The ARM64 probe uses ldp and stp which require 16 byte alignment.
454     increment = 2 * sizeof(uintptr_t);
455 #endif
456     for (size_t offset = 0; offset < 1 * KB; offset += increment) {
457         testProbeModifiesStackPointer([=] (ProbeContext* context) -> void* {
458             return reinterpret_cast<uint8_t*>(context->cpu.sp()) - offset;
459         });
460     }
461 }
462
463 void testProbeModifiesProgramCounter()
464 {
465     // This test relies on testProbeReadsArgumentRegisters() and testProbeWritesArgumentRegisters()
466     // having already validated that we can read and write from registers. We'll use these abilities
467     // to validate that the probe preserves register values.
468     unsigned probeCallCount = 0;
469     bool continuationWasReached = false;
470
471     MacroAssemblerCodeRef continuation = compile([&] (CCallHelpers& jit) {
472         // Validate that we reached the continuation.
473         jit.probe([&] (ProbeContext*) {
474             probeCallCount++;
475             continuationWasReached = true;
476         });
477
478         jit.emitFunctionEpilogue();
479         jit.ret();
480     });
481
482     compileAndRun<void>([&] (CCallHelpers& jit) {
483         jit.emitFunctionPrologue();
484
485         // Write expected values into the registers.
486         jit.probe([&] (ProbeContext* context) {
487             probeCallCount++;
488             context->pc() = continuation.code().executableAddress();
489         });
490
491         jit.breakpoint(); // We should never get here.
492     });
493     CHECK(probeCallCount == 2);
494     CHECK(continuationWasReached);
495 }
496 #endif // ENABLE(MASM_PROBE)
497
498 #define RUN(test) do {                          \
499         if (!shouldRun(#test))                  \
500             break;                              \
501         tasks.append(                           \
502             createSharedTask<void()>(           \
503                 [&] () {                        \
504                     dataLog(#test "...\n");     \
505                     test;                       \
506                     dataLog(#test ": OK!\n");   \
507                 }));                            \
508     } while (false);
509
510 void run(const char* filter)
511 {
512     JSC::initializeThreading();
513
514     Deque<RefPtr<SharedTask<void()>>> tasks;
515
516     auto shouldRun = [&] (const char* testName) -> bool {
517         return !filter || !!strcasestr(testName, filter);
518     };
519
520     RUN(testSimple());
521
522 #if ENABLE(MASM_PROBE)
523     RUN(testProbeReadsArgumentRegisters());
524     RUN(testProbeWritesArgumentRegisters());
525     RUN(testProbePreservesGPRS());
526     RUN(testProbeModifiesStackPointerToInsideProbeContextOnStack());
527     RUN(testProbeModifiesStackPointerToNBytesBelowSP());
528     RUN(testProbeModifiesProgramCounter());
529 #endif
530
531     if (tasks.isEmpty())
532         usage();
533
534     Lock lock;
535
536     Vector<RefPtr<Thread>> threads;
537     for (unsigned i = filter ? 1 : WTF::numberOfProcessorCores(); i--;) {
538         threads.append(
539             Thread::create(
540                 "testmasm thread",
541                 [&] () {
542                     for (;;) {
543                         RefPtr<SharedTask<void()>> task;
544                         {
545                             LockHolder locker(lock);
546                             if (tasks.isEmpty())
547                                 return;
548                             task = tasks.takeFirst();
549                         }
550
551                         task->run();
552                     }
553                 }));
554     }
555
556     for (RefPtr<Thread> thread : threads)
557         thread->waitForCompletion();
558     crashLock.lock();
559 }
560
561 } // anonymous namespace
562
563 #else // not ENABLE(JIT)
564
565 static void run(const char*)
566 {
567     dataLog("JIT is not enabled.\n");
568 }
569
570 #endif // ENABLE(JIT)
571
572 int main(int argc, char** argv)
573 {
574     const char* filter = nullptr;
575     switch (argc) {
576     case 1:
577         break;
578     case 2:
579         filter = argv[1];
580         break;
581     default:
582         usage();
583         break;
584     }
585
586     run(filter);
587     return 0;
588 }