Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / Frontend2.cpp
blob025d676a4b00363034f6a50f07a99c5cdc817c1a
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 "frontend/Frontend2.h"
9 #include "mozilla/Maybe.h" // mozilla::Maybe
10 #include "mozilla/OperatorNewExtensions.h" // mozilla::KnownNotNull
11 #include "mozilla/Range.h" // mozilla::Range
12 #include "mozilla/Span.h" // mozilla::Span
13 #include "mozilla/Variant.h" // mozilla::AsVariant
15 #include <stddef.h> // size_t
16 #include <stdint.h> // uint8_t, uint32_t
18 #include "jsapi.h"
20 #include "frontend/AbstractScopePtr.h" // ScopeIndex
21 #include "frontend/BytecodeSection.h" // EmitScriptThingsVector
22 #include "frontend/CompilationStencil.h" // CompilationState, CompilationStencil
23 #include "frontend/FrontendContext.h" // AutoReportFrontendContext
24 #include "frontend/Parser.h" // NewEmptyLexicalScopeData, NewEmptyGlobalScopeData, NewEmptyVarScopeData, NewEmptyFunctionScopeData
25 #include "frontend/ParserAtom.h" // ParserAtomsTable, TaggedParserAtomIndex
26 #include "frontend/ScriptIndex.h" // ScriptIndex
27 #include "frontend/smoosh_generated.h" // CVec, Smoosh*, smoosh_*
28 #include "frontend/SourceNotes.h" // SrcNote
29 #include "frontend/Stencil.h" // ScopeStencil, RegExpIndex
30 #include "frontend/TokenStream.h" // TokenStreamAnyChars
31 #include "irregexp/RegExpAPI.h" // irregexp::CheckPatternSyntax
32 #include "js/CharacterEncoding.h" // JS::UTF8Chars, UTF8CharsToNewTwoByteCharsZ, JS::ConstUTF8CharsZ
33 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin, JS::LimitedColumnNumberOneOrigin
34 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
35 #include "js/GCAPI.h" // JS::AutoCheckCannotGC
36 #include "js/HeapAPI.h" // JS::GCCellPtr
37 #include "js/RegExpFlags.h" // JS::RegExpFlag, JS::RegExpFlags
38 #include "js/RootingAPI.h" // JS::MutableHandle
39 #include "js/UniquePtr.h" // js::UniquePtr
40 #include "js/Utility.h" // JS::UniqueTwoByteChars, StringBufferArena
41 #include "vm/JSScript.h" // JSScript
42 #include "vm/Scope.h" // GetScopeDataTrailingNames
43 #include "vm/ScopeKind.h" // ScopeKind
44 #include "vm/SharedStencil.h" // ImmutableScriptData, ScopeNote, TryNote, GCThingIndex
46 using mozilla::Utf8Unit;
48 using namespace js::gc;
49 using namespace js::frontend;
50 using namespace js;
52 namespace js {
54 namespace frontend {
56 // Given the result of SmooshMonkey's parser, Convert the list of atoms into
57 // the list of ParserAtoms.
58 bool ConvertAtoms(JSContext* cx, FrontendContext* fc,
59 const SmooshResult& result,
60 CompilationState& compilationState,
61 Vector<TaggedParserAtomIndex>& allAtoms) {
62 size_t numAtoms = result.all_atoms_len;
64 if (!allAtoms.reserve(numAtoms)) {
65 return false;
68 for (size_t i = 0; i < numAtoms; i++) {
69 auto s = reinterpret_cast<const mozilla::Utf8Unit*>(
70 smoosh_get_atom_at(result, i));
71 auto len = smoosh_get_atom_len_at(result, i);
72 auto atom = compilationState.parserAtoms.internUtf8(fc, s, len);
73 if (!atom) {
74 return false;
76 // We don't collect atomization information in smoosh yet.
77 // Assume it needs to be atomized.
78 compilationState.parserAtoms.markUsedByStencil(atom,
79 ParserAtom::Atomize::Yes);
80 allAtoms.infallibleAppend(atom);
83 return true;
86 void CopyBindingNames(JSContext* cx, CVec<SmooshBindingName>& from,
87 Vector<TaggedParserAtomIndex>& allAtoms,
88 ParserBindingName* to) {
89 // We're setting trailing array's content before setting its length.
90 JS::AutoCheckCannotGC nogc(cx);
92 size_t numBindings = from.len;
93 for (size_t i = 0; i < numBindings; i++) {
94 SmooshBindingName& name = from.data[i];
95 new (mozilla::KnownNotNull, &to[i]) ParserBindingName(
96 allAtoms[name.name], name.is_closed_over, name.is_top_level_function);
100 void CopyBindingNames(JSContext* cx, CVec<COption<SmooshBindingName>>& from,
101 Vector<TaggedParserAtomIndex>& allAtoms,
102 ParserBindingName* to) {
103 // We're setting trailing array's content before setting its length.
104 JS::AutoCheckCannotGC nogc(cx);
106 size_t numBindings = from.len;
107 for (size_t i = 0; i < numBindings; i++) {
108 COption<SmooshBindingName>& maybeName = from.data[i];
109 if (maybeName.IsSome()) {
110 SmooshBindingName& name = maybeName.AsSome();
111 new (mozilla::KnownNotNull, &to[i]) ParserBindingName(
112 allAtoms[name.name], name.is_closed_over, name.is_top_level_function);
113 } else {
114 new (mozilla::KnownNotNull, &to[i])
115 ParserBindingName(TaggedParserAtomIndex::null(), false, false);
120 // Given the result of SmooshMonkey's parser, convert a list of scope data
121 // into a list of ScopeStencil.
122 bool ConvertScopeStencil(JSContext* cx, FrontendContext* fc,
123 const SmooshResult& result,
124 Vector<TaggedParserAtomIndex>& allAtoms,
125 CompilationState& compilationState) {
126 LifoAlloc& alloc = compilationState.alloc;
128 if (result.scopes.len > TaggedScriptThingIndex::IndexLimit) {
129 ReportAllocationOverflow(fc);
130 return false;
133 for (size_t i = 0; i < result.scopes.len; i++) {
134 SmooshScopeData& scopeData = result.scopes.data[i];
135 ScopeIndex index;
137 switch (scopeData.tag) {
138 case SmooshScopeData::Tag::Global: {
139 auto& global = scopeData.AsGlobal();
141 size_t numBindings = global.bindings.len;
142 GlobalScope::ParserData* data =
143 NewEmptyGlobalScopeData(fc, alloc, numBindings);
144 if (!data) {
145 return false;
148 CopyBindingNames(cx, global.bindings, allAtoms,
149 GetScopeDataTrailingNamesPointer(data));
151 data->slotInfo.letStart = global.let_start;
152 data->slotInfo.constStart = global.const_start;
153 data->length = numBindings;
155 if (!ScopeStencil::createForGlobalScope(
156 fc, compilationState, ScopeKind::Global, data, &index)) {
157 return false;
159 break;
161 case SmooshScopeData::Tag::Var: {
162 auto& var = scopeData.AsVar();
164 size_t numBindings = var.bindings.len;
166 VarScope::ParserData* data =
167 NewEmptyVarScopeData(fc, alloc, numBindings);
168 if (!data) {
169 return false;
172 CopyBindingNames(cx, var.bindings, allAtoms,
173 GetScopeDataTrailingNamesPointer(data));
175 // NOTE: data->slotInfo.nextFrameSlot is set in
176 // ScopeStencil::createForVarScope.
178 data->length = numBindings;
180 uint32_t firstFrameSlot = var.first_frame_slot;
181 ScopeIndex enclosingIndex(var.enclosing);
182 if (!ScopeStencil::createForVarScope(
183 fc, compilationState, ScopeKind::FunctionBodyVar, data,
184 firstFrameSlot, var.function_has_extensible_scope,
185 mozilla::Some(enclosingIndex), &index)) {
186 return false;
188 break;
190 case SmooshScopeData::Tag::Lexical: {
191 auto& lexical = scopeData.AsLexical();
193 size_t numBindings = lexical.bindings.len;
194 LexicalScope::ParserData* data =
195 NewEmptyLexicalScopeData(fc, alloc, numBindings);
196 if (!data) {
197 return false;
200 CopyBindingNames(cx, lexical.bindings, allAtoms,
201 GetScopeDataTrailingNamesPointer(data));
203 // NOTE: data->slotInfo.nextFrameSlot is set in
204 // ScopeStencil::createForLexicalScope.
206 data->slotInfo.constStart = lexical.const_start;
207 data->length = numBindings;
209 uint32_t firstFrameSlot = lexical.first_frame_slot;
210 ScopeIndex enclosingIndex(lexical.enclosing);
211 if (!ScopeStencil::createForLexicalScope(
212 fc, compilationState, ScopeKind::Lexical, data, firstFrameSlot,
213 mozilla::Some(enclosingIndex), &index)) {
214 return false;
216 break;
218 case SmooshScopeData::Tag::Function: {
219 auto& function = scopeData.AsFunction();
221 size_t numBindings = function.bindings.len;
222 FunctionScope::ParserData* data =
223 NewEmptyFunctionScopeData(fc, alloc, numBindings);
224 if (!data) {
225 return false;
228 CopyBindingNames(cx, function.bindings, allAtoms,
229 GetScopeDataTrailingNamesPointer(data));
231 // NOTE: data->slotInfo.nextFrameSlot is set in
232 // ScopeStencil::createForFunctionScope.
234 if (function.has_parameter_exprs) {
235 data->slotInfo.setHasParameterExprs();
237 data->slotInfo.nonPositionalFormalStart =
238 function.non_positional_formal_start;
239 data->slotInfo.varStart = function.var_start;
240 data->length = numBindings;
242 bool hasParameterExprs = function.has_parameter_exprs;
243 bool needsEnvironment = function.non_positional_formal_start;
244 ScriptIndex functionIndex = ScriptIndex(function.function_index);
245 bool isArrow = function.is_arrow;
247 ScopeIndex enclosingIndex(function.enclosing);
248 if (!ScopeStencil::createForFunctionScope(
249 fc, compilationState, data, hasParameterExprs, needsEnvironment,
250 functionIndex, isArrow, mozilla::Some(enclosingIndex),
251 &index)) {
252 return false;
254 break;
258 // `ConvertGCThings` depends on this condition.
259 MOZ_ASSERT(index == i);
262 return true;
265 // Given the result of SmooshMonkey's parser, convert a list of RegExp data
266 // into a list of RegExpStencil.
267 bool ConvertRegExpData(JSContext* cx, FrontendContext* fc,
268 const SmooshResult& result,
269 CompilationState& compilationState) {
270 auto len = result.regexps.len;
271 if (len == 0) {
272 return true;
275 if (len > TaggedScriptThingIndex::IndexLimit) {
276 ReportAllocationOverflow(fc);
277 return false;
280 if (!compilationState.regExpData.reserve(len)) {
281 js::ReportOutOfMemory(fc);
282 return false;
285 for (size_t i = 0; i < len; i++) {
286 SmooshRegExpItem& item = result.regexps.data[i];
287 auto s = smoosh_get_slice_at(result, item.pattern);
288 auto len = smoosh_get_slice_len_at(result, item.pattern);
290 JS::RegExpFlags::Flag flags = JS::RegExpFlag::NoFlags;
291 if (item.global) {
292 flags |= JS::RegExpFlag::Global;
294 if (item.ignore_case) {
295 flags |= JS::RegExpFlag::IgnoreCase;
297 if (item.multi_line) {
298 flags |= JS::RegExpFlag::Multiline;
300 if (item.dot_all) {
301 flags |= JS::RegExpFlag::DotAll;
303 if (item.sticky) {
304 flags |= JS::RegExpFlag::Sticky;
306 if (item.unicode) {
307 flags |= JS::RegExpFlag::Unicode;
310 // FIXME: This check should be done at parse time.
311 size_t length;
312 JS::UniqueTwoByteChars pattern(
313 UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(s, len), &length,
314 StringBufferArena)
315 .get());
316 if (!pattern) {
317 return false;
320 mozilla::Range<const char16_t> range(pattern.get(), length);
322 TokenStreamAnyChars ts(fc, compilationState.input.options,
323 /* smg = */ nullptr);
325 // See Parser<FullParseHandler, Unit>::newRegExp.
327 if (!irregexp::CheckPatternSyntax(cx->tempLifoAlloc(), fc->stackLimit(), ts,
328 range, flags)) {
329 return false;
332 const mozilla::Utf8Unit* sUtf8 =
333 reinterpret_cast<const mozilla::Utf8Unit*>(s);
334 auto atom = compilationState.parserAtoms.internUtf8(fc, sUtf8, len);
335 if (!atom) {
336 return false;
339 // RegExp patterm must be atomized.
340 compilationState.parserAtoms.markUsedByStencil(atom,
341 ParserAtom::Atomize::Yes);
342 compilationState.regExpData.infallibleEmplaceBack(atom,
343 JS::RegExpFlags(flags));
346 return true;
349 // Convert SmooshImmutableScriptData into ImmutableScriptData.
350 UniquePtr<ImmutableScriptData> ConvertImmutableScriptData(
351 JSContext* cx, const SmooshImmutableScriptData& smooshScriptData,
352 bool isFunction) {
353 Vector<ScopeNote, 0, SystemAllocPolicy> scopeNotes;
354 if (!scopeNotes.resize(smooshScriptData.scope_notes.len)) {
355 return nullptr;
357 for (size_t i = 0; i < smooshScriptData.scope_notes.len; i++) {
358 SmooshScopeNote& scopeNote = smooshScriptData.scope_notes.data[i];
359 scopeNotes[i].index = GCThingIndex(scopeNote.index);
360 scopeNotes[i].start = scopeNote.start;
361 scopeNotes[i].length = scopeNote.length;
362 scopeNotes[i].parent = scopeNote.parent;
365 AutoReportFrontendContext fc(cx);
366 return ImmutableScriptData::new_(
367 &fc, smooshScriptData.main_offset, smooshScriptData.nfixed,
368 smooshScriptData.nslots, GCThingIndex(smooshScriptData.body_scope_index),
369 smooshScriptData.num_ic_entries, isFunction, smooshScriptData.fun_length,
371 mozilla::Span(smooshScriptData.bytecode.data,
372 smooshScriptData.bytecode.len),
373 mozilla::Span<const SrcNote>(), mozilla::Span<const uint32_t>(),
374 scopeNotes, mozilla::Span<const TryNote>());
377 // Given the result of SmooshMonkey's parser, convert a list of GC things
378 // used by a script into ScriptThingsVector.
379 bool ConvertGCThings(JSContext* cx, FrontendContext* fc,
380 const SmooshResult& result,
381 const SmooshScriptStencil& smooshScript,
382 CompilationState& compilationState,
383 Vector<TaggedParserAtomIndex>& allAtoms,
384 ScriptIndex scriptIndex) {
385 size_t ngcthings = smooshScript.gcthings.len;
387 // If there are no things, avoid the allocation altogether.
388 if (ngcthings == 0) {
389 return true;
392 TaggedScriptThingIndex* cursor = nullptr;
393 if (!compilationState.allocateGCThingsUninitialized(fc, scriptIndex,
394 ngcthings, &cursor)) {
395 return false;
398 for (size_t i = 0; i < ngcthings; i++) {
399 SmooshGCThing& item = smooshScript.gcthings.data[i];
401 // Pointer to the uninitialized element.
402 void* raw = &cursor[i];
404 switch (item.tag) {
405 case SmooshGCThing::Tag::Null: {
406 new (raw) TaggedScriptThingIndex();
407 break;
409 case SmooshGCThing::Tag::Atom: {
410 new (raw) TaggedScriptThingIndex(allAtoms[item.AsAtom()]);
411 break;
413 case SmooshGCThing::Tag::Function: {
414 new (raw) TaggedScriptThingIndex(ScriptIndex(item.AsFunction()));
415 break;
417 case SmooshGCThing::Tag::Scope: {
418 new (raw) TaggedScriptThingIndex(ScopeIndex(item.AsScope()));
419 break;
421 case SmooshGCThing::Tag::RegExp: {
422 new (raw) TaggedScriptThingIndex(RegExpIndex(item.AsRegExp()));
423 break;
428 return true;
431 // Given the result of SmooshMonkey's parser, convert a specific script
432 // or function to a StencilScript, given a fixed set of source atoms.
434 // The StencilScript would then be in charge of handling the lifetime and
435 // (until GC things gets removed from stencil) tracing API of the GC.
436 bool ConvertScriptStencil(JSContext* cx, FrontendContext* fc,
437 const SmooshResult& result,
438 const SmooshScriptStencil& smooshScript,
439 Vector<TaggedParserAtomIndex>& allAtoms,
440 CompilationState& compilationState,
441 ScriptIndex scriptIndex) {
442 using ImmutableFlags = js::ImmutableScriptFlagsEnum;
444 const JS::ReadOnlyCompileOptions& options = compilationState.input.options;
446 ScriptStencil& script = compilationState.scriptData[scriptIndex];
447 ScriptStencilExtra& scriptExtra = compilationState.scriptExtra[scriptIndex];
449 scriptExtra.immutableFlags =
450 ImmutableScriptFlags(smooshScript.immutable_flags);
452 // FIXME: The following flags should be set in jsparagus.
453 scriptExtra.immutableFlags.setFlag(ImmutableFlags::SelfHosted,
454 options.selfHostingMode);
455 scriptExtra.immutableFlags.setFlag(ImmutableFlags::ForceStrict,
456 options.forceStrictMode());
457 scriptExtra.immutableFlags.setFlag(ImmutableFlags::HasNonSyntacticScope,
458 options.nonSyntacticScope);
460 if (&smooshScript == &result.scripts.data[0]) {
461 scriptExtra.immutableFlags.setFlag(ImmutableFlags::TreatAsRunOnce,
462 options.isRunOnce);
463 scriptExtra.immutableFlags.setFlag(ImmutableFlags::NoScriptRval,
464 options.noScriptRval);
467 bool isFunction =
468 scriptExtra.immutableFlags.hasFlag(ImmutableFlags::IsFunction);
470 if (smooshScript.immutable_script_data.IsSome()) {
471 auto index = smooshScript.immutable_script_data.AsSome();
472 auto immutableScriptData = ConvertImmutableScriptData(
473 cx, result.script_data_list.data[index], isFunction);
474 if (!immutableScriptData) {
475 return false;
478 auto sharedData = SharedImmutableScriptData::createWith(
479 fc, std::move(immutableScriptData));
480 if (!sharedData) {
481 return false;
484 if (!compilationState.sharedData.addAndShare(fc, scriptIndex, sharedData)) {
485 return false;
488 script.setHasSharedData();
491 scriptExtra.extent.sourceStart = smooshScript.extent.source_start;
492 scriptExtra.extent.sourceEnd = smooshScript.extent.source_end;
493 scriptExtra.extent.toStringStart = smooshScript.extent.to_string_start;
494 scriptExtra.extent.toStringEnd = smooshScript.extent.to_string_end;
495 scriptExtra.extent.lineno = smooshScript.extent.lineno;
496 scriptExtra.extent.column =
497 JS::LimitedColumnNumberOneOrigin(1 + smooshScript.extent.column);
499 if (isFunction) {
500 if (smooshScript.fun_name.IsSome()) {
501 script.functionAtom = allAtoms[smooshScript.fun_name.AsSome()];
503 script.functionFlags = FunctionFlags(smooshScript.fun_flags);
504 scriptExtra.nargs = smooshScript.fun_nargs;
505 if (smooshScript.lazy_function_enclosing_scope_index.IsSome()) {
506 script.setLazyFunctionEnclosingScopeIndex(ScopeIndex(
507 smooshScript.lazy_function_enclosing_scope_index.AsSome()));
509 if (smooshScript.was_function_emitted) {
510 script.setWasEmittedByEnclosingScript();
514 if (!ConvertGCThings(cx, fc, result, smooshScript, compilationState, allAtoms,
515 scriptIndex)) {
516 return false;
519 return true;
522 // Free given SmooshResult on leaving scope.
523 class AutoFreeSmooshResult {
524 SmooshResult* result_;
526 public:
527 AutoFreeSmooshResult() = delete;
529 explicit AutoFreeSmooshResult(SmooshResult* result) : result_(result) {}
530 ~AutoFreeSmooshResult() {
531 if (result_) {
532 smoosh_free(*result_);
537 // Free given SmooshParseResult on leaving scope.
538 class AutoFreeSmooshParseResult {
539 SmooshParseResult* result_;
541 public:
542 AutoFreeSmooshParseResult() = delete;
544 explicit AutoFreeSmooshParseResult(SmooshParseResult* result)
545 : result_(result) {}
546 ~AutoFreeSmooshParseResult() {
547 if (result_) {
548 smoosh_free_parse_result(*result_);
553 void InitSmoosh() { smoosh_init(); }
555 void ReportSmooshCompileError(JSContext* cx, FrontendContext* fc,
556 ErrorMetadata&& metadata, int errorNumber, ...) {
557 va_list args;
558 va_start(args, errorNumber);
559 ReportCompileErrorUTF8(fc, std::move(metadata), /* notes = */ nullptr,
560 errorNumber, &args);
561 va_end(args);
564 /* static */
565 bool Smoosh::tryCompileGlobalScriptToExtensibleStencil(
566 JSContext* cx, FrontendContext* fc, CompilationInput& input,
567 JS::SourceText<mozilla::Utf8Unit>& srcBuf,
568 UniquePtr<ExtensibleCompilationStencil>& stencilOut) {
569 // FIXME: check info members and return with *unimplemented = true
570 // if any field doesn't match to smoosh_run.
572 auto bytes = reinterpret_cast<const uint8_t*>(srcBuf.get());
573 size_t length = srcBuf.length();
575 SmooshCompileOptions compileOptions;
576 compileOptions.no_script_rval = input.options.noScriptRval;
578 SmooshResult result = smoosh_run(bytes, length, &compileOptions);
579 AutoFreeSmooshResult afsr(&result);
581 if (result.error.data) {
582 ErrorMetadata metadata;
583 metadata.filename = JS::ConstUTF8CharsZ("<unknown>");
584 metadata.lineNumber = 1;
585 metadata.columnNumber = JS::ColumnNumberOneOrigin();
586 metadata.isMuted = false;
587 ReportSmooshCompileError(cx, fc, std::move(metadata),
588 JSMSG_SMOOSH_COMPILE_ERROR,
589 reinterpret_cast<const char*>(result.error.data));
590 return false;
593 if (result.unimplemented) {
594 MOZ_ASSERT(!stencilOut);
595 return true;
598 if (!input.initForGlobal(fc)) {
599 return false;
602 LifoAllocScope parserAllocScope(&cx->tempLifoAlloc());
604 Vector<TaggedParserAtomIndex> allAtoms(fc);
605 CompilationState compilationState(fc, parserAllocScope, input);
606 if (!ConvertAtoms(cx, fc, result, compilationState, allAtoms)) {
607 return false;
610 if (!ConvertScopeStencil(cx, fc, result, allAtoms, compilationState)) {
611 return false;
614 if (!ConvertRegExpData(cx, fc, result, compilationState)) {
615 return false;
618 auto len = result.scripts.len;
619 if (len == 0) {
620 // FIXME: What does it mean to have no scripts?
621 MOZ_ASSERT(!stencilOut);
622 return true;
625 if (len > TaggedScriptThingIndex::IndexLimit) {
626 ReportAllocationOverflow(fc);
627 return false;
630 if (!compilationState.scriptData.resize(len)) {
631 js::ReportOutOfMemory(fc);
632 return false;
635 if (!compilationState.scriptExtra.resize(len)) {
636 js::ReportOutOfMemory(fc);
637 return false;
640 // NOTE: Currently we don't support delazification or standalone function.
641 // Once we support, fix the following loop to include 0-th item
642 // and check if it's function.
643 MOZ_ASSERT_IF(result.scripts.len > 0, result.scripts.data[0].fun_flags == 0);
644 for (size_t i = 1; i < result.scripts.len; i++) {
645 auto& script = result.scripts.data[i];
646 if (script.immutable_script_data.IsSome()) {
647 compilationState.nonLazyFunctionCount++;
651 if (!compilationState.prepareSharedDataStorage(fc)) {
652 return false;
655 for (size_t i = 0; i < len; i++) {
656 if (!ConvertScriptStencil(cx, fc, result, result.scripts.data[i], allAtoms,
657 compilationState, ScriptIndex(i))) {
658 return false;
662 auto stencil =
663 fc->getAllocator()->make_unique<frontend::ExtensibleCompilationStencil>(
664 std::move(compilationState));
665 if (!stencil) {
666 return false;
669 stencilOut = std::move(stencil);
670 return true;
673 bool SmooshParseScript(JSContext* cx, const uint8_t* bytes, size_t length) {
674 SmooshParseResult result = smoosh_test_parse_script(bytes, length);
675 AutoFreeSmooshParseResult afspr(&result);
676 if (result.error.data) {
677 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
678 result.unimplemented ? JSMSG_SMOOSH_UNIMPLEMENTED
679 : JSMSG_SMOOSH_COMPILE_ERROR,
680 reinterpret_cast<const char*>(result.error.data));
681 return false;
684 return true;
687 bool SmooshParseModule(JSContext* cx, const uint8_t* bytes, size_t length) {
688 SmooshParseResult result = smoosh_test_parse_module(bytes, length);
689 AutoFreeSmooshParseResult afspr(&result);
690 if (result.error.data) {
691 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
692 result.unimplemented ? JSMSG_SMOOSH_UNIMPLEMENTED
693 : JSMSG_SMOOSH_COMPILE_ERROR,
694 reinterpret_cast<const char*>(result.error.data));
695 return false;
698 return true;
701 } // namespace frontend
703 } // namespace js