/work/obj-fuzz/dist/include/js/CompileOptions.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | /* |
7 | | * Options for JavaScript compilation. |
8 | | * |
9 | | * In the most common use case, a CompileOptions instance is allocated on the |
10 | | * stack, and holds non-owning references to non-POD option values: strings, |
11 | | * principals, objects, and so on. The code declaring the instance guarantees |
12 | | * that such option values will outlive the CompileOptions itself: objects are |
13 | | * otherwise rooted, principals have had their reference counts bumped, and |
14 | | * strings won't be freed until the CompileOptions goes out of scope. In this |
15 | | * situation, CompileOptions only refers to things others own, so it can be |
16 | | * lightweight. |
17 | | * |
18 | | * In some cases, however, we need to hold compilation options with a |
19 | | * non-stack-like lifetime. For example, JS::CompileOffThread needs to save |
20 | | * compilation options where a worker thread can find them, then return |
21 | | * immediately. The worker thread will come along at some later point, and use |
22 | | * the options. |
23 | | * |
24 | | * The compiler itself just needs to be able to access a collection of options; |
25 | | * it doesn't care who owns them, or what's keeping them alive. It does its |
26 | | * own addrefs/copies/tracing/etc. |
27 | | * |
28 | | * Furthermore, in some cases compile options are propagated from one entity to |
29 | | * another (e.g. from a script to a function defined in that script). This |
30 | | * involves copying over some, but not all, of the options. |
31 | | * |
32 | | * So we have a class hierarchy that reflects these four use cases: |
33 | | * |
34 | | * - TransitiveCompileOptions is the common base class, representing options |
35 | | * that should get propagated from a script to functions defined in that |
36 | | * script. This class is abstract and is only ever used as a subclass. |
37 | | * |
38 | | * - ReadOnlyCompileOptions is the only subclass of TransitiveCompileOptions, |
39 | | * representing a full set of compile options. It can be used by code that |
40 | | * simply needs to access options set elsewhere, like the compiler. This |
41 | | * class too is abstract and is only ever used as a subclass. |
42 | | * |
43 | | * - The usual CompileOptions class must be stack-allocated, and holds |
44 | | * non-owning references to the filename, element, and so on. It's derived |
45 | | * from ReadOnlyCompileOptions, so the compiler can use it. |
46 | | * |
47 | | * - OwningCompileOptions roots / copies / reference counts of all its values, |
48 | | * and unroots / frees / releases them when it is destructed. It too is |
49 | | * derived from ReadOnlyCompileOptions, so the compiler accepts it. |
50 | | */ |
51 | | |
52 | | #ifndef js_CompileOptions_h |
53 | | #define js_CompileOptions_h |
54 | | |
55 | | #include "mozilla/Attributes.h" // MOZ_MUST_USE |
56 | | #include "mozilla/MemoryReporting.h" // mozilla::MallocSizeOf |
57 | | |
58 | | #include <stddef.h> // size_t |
59 | | #include <stdint.h> // uint8_t |
60 | | |
61 | | #include "jstypes.h" // JS_PUBLIC_API |
62 | | |
63 | | #include "js/RootingAPI.h" // JS::PersistentRooted, JS::Rooted |
64 | | |
65 | | struct JSContext; |
66 | | class JSObject; |
67 | | class JSScript; |
68 | | class JSString; |
69 | | |
70 | | namespace JS { |
71 | | |
72 | | enum class AsmJSOption : uint8_t |
73 | | { |
74 | | Enabled, |
75 | | Disabled, |
76 | | DisabledByDebugger, |
77 | | }; |
78 | | |
79 | | /** |
80 | | * The common base class for the CompileOptions hierarchy. |
81 | | * |
82 | | * Use this in code that needs to propagate compile options from one |
83 | | * compilation unit to another. |
84 | | */ |
85 | | class JS_PUBLIC_API(TransitiveCompileOptions) |
86 | | { |
87 | | protected: |
88 | | /** |
89 | | * The Web Platform allows scripts to be loaded from arbitrary cross-origin |
90 | | * sources. This allows an attack by which a malicious website loads a |
91 | | * sensitive file (say, a bank statement) cross-origin (using the user's |
92 | | * cookies), and sniffs the generated syntax errors (via a window.onerror |
93 | | * handler) for juicy morsels of its contents. |
94 | | * |
95 | | * To counter this attack, HTML5 specifies that script errors should be |
96 | | * sanitized ("muted") when the script is not same-origin with the global |
97 | | * for which it is loaded. Callers should set this flag for cross-origin |
98 | | * scripts, and it will be propagated appropriately to child scripts and |
99 | | * passed back in JSErrorReports. |
100 | | */ |
101 | | bool mutedErrors_ = false; |
102 | | |
103 | | const char* filename_ = nullptr; |
104 | | const char* introducerFilename_ = nullptr; |
105 | | const char16_t* sourceMapURL_ = nullptr; |
106 | | |
107 | | public: |
108 | | // POD options. |
109 | | bool selfHostingMode = false; |
110 | | bool canLazilyParse = true; |
111 | | bool strictOption = false; |
112 | | bool extraWarningsOption = false; |
113 | | bool werrorOption = false; |
114 | | AsmJSOption asmJSOption = AsmJSOption::Disabled; |
115 | | bool throwOnAsmJSValidationFailureOption = false; |
116 | | bool forceAsync = false; |
117 | | bool sourceIsLazy = false; |
118 | | bool allowHTMLComments = true; |
119 | | bool isProbablySystemCode = false; |
120 | | bool hideScriptFromDebugger = false; |
121 | | |
122 | | /** |
123 | | * |introductionType| is a statically allocated C string: one of "eval", |
124 | | * "Function", or "GeneratorFunction". |
125 | | */ |
126 | | const char* introductionType = nullptr; |
127 | | |
128 | | unsigned introductionLineno = 0; |
129 | | uint32_t introductionOffset = 0; |
130 | | bool hasIntroductionInfo = false; |
131 | | |
132 | | protected: |
133 | 1.51k | TransitiveCompileOptions() = default; |
134 | | |
135 | | // Set all POD options (those not requiring reference counts, copies, |
136 | | // rooting, or other hand-holding) to their values in |rhs|. |
137 | | void copyPODTransitiveOptions(const TransitiveCompileOptions& rhs); |
138 | | |
139 | | public: |
140 | | // Read-only accessors for non-POD options. The proper way to set these |
141 | | // depends on the derived type. |
142 | 0 | bool mutedErrors() const { return mutedErrors_; } |
143 | 1.48k | const char* filename() const { return filename_; } |
144 | 1.48k | const char* introducerFilename() const { return introducerFilename_; } |
145 | 1.48k | const char16_t* sourceMapURL() const { return sourceMapURL_; } |
146 | | virtual JSObject* element() const = 0; |
147 | | virtual JSString* elementAttributeName() const = 0; |
148 | | virtual JSScript* introductionScript() const = 0; |
149 | | |
150 | | private: |
151 | | void operator=(const TransitiveCompileOptions&) = delete; |
152 | | }; |
153 | | |
154 | | class JS_PUBLIC_API(CompileOptions); |
155 | | |
156 | | /** |
157 | | * The class representing a full set of compile options. |
158 | | * |
159 | | * Use this in code that only needs to access compilation options created |
160 | | * elsewhere, like the compiler. Don't instantiate this class (the constructor |
161 | | * is protected anyway); instead, create instances only of the derived classes: |
162 | | * CompileOptions and OwningCompileOptions. |
163 | | */ |
164 | | class JS_PUBLIC_API(ReadOnlyCompileOptions) |
165 | | : public TransitiveCompileOptions |
166 | | { |
167 | | public: |
168 | | // POD options. |
169 | | unsigned lineno = 1; |
170 | | unsigned column = 0; |
171 | | |
172 | | // The offset within the ScriptSource's full uncompressed text of the first |
173 | | // character we're presenting for compilation with this CompileOptions. |
174 | | // |
175 | | // When we compile a LazyScript, we pass the compiler only the substring of |
176 | | // the source the lazy function occupies. With chunked decompression, we |
177 | | // may not even have the complete uncompressed source present in memory. But |
178 | | // parse node positions are offsets within the ScriptSource's full text, |
179 | | // and LazyScripts indicate their substring of the full source by its |
180 | | // starting and ending offsets within the full text. This |
181 | | // scriptSourceOffset field lets the frontend convert between these |
182 | | // offsets and offsets within the substring presented for compilation. |
183 | | unsigned scriptSourceOffset = 0; |
184 | | |
185 | | // isRunOnce only applies to non-function scripts. |
186 | | bool isRunOnce = false; |
187 | | |
188 | | bool nonSyntacticScope = false; |
189 | | bool noScriptRval = false; |
190 | | bool allowSyntaxParser = true; |
191 | | |
192 | | |
193 | | private: |
194 | | friend class CompileOptions; |
195 | | |
196 | | protected: |
197 | 1.51k | ReadOnlyCompileOptions() = default; |
198 | | |
199 | | // Set all POD options (those not requiring reference counts, copies, |
200 | | // rooting, or other hand-holding) to their values in |rhs|. |
201 | | void copyPODOptions(const ReadOnlyCompileOptions& rhs); |
202 | | |
203 | | public: |
204 | | // Read-only accessors for non-POD options. The proper way to set these |
205 | | // depends on the derived type. |
206 | 26 | bool mutedErrors() const { return mutedErrors_; } |
207 | 43 | const char* filename() const { return filename_; } |
208 | 26 | const char* introducerFilename() const { return introducerFilename_; } |
209 | 16 | const char16_t* sourceMapURL() const { return sourceMapURL_; } |
210 | | virtual JSObject* element() const override = 0; |
211 | | virtual JSString* elementAttributeName() const override = 0; |
212 | | virtual JSScript* introductionScript() const override = 0; |
213 | | |
214 | | private: |
215 | | void operator=(const ReadOnlyCompileOptions&) = delete; |
216 | | }; |
217 | | |
218 | | /** |
219 | | * Compilation options, with dynamic lifetime. An instance of this type |
220 | | * makes a copy of / holds / roots all dynamically allocated resources |
221 | | * (principals; elements; strings) that it refers to. Its destructor frees |
222 | | * / drops / unroots them. This is heavier than CompileOptions, below, but |
223 | | * unlike CompileOptions, it can outlive any given stack frame. |
224 | | * |
225 | | * Note that this *roots* any JS values it refers to - they're live |
226 | | * unconditionally. Thus, instances of this type can't be owned, directly |
227 | | * or indirectly, by a JavaScript object: if any value that this roots ever |
228 | | * comes to refer to the object that owns this, then the whole cycle, and |
229 | | * anything else it entrains, will never be freed. |
230 | | */ |
231 | | class JS_PUBLIC_API(OwningCompileOptions) final |
232 | | : public ReadOnlyCompileOptions |
233 | | { |
234 | | PersistentRooted<JSObject*> elementRoot; |
235 | | PersistentRooted<JSString*> elementAttributeNameRoot; |
236 | | PersistentRooted<JSScript*> introductionScriptRoot; |
237 | | |
238 | | public: |
239 | | // A minimal constructor, for use with OwningCompileOptions::copy. |
240 | | explicit OwningCompileOptions(JSContext* cx); |
241 | | ~OwningCompileOptions(); |
242 | | |
243 | 0 | JSObject* element() const override { return elementRoot; } |
244 | 0 | JSString* elementAttributeName() const override { return elementAttributeNameRoot; } |
245 | 0 | JSScript* introductionScript() const override { return introductionScriptRoot; } |
246 | | |
247 | | /** Set this to a copy of |rhs|. Return false on OOM. */ |
248 | | bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs); |
249 | | |
250 | | /* These setters make copies of their string arguments and are fallible. */ |
251 | | MOZ_MUST_USE bool setFile(JSContext* cx, const char* f); |
252 | | MOZ_MUST_USE bool setFileAndLine(JSContext* cx, const char* f, unsigned l); |
253 | | MOZ_MUST_USE bool setSourceMapURL(JSContext* cx, const char16_t* s); |
254 | | MOZ_MUST_USE bool setIntroducerFilename(JSContext* cx, const char* s); |
255 | | |
256 | | /* These setters are infallible, and can be chained. */ |
257 | | |
258 | 0 | OwningCompileOptions& setLine(unsigned l) { |
259 | 0 | lineno = l; |
260 | 0 | return *this; |
261 | 0 | } |
262 | | |
263 | 0 | OwningCompileOptions& setElement(JSObject* e) { |
264 | 0 | elementRoot = e; |
265 | 0 | return *this; |
266 | 0 | } |
267 | | |
268 | 0 | OwningCompileOptions& setElementAttributeName(JSString* p) { |
269 | 0 | elementAttributeNameRoot = p; |
270 | 0 | return *this; |
271 | 0 | } |
272 | | |
273 | 0 | OwningCompileOptions& setIntroductionScript(JSScript* s) { |
274 | 0 | introductionScriptRoot = s; |
275 | 0 | return *this; |
276 | 0 | } |
277 | | |
278 | 0 | OwningCompileOptions& setMutedErrors(bool mute) { |
279 | 0 | mutedErrors_ = mute; |
280 | 0 | return *this; |
281 | 0 | } |
282 | | |
283 | 0 | OwningCompileOptions& setColumn(unsigned c) { |
284 | 0 | column = c; |
285 | 0 | return *this; |
286 | 0 | } |
287 | | |
288 | 0 | OwningCompileOptions& setScriptSourceOffset(unsigned o) { |
289 | 0 | scriptSourceOffset = o; |
290 | 0 | return *this; |
291 | 0 | } |
292 | | |
293 | 0 | OwningCompileOptions& setIsRunOnce(bool once) { |
294 | 0 | isRunOnce = once; |
295 | 0 | return *this; |
296 | 0 | } |
297 | | |
298 | 0 | OwningCompileOptions& setNoScriptRval(bool nsr) { |
299 | 0 | noScriptRval = nsr; |
300 | 0 | return *this; |
301 | 0 | } |
302 | | |
303 | 0 | OwningCompileOptions& setSelfHostingMode(bool shm) { |
304 | 0 | selfHostingMode = shm; |
305 | 0 | return *this; |
306 | 0 | } |
307 | | |
308 | 0 | OwningCompileOptions& setCanLazilyParse(bool clp) { |
309 | 0 | canLazilyParse = clp; |
310 | 0 | return *this; |
311 | 0 | } |
312 | | |
313 | 0 | OwningCompileOptions& setAllowSyntaxParser(bool clp) { |
314 | 0 | allowSyntaxParser = clp; |
315 | 0 | return *this; |
316 | 0 | } |
317 | | |
318 | 0 | OwningCompileOptions& setSourceIsLazy(bool l) { |
319 | 0 | sourceIsLazy = l; |
320 | 0 | return *this; |
321 | 0 | } |
322 | | |
323 | 0 | OwningCompileOptions& setNonSyntacticScope(bool n) { |
324 | 0 | nonSyntacticScope = n; |
325 | 0 | return *this; |
326 | 0 | } |
327 | | |
328 | 0 | OwningCompileOptions& setIntroductionType(const char* t) { |
329 | 0 | introductionType = t; |
330 | 0 | return *this; |
331 | 0 | } |
332 | | |
333 | | bool setIntroductionInfo(JSContext* cx, const char* introducerFn, |
334 | | const char* intro, unsigned line, |
335 | | JSScript* script, uint32_t offset) |
336 | 0 | { |
337 | 0 | if (!setIntroducerFilename(cx, introducerFn)) { |
338 | 0 | return false; |
339 | 0 | } |
340 | 0 |
|
341 | 0 | introductionType = intro; |
342 | 0 | introductionLineno = line; |
343 | 0 | introductionScriptRoot = script; |
344 | 0 | introductionOffset = offset; |
345 | 0 | hasIntroductionInfo = true; |
346 | 0 | return true; |
347 | 0 | } |
348 | | |
349 | | size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
350 | | |
351 | | private: |
352 | | void operator=(const CompileOptions& rhs) = delete; |
353 | | }; |
354 | | |
355 | | /** |
356 | | * Compilation options stored on the stack. An instance of this type |
357 | | * simply holds references to dynamically allocated resources (element; |
358 | | * filename; source map URL) that are owned by something else. If you |
359 | | * create an instance of this type, it's up to you to guarantee that |
360 | | * everything you store in it will outlive it. |
361 | | */ |
362 | | class MOZ_STACK_CLASS JS_PUBLIC_API(CompileOptions) final |
363 | | : public ReadOnlyCompileOptions |
364 | | { |
365 | | private: |
366 | | Rooted<JSObject*> elementRoot; |
367 | | Rooted<JSString*> elementAttributeNameRoot; |
368 | | Rooted<JSScript*> introductionScriptRoot; |
369 | | |
370 | | public: |
371 | | explicit CompileOptions(JSContext* cx); |
372 | | |
373 | | CompileOptions(JSContext* cx, const ReadOnlyCompileOptions& rhs) |
374 | | : ReadOnlyCompileOptions(), |
375 | | elementRoot(cx), |
376 | | elementAttributeNameRoot(cx), |
377 | | introductionScriptRoot(cx) |
378 | 8 | { |
379 | 8 | copyPODOptions(rhs); |
380 | 8 | |
381 | 8 | filename_ = rhs.filename(); |
382 | 8 | introducerFilename_ = rhs.introducerFilename(); |
383 | 8 | sourceMapURL_ = rhs.sourceMapURL(); |
384 | 8 | elementRoot = rhs.element(); |
385 | 8 | elementAttributeNameRoot = rhs.elementAttributeName(); |
386 | 8 | introductionScriptRoot = rhs.introductionScript(); |
387 | 8 | } |
388 | | |
389 | | CompileOptions(JSContext* cx, const TransitiveCompileOptions& rhs) |
390 | | : ReadOnlyCompileOptions(), |
391 | | elementRoot(cx), |
392 | | elementAttributeNameRoot(cx), |
393 | | introductionScriptRoot(cx) |
394 | 1.48k | { |
395 | 1.48k | copyPODTransitiveOptions(rhs); |
396 | 1.48k | |
397 | 1.48k | filename_ = rhs.filename(); |
398 | 1.48k | introducerFilename_ = rhs.introducerFilename(); |
399 | 1.48k | sourceMapURL_ = rhs.sourceMapURL(); |
400 | 1.48k | elementRoot = rhs.element(); |
401 | 1.48k | elementAttributeNameRoot = rhs.elementAttributeName(); |
402 | 1.48k | introductionScriptRoot = rhs.introductionScript(); |
403 | 1.48k | } |
404 | | |
405 | 1.50k | JSObject* element() const override { |
406 | 1.50k | return elementRoot; |
407 | 1.50k | } |
408 | | |
409 | 1.50k | JSString* elementAttributeName() const override { |
410 | 1.50k | return elementAttributeNameRoot; |
411 | 1.50k | } |
412 | | |
413 | 1.50k | JSScript* introductionScript() const override { |
414 | 1.50k | return introductionScriptRoot; |
415 | 1.50k | } |
416 | | |
417 | 0 | CompileOptions& setFile(const char* f) { |
418 | 0 | filename_ = f; |
419 | 0 | return *this; |
420 | 0 | } |
421 | | |
422 | 0 | CompileOptions& setLine(unsigned l) { |
423 | 0 | lineno = l; |
424 | 0 | return *this; |
425 | 0 | } |
426 | | |
427 | 9 | CompileOptions& setFileAndLine(const char* f, unsigned l) { |
428 | 9 | filename_ = f; |
429 | 9 | lineno = l; |
430 | 9 | return *this; |
431 | 9 | } |
432 | | |
433 | 0 | CompileOptions& setSourceMapURL(const char16_t* s) { |
434 | 0 | sourceMapURL_ = s; |
435 | 0 | return *this; |
436 | 0 | } |
437 | | |
438 | 0 | CompileOptions& setElement(JSObject* e) { |
439 | 0 | elementRoot = e; |
440 | 0 | return *this; |
441 | 0 | } |
442 | | |
443 | 0 | CompileOptions& setElementAttributeName(JSString* p) { |
444 | 0 | elementAttributeNameRoot = p; |
445 | 0 | return *this; |
446 | 0 | } |
447 | | |
448 | 0 | CompileOptions& setIntroductionScript(JSScript* s) { |
449 | 0 | introductionScriptRoot = s; |
450 | 0 | return *this; |
451 | 0 | } |
452 | | |
453 | 6 | CompileOptions& setMutedErrors(bool mute) { |
454 | 6 | mutedErrors_ = mute; |
455 | 6 | return *this; |
456 | 6 | } |
457 | | |
458 | 0 | CompileOptions& setColumn(unsigned c) { |
459 | 0 | column = c; |
460 | 0 | return *this; |
461 | 0 | } |
462 | | |
463 | 0 | CompileOptions& setScriptSourceOffset(unsigned o) { |
464 | 0 | scriptSourceOffset = o; |
465 | 0 | return *this; |
466 | 0 | } |
467 | | |
468 | 3 | CompileOptions& setIsRunOnce(bool once) { |
469 | 3 | isRunOnce = once; |
470 | 3 | return *this; |
471 | 3 | } |
472 | | |
473 | 20 | CompileOptions& setNoScriptRval(bool nsr) { |
474 | 20 | noScriptRval = nsr; |
475 | 20 | return *this; |
476 | 20 | } |
477 | | |
478 | 10 | CompileOptions& setSelfHostingMode(bool shm) { |
479 | 10 | selfHostingMode = shm; |
480 | 10 | return *this; |
481 | 10 | } |
482 | | |
483 | 4 | CompileOptions& setCanLazilyParse(bool clp) { |
484 | 4 | canLazilyParse = clp; |
485 | 4 | return *this; |
486 | 4 | } |
487 | | |
488 | 0 | CompileOptions& setAllowSyntaxParser(bool clp) { |
489 | 0 | allowSyntaxParser = clp; |
490 | 0 | return *this; |
491 | 0 | } |
492 | | |
493 | 5 | CompileOptions& setSourceIsLazy(bool l) { |
494 | 5 | sourceIsLazy = l; |
495 | 5 | return *this; |
496 | 5 | } |
497 | | |
498 | 5 | CompileOptions& setNonSyntacticScope(bool n) { |
499 | 5 | nonSyntacticScope = n; |
500 | 5 | return *this; |
501 | 5 | } |
502 | | |
503 | 13 | CompileOptions& setIntroductionType(const char* t) { |
504 | 13 | introductionType = t; |
505 | 13 | return *this; |
506 | 13 | } |
507 | | |
508 | | CompileOptions& setIntroductionInfo(const char* introducerFn, |
509 | | const char* intro, unsigned line, |
510 | | JSScript* script, uint32_t offset) |
511 | 0 | { |
512 | 0 | introducerFilename_ = introducerFn; |
513 | 0 | introductionType = intro; |
514 | 0 | introductionLineno = line; |
515 | 0 | introductionScriptRoot = script; |
516 | 0 | introductionOffset = offset; |
517 | 0 | hasIntroductionInfo = true; |
518 | 0 | return *this; |
519 | 0 | } |
520 | | |
521 | 5 | CompileOptions& maybeMakeStrictMode(bool strict) { |
522 | 5 | strictOption = strictOption || strict; |
523 | 5 | return *this; |
524 | 5 | } |
525 | | |
526 | | private: |
527 | | void operator=(const CompileOptions& rhs) = delete; |
528 | | }; |
529 | | |
530 | | } // namespace JS |
531 | | |
532 | | #endif /* js_CompileOptions_h */ |