]> git.saurik.com Git - apple/javascriptcore.git/blame - API/tests/ExecutionTimeLimitTest.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / API / tests / ExecutionTimeLimitTest.cpp
CommitLineData
ed1e77d3
A
1/*
2 * Copyright (C) 2015 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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "ExecutionTimeLimitTest.h"
28
29#if OS(DARWIN)
30
31#include "JSContextRefPrivate.h"
32#include "JavaScriptCore.h"
33
34#include <mach/mach.h>
35#include <mach/mach_time.h>
36#include <stdio.h>
37#include <sys/time.h>
38
39static JSGlobalContextRef context = nullptr;
40
41static double currentCPUTime()
42{
43 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
44 thread_basic_info_data_t info;
45
46 /* Get thread information */
47 mach_port_t threadPort = mach_thread_self();
48 thread_info(threadPort, THREAD_BASIC_INFO, (thread_info_t)(&info), &infoCount);
49 mach_port_deallocate(mach_task_self(), threadPort);
50
51 double time = info.user_time.seconds + info.user_time.microseconds / 1000000.;
52 time += info.system_time.seconds + info.system_time.microseconds / 1000000.;
53
54 return time;
55}
56
57static JSValueRef currentCPUTimeAsJSFunctionCallback(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
58{
59 UNUSED_PARAM(functionObject);
60 UNUSED_PARAM(thisObject);
61 UNUSED_PARAM(argumentCount);
62 UNUSED_PARAM(arguments);
63 UNUSED_PARAM(exception);
64
65 ASSERT(JSContextGetGlobalContext(ctx) == context);
66 return JSValueMakeNumber(ctx, currentCPUTime());
67}
68
69bool shouldTerminateCallbackWasCalled = false;
70static bool shouldTerminateCallback(JSContextRef ctx, void* context)
71{
72 UNUSED_PARAM(ctx);
73 UNUSED_PARAM(context);
74 shouldTerminateCallbackWasCalled = true;
75 return true;
76}
77
78bool cancelTerminateCallbackWasCalled = false;
79static bool cancelTerminateCallback(JSContextRef ctx, void* context)
80{
81 UNUSED_PARAM(ctx);
82 UNUSED_PARAM(context);
83 cancelTerminateCallbackWasCalled = true;
84 return false;
85}
86
87int extendTerminateCallbackCalled = 0;
88static bool extendTerminateCallback(JSContextRef ctx, void* context)
89{
90 UNUSED_PARAM(context);
91 extendTerminateCallbackCalled++;
92 if (extendTerminateCallbackCalled == 1) {
93 JSContextGroupRef contextGroup = JSContextGetGroup(ctx);
94 JSContextGroupSetExecutionTimeLimit(contextGroup, .200f, extendTerminateCallback, 0);
95 return false;
96 }
97 return true;
98}
99
100
101int testExecutionTimeLimit()
102{
103 context = JSGlobalContextCreateInGroup(nullptr, nullptr);
104
105 JSContextGroupRef contextGroup = JSContextGetGroup(context);
106 JSObjectRef globalObject = JSContextGetGlobalObject(context);
107 ASSERT(JSValueIsObject(context, globalObject));
108
109 JSValueRef v = nullptr;
110 JSValueRef exception = nullptr;
111 bool failed = false;
112
113 JSStringRef currentCPUTimeStr = JSStringCreateWithUTF8CString("currentCPUTime");
114 JSObjectRef currentCPUTimeFunction = JSObjectMakeFunctionWithCallback(context, currentCPUTimeStr, currentCPUTimeAsJSFunctionCallback);
115 JSObjectSetProperty(context, globalObject, currentCPUTimeStr, currentCPUTimeFunction, kJSPropertyAttributeNone, nullptr);
116 JSStringRelease(currentCPUTimeStr);
117
118 /* Test script timeout: */
119 JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, shouldTerminateCallback, 0);
120 {
121 const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } ";
122 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
123 double startTime;
124 double endTime;
125 exception = nullptr;
126 shouldTerminateCallbackWasCalled = false;
127 startTime = currentCPUTime();
128 v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
129 endTime = currentCPUTime();
130
131 if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled)
132 printf("PASS: script timed out as expected.\n");
133 else {
134 if (!((endTime - startTime) < .150f))
135 printf("FAIL: script did not time out as expected.\n");
136 if (!shouldTerminateCallbackWasCalled)
137 printf("FAIL: script timeout callback was not called.\n");
138 failed = true;
139 }
140
141 if (!exception) {
142 printf("FAIL: TerminatedExecutionException was not thrown.\n");
143 failed = true;
144 }
145 }
146
147 /* Test the script timeout's TerminatedExecutionException should NOT be catchable: */
148 JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, shouldTerminateCallback, 0);
149 {
150 const char* loopForeverScript = "var startTime = currentCPUTime(); try { while (true) { if (currentCPUTime() - startTime > .150) break; } } catch(e) { }";
151 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
152 double startTime;
153 double endTime;
154 exception = nullptr;
155 shouldTerminateCallbackWasCalled = false;
156 startTime = currentCPUTime();
157 v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
158 endTime = currentCPUTime();
159
160 if (((endTime - startTime) >= .150f) || !shouldTerminateCallbackWasCalled) {
161 if (!((endTime - startTime) < .150f))
162 printf("FAIL: script did not time out as expected.\n");
163 if (!shouldTerminateCallbackWasCalled)
164 printf("FAIL: script timeout callback was not called.\n");
165 failed = true;
166 }
167
168 if (exception)
169 printf("PASS: TerminatedExecutionException was not catchable as expected.\n");
170 else {
171 printf("FAIL: TerminatedExecutionException was caught.\n");
172 failed = true;
173 }
174 }
175
176 /* Test script timeout with no callback: */
177 JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, 0, 0);
178 {
179 const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } ";
180 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
181 double startTime;
182 double endTime;
183 exception = nullptr;
184 startTime = currentCPUTime();
185 v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
186 endTime = currentCPUTime();
187
188 if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled)
189 printf("PASS: script timed out as expected when no callback is specified.\n");
190 else {
191 if (!((endTime - startTime) < .150f))
192 printf("FAIL: script did not time out as expected when no callback is specified.\n");
193 failed = true;
194 }
195
196 if (!exception) {
197 printf("FAIL: TerminatedExecutionException was not thrown.\n");
198 failed = true;
199 }
200 }
201
202 /* Test script timeout cancellation: */
203 JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, cancelTerminateCallback, 0);
204 {
205 const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } ";
206 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
207 double startTime;
208 double endTime;
209 exception = nullptr;
210 startTime = currentCPUTime();
211 v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
212 endTime = currentCPUTime();
213
214 if (((endTime - startTime) >= .150f) && cancelTerminateCallbackWasCalled && !exception)
215 printf("PASS: script timeout was cancelled as expected.\n");
216 else {
217 if (((endTime - startTime) < .150) || exception)
218 printf("FAIL: script timeout was not cancelled.\n");
219 if (!cancelTerminateCallbackWasCalled)
220 printf("FAIL: script timeout callback was not called.\n");
221 failed = true;
222 }
223
224 if (exception) {
225 printf("FAIL: Unexpected TerminatedExecutionException thrown.\n");
226 failed = true;
227 }
228 }
229
230 /* Test script timeout extension: */
231 JSContextGroupSetExecutionTimeLimit(contextGroup, 0.100f, extendTerminateCallback, 0);
232 {
233 const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .500) break; } ";
234 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
235 double startTime;
236 double endTime;
237 double deltaTime;
238 exception = nullptr;
239 startTime = currentCPUTime();
240 v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
241 endTime = currentCPUTime();
242 deltaTime = endTime - startTime;
243
244 if ((deltaTime >= .300f) && (deltaTime < .500f) && (extendTerminateCallbackCalled == 2) && exception)
245 printf("PASS: script timeout was extended as expected.\n");
246 else {
247 if (deltaTime < .200f)
248 printf("FAIL: script timeout was not extended as expected.\n");
249 else if (deltaTime >= .500f)
250 printf("FAIL: script did not timeout.\n");
251
252 if (extendTerminateCallbackCalled < 1)
253 printf("FAIL: script timeout callback was not called.\n");
254 if (extendTerminateCallbackCalled < 2)
255 printf("FAIL: script timeout callback was not called after timeout extension.\n");
256
257 if (!exception)
258 printf("FAIL: TerminatedExecutionException was not thrown during timeout extension test.\n");
259
260 failed = true;
261 }
262 }
263
264 JSGlobalContextRelease(context);
265 return failed;
266}
267
268#endif // OS(DARWIN)