1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/RefPtr.h" // RefPtr
8 #include "mozilla/Utf8.h" // mozilla::Utf8Unit
10 #include <string.h> // strcmp
12 #include "frontend/FrontendContext.h" // js::FrontendContext
13 #include "js/AllocPolicy.h" // js::ReportOutOfMemory
14 #include "js/CompileOptions.h" // JS::PrefableCompileOptions, JS::CompileOptions
15 #include "js/Exception.h" // JS_IsExceptionPending, JS_IsThrowingOutOfMemory, JS_GetPendingException, JS_ClearPendingException, JS_ErrorFromException
16 #include "js/experimental/CompileScript.h" // JS::NewFrontendContext, JS::DestroyFrontendContext, JS::SetNativeStackQuota, JS::CompileGlobalScriptToStencil, JS::ConvertFrontendErrorsToRuntimeErrors, JS::HadFrontendErrors, JS::HadFrontendOverRecursed, JS::HadFrontendOutOfMemory, JS::HadFrontendAllocationOverflow, JS::GetFrontendWarningCount, JS::GetFrontendWarningAt
17 #include "js/friend/ErrorMessages.h" // JSMSG_*
18 #include "js/friend/StackLimits.h" // js::ReportOverRecursed
19 #include "js/RootingAPI.h" // JS::Rooted
20 #include "js/SourceText.h" // JS::SourceText
21 #include "js/Stack.h" // JS::NativeStackSize
22 #include "js/Warnings.h" // JS::SetWarningReporter
23 #include "jsapi-tests/tests.h"
24 #include "util/NativeStack.h" // js::GetNativeStackBase
25 #include "vm/ErrorObject.h" // js::ErrorObject
26 #include "vm/JSContext.h" // JSContext
27 #include "vm/JSObject.h" // JSObject
28 #include "vm/NativeObject.h" // js::NativeObject
29 #include "vm/Runtime.h" // js::ReportAllocationOverflow
33 BEGIN_TEST(testFrontendErrors_error
) {
34 JS::FrontendContext
* fc
= JS::NewFrontendContext();
37 static constexpr JS::NativeStackSize stackSize
= 128 * sizeof(size_t) * 1024;
39 JS::SetNativeStackQuota(fc
, stackSize
);
41 JS::PrefableCompileOptions prefableOptions
;
42 JS::CompileOptions
options(prefableOptions
);
43 const char* filename
= "testFrontendErrors_error.js";
44 options
.setFile(filename
);
46 CHECK(!JS::HadFrontendErrors(fc
));
49 const char source
[] = "syntax error";
51 JS::SourceText
<mozilla::Utf8Unit
> srcBuf
;
53 srcBuf
.init(fc
, source
, strlen(source
), JS::SourceOwnership::Borrowed
));
54 JS::CompilationStorage compileStorage
;
55 RefPtr
<JS::Stencil
> stencil
=
56 JS::CompileGlobalScriptToStencil(fc
, options
, srcBuf
, compileStorage
);
60 CHECK(JS::HadFrontendErrors(fc
));
61 CHECK(!JS::HadFrontendOverRecursed(fc
));
62 CHECK(!JS::HadFrontendOutOfMemory(fc
));
63 CHECK(!JS::HadFrontendAllocationOverflow(fc
));
64 CHECK(JS::GetFrontendWarningCount(fc
) == 0);
67 const JSErrorReport
* report
= JS::GetFrontendErrorReport(fc
, options
);
70 CHECK(report
->errorNumber
== JSMSG_UNEXPECTED_TOKEN_NO_EXPECT
);
71 // FrontendContext's error report borrows the filename.
72 CHECK(report
->filename
.c_str() == filename
);
75 CHECK(!JS_IsExceptionPending(cx
));
77 JS::SetWarningReporter(cx
, warningReporter
);
79 bool result
= JS::ConvertFrontendErrorsToRuntimeErrors(cx
, fc
, options
);
82 CHECK(JS_IsExceptionPending(cx
));
83 CHECK(!warningReporterCalled
);
84 CHECK(!JS_IsThrowingOutOfMemory(cx
));
87 JS::Rooted
<JS::Value
> exception(cx
);
88 CHECK(JS_GetPendingException(cx
, &exception
));
90 CHECK(exception
.isObject());
91 JS::Rooted
<JSObject
*> exceptionObj(cx
, &exception
.toObject());
93 const JSErrorReport
* report
= JS_ErrorFromException(cx
, exceptionObj
);
96 CHECK(report
->errorNumber
== JSMSG_UNEXPECTED_TOKEN_NO_EXPECT
);
97 // Runtime's error report doesn't borrow the filename.
98 CHECK(report
->filename
.c_str() != filename
);
99 CHECK(strcmp(report
->filename
.c_str(), filename
) == 0);
102 JS_ClearPendingException(cx
);
104 JS::DestroyFrontendContext(fc
);
109 static bool warningReporterCalled
;
111 static void warningReporter(JSContext
* cx
, JSErrorReport
* report
) {
112 warningReporterCalled
= true;
114 END_TEST(testFrontendErrors_error
)
116 /* static */ bool cls_testFrontendErrors_error::warningReporterCalled
= false;
118 BEGIN_TEST(testFrontendErrors_warning
) {
119 JS::FrontendContext
* fc
= JS::NewFrontendContext();
122 static constexpr JS::NativeStackSize stackSize
= 128 * sizeof(size_t) * 1024;
124 JS::SetNativeStackQuota(fc
, stackSize
);
126 JS::PrefableCompileOptions prefableOptions
;
127 JS::CompileOptions
options(prefableOptions
);
128 options
.setFile(filename
);
131 const char source
[] = "function f() { return; f(); }";
133 JS::SourceText
<mozilla::Utf8Unit
> srcBuf
;
135 srcBuf
.init(fc
, source
, strlen(source
), JS::SourceOwnership::Borrowed
));
136 JS::CompilationStorage compileStorage
;
137 RefPtr
<JS::Stencil
> stencil
=
138 JS::CompileGlobalScriptToStencil(fc
, options
, srcBuf
, compileStorage
);
142 CHECK(!JS::HadFrontendErrors(fc
));
143 CHECK(!JS::HadFrontendOverRecursed(fc
));
144 CHECK(!JS::HadFrontendOutOfMemory(fc
));
145 CHECK(!JS::HadFrontendAllocationOverflow(fc
));
146 CHECK(JS::GetFrontendWarningCount(fc
) == 1);
149 const JSErrorReport
* report
= JS::GetFrontendWarningAt(fc
, 0, options
);
152 CHECK(report
->errorNumber
== JSMSG_STMT_AFTER_RETURN
);
153 // FrontendContext's error report borrows the filename.
154 CHECK(report
->filename
.c_str() == filename
);
157 CHECK(!JS_IsExceptionPending(cx
));
159 JS::SetWarningReporter(cx
, warningReporter
);
161 bool result
= JS::ConvertFrontendErrorsToRuntimeErrors(cx
, fc
, options
);
164 CHECK(!JS_IsExceptionPending(cx
));
165 CHECK(warningReporterCalled
);
166 CHECK(!JS_IsThrowingOutOfMemory(cx
));
168 CHECK(errorNumberMatches
);
169 CHECK(filenameMatches
);
171 JS::DestroyFrontendContext(fc
);
176 static const char* filename
;
177 static bool warningReporterCalled
;
178 static bool errorNumberMatches
;
179 static bool filenameMatches
;
181 static void warningReporter(JSContext
* cx
, JSErrorReport
* report
) {
182 warningReporterCalled
= true;
184 errorNumberMatches
= report
->errorNumber
== JSMSG_STMT_AFTER_RETURN
;
185 filenameMatches
= report
->filename
.c_str() == filename
;
187 END_TEST(testFrontendErrors_warning
)
189 /* static */ const char* cls_testFrontendErrors_warning::filename
=
190 "testFrontendErrors_warning.js";
191 /* static */ bool cls_testFrontendErrors_warning::warningReporterCalled
= false;
192 /* static */ bool cls_testFrontendErrors_warning::errorNumberMatches
= false;
193 /* static */ bool cls_testFrontendErrors_warning::filenameMatches
= false;
195 BEGIN_TEST(testFrontendErrors_oom
) {
196 JS::FrontendContext
* fc
= JS::NewFrontendContext();
199 JS::PrefableCompileOptions prefableOptions
;
200 JS::CompileOptions
options(prefableOptions
);
202 CHECK(!JS::HadFrontendErrors(fc
));
204 js::ReportOutOfMemory(fc
);
206 CHECK(JS::HadFrontendErrors(fc
));
207 CHECK(!JS::HadFrontendOverRecursed(fc
));
208 CHECK(JS::HadFrontendOutOfMemory(fc
));
209 CHECK(!JS::HadFrontendAllocationOverflow(fc
));
210 CHECK(JS::GetFrontendWarningCount(fc
) == 0);
212 CHECK(!JS_IsExceptionPending(cx
));
214 JS::SetWarningReporter(cx
, warningReporter
);
216 bool result
= JS::ConvertFrontendErrorsToRuntimeErrors(cx
, fc
, options
);
219 CHECK(JS_IsExceptionPending(cx
));
220 CHECK(!warningReporterCalled
);
221 CHECK(JS_IsThrowingOutOfMemory(cx
));
223 JS_ClearPendingException(cx
);
225 JS::DestroyFrontendContext(fc
);
230 static bool warningReporterCalled
;
232 static void warningReporter(JSContext
* cx
, JSErrorReport
* report
) {
233 warningReporterCalled
= true;
235 END_TEST(testFrontendErrors_oom
)
237 /* static */ bool cls_testFrontendErrors_oom::warningReporterCalled
= false;
239 BEGIN_TEST(testFrontendErrors_overRecursed
) {
240 JS::FrontendContext
* fc
= JS::NewFrontendContext();
243 JS::PrefableCompileOptions prefableOptions
;
244 JS::CompileOptions
options(prefableOptions
);
246 CHECK(!JS::HadFrontendErrors(fc
));
248 js::ReportOverRecursed(fc
);
250 CHECK(JS::HadFrontendErrors(fc
));
251 CHECK(JS::HadFrontendOverRecursed(fc
));
252 CHECK(!JS::HadFrontendOutOfMemory(fc
));
253 CHECK(!JS::HadFrontendAllocationOverflow(fc
));
254 CHECK(JS::GetFrontendWarningCount(fc
) == 0);
256 CHECK(!JS_IsExceptionPending(cx
));
258 JS::SetWarningReporter(cx
, warningReporter
);
260 bool result
= JS::ConvertFrontendErrorsToRuntimeErrors(cx
, fc
, options
);
263 CHECK(JS_IsExceptionPending(cx
));
264 CHECK(!warningReporterCalled
);
265 CHECK(!JS_IsThrowingOutOfMemory(cx
));
268 JS::Rooted
<JS::Value
> exception(cx
);
269 CHECK(JS_GetPendingException(cx
, &exception
));
271 CHECK(exception
.isObject());
272 JS::Rooted
<JSObject
*> exceptionObj(cx
, &exception
.toObject());
274 const JSErrorReport
* report
= JS_ErrorFromException(cx
, exceptionObj
);
277 CHECK(report
->errorNumber
== JSMSG_OVER_RECURSED
);
280 JS_ClearPendingException(cx
);
282 JS::DestroyFrontendContext(fc
);
287 static bool warningReporterCalled
;
289 static void warningReporter(JSContext
* cx
, JSErrorReport
* report
) {
290 warningReporterCalled
= true;
292 END_TEST(testFrontendErrors_overRecursed
)
294 /* static */ bool cls_testFrontendErrors_overRecursed::warningReporterCalled
=
297 BEGIN_TEST(testFrontendErrors_allocationOverflow
) {
298 JS::FrontendContext
* fc
= JS::NewFrontendContext();
301 JS::PrefableCompileOptions prefableOptions
;
302 JS::CompileOptions
options(prefableOptions
);
304 CHECK(!JS::HadFrontendErrors(fc
));
306 js::ReportAllocationOverflow(fc
);
308 CHECK(JS::HadFrontendErrors(fc
));
309 CHECK(!JS::HadFrontendOverRecursed(fc
));
310 CHECK(!JS::HadFrontendOutOfMemory(fc
));
311 CHECK(JS::HadFrontendAllocationOverflow(fc
));
312 CHECK(JS::GetFrontendWarningCount(fc
) == 0);
314 CHECK(!JS_IsExceptionPending(cx
));
316 JS::SetWarningReporter(cx
, warningReporter
);
318 bool result
= JS::ConvertFrontendErrorsToRuntimeErrors(cx
, fc
, options
);
321 CHECK(JS_IsExceptionPending(cx
));
322 CHECK(!warningReporterCalled
);
323 CHECK(!JS_IsThrowingOutOfMemory(cx
));
326 JS::Rooted
<JS::Value
> exception(cx
);
327 CHECK(JS_GetPendingException(cx
, &exception
));
329 CHECK(exception
.isObject());
330 JS::Rooted
<JSObject
*> exceptionObj(cx
, &exception
.toObject());
332 const JSErrorReport
* report
= JS_ErrorFromException(cx
, exceptionObj
);
335 CHECK(report
->errorNumber
== JSMSG_ALLOC_OVERFLOW
);
338 JS_ClearPendingException(cx
);
340 JS::DestroyFrontendContext(fc
);
345 static bool warningReporterCalled
;
347 static void warningReporter(JSContext
* cx
, JSErrorReport
* report
) {
348 warningReporterCalled
= true;
350 END_TEST(testFrontendErrors_allocationOverflow
)
353 cls_testFrontendErrors_allocationOverflow::warningReporterCalled
= false;