Bug 1885489 - Part 5: Add SnapshotIterator::readInt32(). r=iain
[gecko.git] / js / src / builtin / TestingUtility.cpp
blob9d4af5897c190bf8e3cd3f722367712c4bbd3484
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 "builtin/TestingUtility.h"
9 #include <stdint.h> // uint32_t
11 #include "jsapi.h" // JS_NewPlainObject, JS_WrapValue
13 #include "frontend/CompilationStencil.h" // js::frontend::CompilationStencil
14 #include "js/CharacterEncoding.h" // JS_EncodeStringToUTF8
15 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
16 #include "js/CompileOptions.h" // JS::CompileOptions
17 #include "js/Conversions.h" // JS::ToBoolean, JS::ToString, JS::ToUint32, JS::ToInt32
18 #include "js/PropertyAndElement.h" // JS_GetProperty, JS_DefineProperty
19 #include "js/PropertyDescriptor.h" // JSPROP_ENUMERATE
20 #include "js/RealmOptions.h" // JS::RealmBehaviors
21 #include "js/RootingAPI.h" // JS::Rooted, JS::Handle
22 #include "js/Utility.h" // JS::UniqueChars
23 #include "js/Value.h" // JS::Value, JS::StringValue
24 #include "vm/JSContext.h" // JS::ReportUsageErrorASCII
25 #include "vm/JSScript.h"
26 #include "vm/Realm.h" // JS::Realm
28 bool js::ParseCompileOptions(JSContext* cx, JS::CompileOptions& options,
29 JS::Handle<JSObject*> opts,
30 JS::UniqueChars* fileNameBytes) {
31 JS::Rooted<JS::Value> v(cx);
32 JS::Rooted<JSString*> s(cx);
34 if (!JS_GetProperty(cx, opts, "isRunOnce", &v)) {
35 return false;
37 if (!v.isUndefined()) {
38 options.setIsRunOnce(JS::ToBoolean(v));
41 if (!JS_GetProperty(cx, opts, "noScriptRval", &v)) {
42 return false;
44 if (!v.isUndefined()) {
45 options.setNoScriptRval(JS::ToBoolean(v));
48 if (!JS_GetProperty(cx, opts, "fileName", &v)) {
49 return false;
51 if (v.isNull()) {
52 options.setFile(nullptr);
53 } else if (!v.isUndefined()) {
54 s = JS::ToString(cx, v);
55 if (!s) {
56 return false;
58 if (fileNameBytes) {
59 *fileNameBytes = JS_EncodeStringToUTF8(cx, s);
60 if (!*fileNameBytes) {
61 return false;
63 options.setFile(fileNameBytes->get());
67 if (!JS_GetProperty(cx, opts, "skipFileNameValidation", &v)) {
68 return false;
70 if (!v.isUndefined()) {
71 options.setSkipFilenameValidation(JS::ToBoolean(v));
74 if (!JS_GetProperty(cx, opts, "lineNumber", &v)) {
75 return false;
77 if (!v.isUndefined()) {
78 uint32_t u;
79 if (!JS::ToUint32(cx, v, &u)) {
80 return false;
82 options.setLine(u);
85 if (!JS_GetProperty(cx, opts, "columnNumber", &v)) {
86 return false;
88 if (!v.isUndefined()) {
89 int32_t c;
90 if (!JS::ToInt32(cx, v, &c)) {
91 return false;
93 if (c < 1) {
94 c = 1;
96 options.setColumn(JS::ColumnNumberOneOrigin(c));
99 if (!JS_GetProperty(cx, opts, "sourceIsLazy", &v)) {
100 return false;
102 if (v.isBoolean()) {
103 options.setSourceIsLazy(v.toBoolean());
106 if (!JS_GetProperty(cx, opts, "forceFullParse", &v)) {
107 return false;
109 bool forceFullParseIsSet = !v.isUndefined();
110 if (v.isBoolean() && v.toBoolean()) {
111 options.setForceFullParse();
114 if (!JS_GetProperty(cx, opts, "eagerDelazificationStrategy", &v)) {
115 return false;
117 if (forceFullParseIsSet && !v.isUndefined()) {
118 JS_ReportErrorASCII(
119 cx, "forceFullParse and eagerDelazificationStrategy are both set.");
120 return false;
122 if (v.isString()) {
123 s = JS::ToString(cx, v);
124 if (!s) {
125 return false;
128 JSLinearString* str = JS_EnsureLinearString(cx, s);
129 if (!str) {
130 return false;
133 bool found = false;
134 JS::DelazificationOption strategy = JS::DelazificationOption::OnDemandOnly;
136 #define MATCH_AND_SET_STRATEGY_(NAME) \
137 if (!found && JS_LinearStringEqualsLiteral(str, #NAME)) { \
138 strategy = JS::DelazificationOption::NAME; \
139 found = true; \
142 FOREACH_DELAZIFICATION_STRATEGY(MATCH_AND_SET_STRATEGY_);
143 #undef MATCH_AND_SET_STRATEGY_
144 #undef FOR_STRATEGY_NAMES
146 if (!found) {
147 JS_ReportErrorASCII(cx,
148 "eagerDelazificationStrategy does not match any "
149 "DelazificationOption.");
150 return false;
152 options.setEagerDelazificationStrategy(strategy);
155 return true;
158 bool js::ParseSourceOptions(JSContext* cx, JS::Handle<JSObject*> opts,
159 JS::MutableHandle<JSString*> displayURL,
160 JS::MutableHandle<JSString*> sourceMapURL) {
161 JS::Rooted<JS::Value> v(cx);
163 if (!JS_GetProperty(cx, opts, "displayURL", &v)) {
164 return false;
166 if (!v.isUndefined()) {
167 displayURL.set(ToString(cx, v));
168 if (!displayURL) {
169 return false;
173 if (!JS_GetProperty(cx, opts, "sourceMapURL", &v)) {
174 return false;
176 if (!v.isUndefined()) {
177 sourceMapURL.set(ToString(cx, v));
178 if (!sourceMapURL) {
179 return false;
183 return true;
186 bool js::SetSourceOptions(JSContext* cx, FrontendContext* fc,
187 ScriptSource* source,
188 JS::Handle<JSString*> displayURL,
189 JS::Handle<JSString*> sourceMapURL) {
190 if (displayURL && !source->hasDisplayURL()) {
191 JS::UniqueTwoByteChars chars = JS_CopyStringCharsZ(cx, displayURL);
192 if (!chars) {
193 return false;
195 if (!source->setDisplayURL(fc, std::move(chars))) {
196 return false;
199 if (sourceMapURL && !source->hasSourceMapURL()) {
200 JS::UniqueTwoByteChars chars = JS_CopyStringCharsZ(cx, sourceMapURL);
201 if (!chars) {
202 return false;
204 if (!source->setSourceMapURL(fc, std::move(chars))) {
205 return false;
209 return true;
212 JSObject* js::CreateScriptPrivate(JSContext* cx,
213 JS::Handle<JSString*> path /* = nullptr */) {
214 JS::Rooted<JSObject*> info(cx, JS_NewPlainObject(cx));
215 if (!info) {
216 return nullptr;
219 if (path) {
220 JS::Rooted<JS::Value> pathValue(cx, JS::StringValue(path));
221 if (!JS_DefineProperty(cx, info, "path", pathValue, JSPROP_ENUMERATE)) {
222 return nullptr;
226 return info;
229 bool js::ParseDebugMetadata(JSContext* cx, JS::Handle<JSObject*> opts,
230 JS::MutableHandle<JS::Value> privateValue,
231 JS::MutableHandle<JSString*> elementAttributeName) {
232 JS::Rooted<JS::Value> v(cx);
233 JS::Rooted<JSString*> s(cx);
235 if (!JS_GetProperty(cx, opts, "element", &v)) {
236 return false;
238 if (v.isObject()) {
239 JS::Rooted<JSObject*> infoObject(cx, CreateScriptPrivate(cx));
240 if (!infoObject) {
241 return false;
243 JS::Rooted<JS::Value> elementValue(cx, v);
244 if (!JS_WrapValue(cx, &elementValue)) {
245 return false;
247 if (!JS_DefineProperty(cx, infoObject, "element", elementValue, 0)) {
248 return false;
250 privateValue.set(JS::ObjectValue(*infoObject));
253 if (!JS_GetProperty(cx, opts, "elementAttributeName", &v)) {
254 return false;
256 if (!v.isUndefined()) {
257 s = ToString(cx, v);
258 if (!s) {
259 return false;
261 elementAttributeName.set(s);
264 return true;
267 JS::UniqueChars js::StringToLocale(JSContext* cx, JS::Handle<JSObject*> callee,
268 JS::Handle<JSString*> str_) {
269 Rooted<JSLinearString*> str(cx, str_->ensureLinear(cx));
270 if (!str) {
271 return nullptr;
274 if (!StringIsAscii(str)) {
275 ReportUsageErrorASCII(cx, callee,
276 "First argument contains non-ASCII characters");
277 return nullptr;
280 UniqueChars locale = JS_EncodeStringToASCII(cx, str);
281 if (!locale) {
282 return nullptr;
285 bool containsOnlyValidBCP47Characters =
286 mozilla::IsAsciiAlpha(locale[0]) &&
287 std::all_of(locale.get(), locale.get() + str->length(), [](auto c) {
288 return mozilla::IsAsciiAlphanumeric(c) || c == '-';
291 if (!containsOnlyValidBCP47Characters) {
292 ReportUsageErrorASCII(cx, callee,
293 "First argument should be a BCP47 language tag");
294 return nullptr;
297 return locale;
300 bool js::ValidateLazinessOfStencilAndGlobal(
301 JSContext* cx, const js::frontend::CompilationStencil& stencil) {
302 if (cx->realm()->behaviors().discardSource() && stencil.canLazilyParse) {
303 JS_ReportErrorASCII(cx,
304 "Stencil compiled with with lazy parse option cannot "
305 "be used in a realm with discardSource");
306 return false;
309 return true;
312 bool js::ValidateModuleCompileOptions(JSContext* cx,
313 JS::CompileOptions& options) {
314 if (options.lineno == 0) {
315 JS_ReportErrorASCII(cx, "Module cannot be compiled with lineNumber == 0");
316 return false;
319 if (!options.filename()) {
320 JS_ReportErrorASCII(cx, "Module should have filename");
321 return false;
324 return true;