Unreviewed, roll out http://trac.webkit.org/changeset/187972.
[WebKit-https.git] / Tools / DumpRenderTree / JavaScriptThreading.cpp
1 /*
2  * Copyright (C) 2005, 2006, 2007 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/Threading.h>
40 #include <wtf/ThreadingPrimitives.h>
41 #include <wtf/Vector.h>
42
43 static const size_t javaScriptThreadsCount = 4;
44 static bool javaScriptThreadsShouldTerminate;
45 static JSContextGroupRef javaScriptThreadsGroup;
46
47 static Mutex& javaScriptThreadsMutex()
48 {
49     DEPRECATED_DEFINE_STATIC_LOCAL(Mutex, staticMutex, ());
50     return staticMutex;
51 }
52
53 typedef HashSet<ThreadIdentifier> ThreadSet;
54 static ThreadSet& javaScriptThreads()
55 {
56     DEPRECATED_DEFINE_STATIC_LOCAL(ThreadSet, staticJavaScriptThreads, ());
57     ASSERT(!javaScriptThreadsMutex().tryLock());
58     return staticJavaScriptThreads;
59 }
60
61 // This function exercises JSC in a loop until javaScriptThreadsShouldTerminate
62 // becomes true or it probabilistically decides to spawn a replacement thread and exit.
63 void runJavaScriptThread(void*)
64 {
65     static const char* const script =
66         "var array = [];"
67         "for (var i = 0; i < 1024; i++) {"
68         "    array.push(String(i));"
69         "}";
70
71     JSGlobalContextRef ctx;
72     {
73         MutexLocker locker(javaScriptThreadsMutex());
74         ctx = JSGlobalContextCreateInGroup(javaScriptThreadsGroup, 0);
75     }
76
77     JSStringRef scriptRef;
78     {
79         MutexLocker locker(javaScriptThreadsMutex());
80         scriptRef = JSStringCreateWithUTF8CString(script);
81     }
82
83     while (true) {
84         {
85             MutexLocker locker(javaScriptThreadsMutex());
86             JSValueRef exception = 0;
87             JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception);
88             ASSERT(!exception);
89         }
90
91         {
92             MutexLocker locker(javaScriptThreadsMutex());
93             const size_t valuesCount = 1024;
94             JSValueRef values[valuesCount];
95             for (size_t i = 0; i < valuesCount; ++i)
96                 values[i] = JSObjectMake(ctx, 0, 0);
97         }
98
99         {
100             MutexLocker locker(javaScriptThreadsMutex());
101             if (javaScriptThreadsShouldTerminate)
102                 break;
103         }
104
105         // Respawn probabilistically.
106         if (rand() % 5)
107             continue;
108
109         MutexLocker locker(javaScriptThreadsMutex());
110         ThreadIdentifier thread = currentThread();
111         detachThread(thread);
112         javaScriptThreads().remove(thread);
113         javaScriptThreads().add(createThread(&runJavaScriptThread, 0, 0));
114         break;
115     }
116
117     MutexLocker locker(javaScriptThreadsMutex());
118     JSStringRelease(scriptRef);
119     JSGarbageCollect(ctx);
120     JSGlobalContextRelease(ctx);
121 }
122
123 void startJavaScriptThreads()
124 {
125     javaScriptThreadsGroup = JSContextGroupCreate();
126
127     MutexLocker locker(javaScriptThreadsMutex());
128
129     for (size_t i = 0; i < javaScriptThreadsCount; ++i)
130         javaScriptThreads().add(createThread(&runJavaScriptThread, 0, 0));
131 }
132
133 void stopJavaScriptThreads()
134 {
135     {
136         MutexLocker locker(javaScriptThreadsMutex());
137         javaScriptThreadsShouldTerminate = true;
138     }
139
140     Vector<ThreadIdentifier, javaScriptThreadsCount> threads;
141     {
142         MutexLocker locker(javaScriptThreadsMutex());
143         copyToVector(javaScriptThreads(), threads);
144         ASSERT(threads.size() == javaScriptThreadsCount);
145     }
146
147     for (size_t i = 0; i < javaScriptThreadsCount; ++i)
148         waitForThreadCompletion(threads[i]);
149
150     {
151         MutexLocker locker(javaScriptThreadsMutex());
152         javaScriptThreads().clear();
153     }
154
155     JSContextGroupRelease(javaScriptThreadsGroup);
156 }