Introduce makeBlockPtr for lambdas
[WebKit-https.git] / Tools / DumpRenderTree / JavaScriptThreading.cpp
1 /*
2  * Copyright (C) 2005-2017 Apple Inc. All rights reserved.
3  *           (C) 2007 Graham Dennis (graham.dennis@gmail.com)
4  *           (C) 2007 Eric Seidel <eric@webkit.org>
5  *           (C) 2012 Patrick Ganstere <paroga@paroga.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1.  Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer. 
13  * 2.  Redistributions in binary form must reproduce the above copyright
14  *     notice, this list of conditions and the following disclaimer in the
15  *     documentation and/or other materials provided with the distribution. 
16  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
17  *     its contributors may be used to endorse or promote products derived
18  *     from this software without specific prior written permission. 
19  *
20  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
21  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31  
32 #include "config.h"
33 #include "JavaScriptThreading.h"
34
35 #include <JavaScriptCore/JavaScriptCore.h>
36 #include <stdlib.h>
37 #include <wtf/Assertions.h>
38 #include <wtf/HashSet.h>
39 #include <wtf/Lock.h>
40 #include <wtf/NeverDestroyed.h>
41 #include <wtf/Threading.h>
42 #include <wtf/ThreadingPrimitives.h>
43 #include <wtf/Vector.h>
44
45 static const size_t javaScriptThreadsCount = 4;
46 static bool javaScriptThreadsShouldTerminate;
47 static JSContextGroupRef javaScriptThreadsGroup;
48 static Lock javaScriptThreadsLock;
49
50 typedef HashSet<RefPtr<Thread>> ThreadSet;
51 static ThreadSet& javaScriptThreads()
52 {
53     static NeverDestroyed<ThreadSet> staticJavaScriptThreads;
54     ASSERT(!javaScriptThreadsLock.tryLock());
55     return staticJavaScriptThreads;
56 }
57
58 // This function exercises JSC in a loop until javaScriptThreadsShouldTerminate
59 // becomes true or it probabilistically decides to spawn a replacement thread and exit.
60 void runJavaScriptThread()
61 {
62     static const char* const script =
63         "var array = [];"
64         "for (var i = 0; i < 1024; i++) {"
65         "    array.push(String(i));"
66         "}";
67
68     JSGlobalContextRef ctx;
69     {
70         auto locker = holdLock(javaScriptThreadsLock);
71         ctx = JSGlobalContextCreateInGroup(javaScriptThreadsGroup, 0);
72     }
73
74     JSStringRef scriptRef;
75     {
76         auto locker = holdLock(javaScriptThreadsLock);
77         scriptRef = JSStringCreateWithUTF8CString(script);
78     }
79
80     while (true) {
81         {
82             auto locker = holdLock(javaScriptThreadsLock);
83             JSValueRef exception = 0;
84             JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception);
85             ASSERT(!exception);
86         }
87
88         {
89             auto locker = holdLock(javaScriptThreadsLock);
90             const size_t valuesCount = 1024;
91             JSValueRef values[valuesCount];
92             for (size_t i = 0; i < valuesCount; ++i)
93                 values[i] = JSObjectMake(ctx, 0, 0);
94         }
95
96         {
97             auto locker = holdLock(javaScriptThreadsLock);
98             if (javaScriptThreadsShouldTerminate)
99                 break;
100         }
101
102         // Respawn probabilistically.
103         if (rand() % 5)
104             continue;
105
106         auto locker = holdLock(javaScriptThreadsLock);
107         Thread& thread = Thread::current();
108         thread.detach();
109         javaScriptThreads().remove(&thread);
110         javaScriptThreads().add(Thread::create("JavaScript Thread", &runJavaScriptThread));
111         break;
112     }
113
114     auto locker = holdLock(javaScriptThreadsLock);
115     JSStringRelease(scriptRef);
116     JSGarbageCollect(ctx);
117     JSGlobalContextRelease(ctx);
118 }
119
120 void startJavaScriptThreads()
121 {
122     javaScriptThreadsGroup = JSContextGroupCreate();
123
124     auto locker = holdLock(javaScriptThreadsLock);
125
126     for (size_t i = 0; i < javaScriptThreadsCount; ++i)
127         javaScriptThreads().add(Thread::create("JavaScript Thread", &runJavaScriptThread));
128 }
129
130 void stopJavaScriptThreads()
131 {
132     {
133         auto locker = holdLock(javaScriptThreadsLock);
134         javaScriptThreadsShouldTerminate = true;
135     }
136
137     Vector<RefPtr<Thread>, javaScriptThreadsCount> threads;
138     {
139         auto locker = holdLock(javaScriptThreadsLock);
140         threads = copyToVector(javaScriptThreads());
141         ASSERT(threads.size() == javaScriptThreadsCount);
142     }
143
144     for (size_t i = 0; i < javaScriptThreadsCount; ++i)
145         threads[i]->waitForCompletion();
146
147     {
148         auto locker = holdLock(javaScriptThreadsLock);
149         javaScriptThreads().clear();
150     }
151
152     JSContextGroupRelease(javaScriptThreadsGroup);
153 }