diff options
Diffstat (limited to 'js/src/frontend/Frontend2.cpp')
-rw-r--r-- | js/src/frontend/Frontend2.cpp | 752 |
1 files changed, 752 insertions, 0 deletions
diff --git a/js/src/frontend/Frontend2.cpp b/js/src/frontend/Frontend2.cpp new file mode 100644 index 0000000000..c87efb7086 --- /dev/null +++ b/js/src/frontend/Frontend2.cpp @@ -0,0 +1,752 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "frontend/Frontend2.h" + +#include "mozilla/Maybe.h" // mozilla::Maybe +#include "mozilla/OperatorNewExtensions.h" // mozilla::KnownNotNull +#include "mozilla/Range.h" // mozilla::Range +#include "mozilla/Span.h" // mozilla::{Span, Span} +#include "mozilla/Variant.h" // mozilla::AsVariant + +#include <stddef.h> // size_t +#include <stdint.h> // uint8_t, uint32_t + +#include "jsapi.h" + +#include "frontend/AbstractScopePtr.h" // ScopeIndex +#include "frontend/BytecodeSection.h" // EmitScriptThingsVector +#include "frontend/CompilationInfo.h" // CompilationState, CompilationStencil +#include "frontend/Parser.h" // NewEmptyLexicalScopeData, NewEmptyGlobalScopeData, NewEmptyVarScopeData, NewEmptyFunctionScopeData +#include "frontend/ParserAtom.h" // ParserAtomsTable +#include "frontend/ScriptIndex.h" // ScriptIndex +#include "frontend/smoosh_generated.h" // CVec, Smoosh*, smoosh_* +#include "frontend/SourceNotes.h" // SrcNote +#include "frontend/Stencil.h" // ScopeStencil, RegExpIndex +#include "frontend/TokenStream.h" // TokenStreamAnyChars +#include "irregexp/RegExpAPI.h" // irregexp::CheckPatternSyntax +#include "js/CharacterEncoding.h" // JS::UTF8Chars, UTF8CharsToNewTwoByteCharsZ +#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* +#include "js/GCAPI.h" // JS::AutoCheckCannotGC +#include "js/HeapAPI.h" // JS::GCCellPtr +#include "js/RegExpFlags.h" // JS::RegExpFlag, JS::RegExpFlags +#include "js/RootingAPI.h" // JS::MutableHandle +#include "js/UniquePtr.h" // js::UniquePtr +#include "js/Utility.h" // JS::UniqueTwoByteChars, StringBufferArena +#include "vm/JSScript.h" // JSScript +#include "vm/ScopeKind.h" // ScopeKind +#include "vm/SharedStencil.h" // ImmutableScriptData, ScopeNote, TryNote, GCThingIndex + +using mozilla::Utf8Unit; + +using namespace js::gc; +using namespace js::frontend; +using namespace js; + +namespace js { + +namespace frontend { + +// Given the result of SmooshMonkey's parser, Convert the list of atoms into +// the list of ParserAtoms. +bool ConvertAtoms(JSContext* cx, const SmooshResult& result, + CompilationState& compilationState, + Vector<const ParserAtom*>& allAtoms) { + size_t numAtoms = result.all_atoms_len; + + if (!allAtoms.reserve(numAtoms)) { + return false; + } + + for (size_t i = 0; i < numAtoms; i++) { + auto s = reinterpret_cast<const mozilla::Utf8Unit*>( + smoosh_get_atom_at(result, i)); + auto len = smoosh_get_atom_len_at(result, i); + const ParserAtom* atom = + compilationState.parserAtoms.internUtf8(cx, s, len); + if (!atom) { + return false; + } + atom->markUsedByStencil(); + allAtoms.infallibleAppend(atom); + } + + return true; +} + +void CopyBindingNames(JSContext* cx, CVec<SmooshBindingName>& from, + Vector<const ParserAtom*>& allAtoms, + ParserBindingName* to) { + // We're setting trailing array's content before setting its length. + JS::AutoCheckCannotGC nogc(cx); + + size_t numBindings = from.len; + for (size_t i = 0; i < numBindings; i++) { + SmooshBindingName& name = from.data[i]; + new (mozilla::KnownNotNull, &to[i]) + ParserBindingName(allAtoms[name.name]->toIndex(), name.is_closed_over, + name.is_top_level_function); + } +} + +void CopyBindingNames(JSContext* cx, CVec<COption<SmooshBindingName>>& from, + Vector<const ParserAtom*>& allAtoms, + ParserBindingName* to) { + // We're setting trailing array's content before setting its length. + JS::AutoCheckCannotGC nogc(cx); + + size_t numBindings = from.len; + for (size_t i = 0; i < numBindings; i++) { + COption<SmooshBindingName>& maybeName = from.data[i]; + if (maybeName.IsSome()) { + SmooshBindingName& name = maybeName.AsSome(); + new (mozilla::KnownNotNull, &to[i]) + ParserBindingName(allAtoms[name.name]->toIndex(), name.is_closed_over, + name.is_top_level_function); + } else { + new (mozilla::KnownNotNull, &to[i]) + ParserBindingName(TaggedParserAtomIndex::null(), false, false); + } + } +} + +// Given the result of SmooshMonkey's parser, convert a list of scope data +// into a list of ScopeStencil. +bool ConvertScopeStencil(JSContext* cx, const SmooshResult& result, + Vector<const ParserAtom*>& allAtoms, + CompilationStencil& stencil, + CompilationState& compilationState) { + LifoAlloc& alloc = stencil.alloc; + + if (result.scopes.len > TaggedScriptThingIndex::IndexLimit) { + ReportAllocationOverflow(cx); + return false; + } + + for (size_t i = 0; i < result.scopes.len; i++) { + SmooshScopeData& scopeData = result.scopes.data[i]; + ScopeIndex index; + + switch (scopeData.tag) { + case SmooshScopeData::Tag::Global: { + auto& global = scopeData.AsGlobal(); + + size_t numBindings = global.bindings.len; + GlobalScope::ParserData* data = + NewEmptyGlobalScopeData(cx, alloc, numBindings); + if (!data) { + return false; + } + + CopyBindingNames(cx, global.bindings, allAtoms, + data->trailingNames.start()); + + data->slotInfo.letStart = global.let_start; + data->slotInfo.constStart = global.const_start; + data->slotInfo.length = numBindings; + + if (!ScopeStencil::createForGlobalScope(cx, stencil, compilationState, + ScopeKind::Global, data, + &index)) { + return false; + } + break; + } + case SmooshScopeData::Tag::Var: { + auto& var = scopeData.AsVar(); + + size_t numBindings = var.bindings.len; + + VarScope::ParserData* data = + NewEmptyVarScopeData(cx, alloc, numBindings); + if (!data) { + return false; + } + + CopyBindingNames(cx, var.bindings, allAtoms, + data->trailingNames.start()); + + // NOTE: data->slotInfo.nextFrameSlot is set in + // ScopeStencil::createForVarScope. + + data->slotInfo.length = numBindings; + + uint32_t firstFrameSlot = var.first_frame_slot; + ScopeIndex enclosingIndex(var.enclosing); + if (!ScopeStencil::createForVarScope( + cx, stencil, compilationState, ScopeKind::FunctionBodyVar, data, + firstFrameSlot, var.function_has_extensible_scope, + mozilla::Some(enclosingIndex), &index)) { + return false; + } + break; + } + case SmooshScopeData::Tag::Lexical: { + auto& lexical = scopeData.AsLexical(); + + size_t numBindings = lexical.bindings.len; + LexicalScope::ParserData* data = + NewEmptyLexicalScopeData(cx, alloc, numBindings); + if (!data) { + return false; + } + + CopyBindingNames(cx, lexical.bindings, allAtoms, + data->trailingNames.start()); + + // NOTE: data->slotInfo.nextFrameSlot is set in + // ScopeStencil::createForLexicalScope. + + data->slotInfo.constStart = lexical.const_start; + data->slotInfo.length = numBindings; + + uint32_t firstFrameSlot = lexical.first_frame_slot; + ScopeIndex enclosingIndex(lexical.enclosing); + if (!ScopeStencil::createForLexicalScope( + cx, stencil, compilationState, ScopeKind::Lexical, data, + firstFrameSlot, mozilla::Some(enclosingIndex), &index)) { + return false; + } + break; + } + case SmooshScopeData::Tag::Function: { + auto& function = scopeData.AsFunction(); + + size_t numBindings = function.bindings.len; + FunctionScope::ParserData* data = + NewEmptyFunctionScopeData(cx, alloc, numBindings); + if (!data) { + return false; + } + + CopyBindingNames(cx, function.bindings, allAtoms, + data->trailingNames.start()); + + // NOTE: data->slotInfo.nextFrameSlot is set in + // ScopeStencil::createForFunctionScope. + + if (function.has_parameter_exprs) { + data->slotInfo.setHasParameterExprs(); + } + data->slotInfo.nonPositionalFormalStart = + function.non_positional_formal_start; + data->slotInfo.varStart = function.var_start; + data->slotInfo.length = numBindings; + + bool hasParameterExprs = function.has_parameter_exprs; + bool needsEnvironment = function.non_positional_formal_start; + ScriptIndex functionIndex = ScriptIndex(function.function_index); + bool isArrow = function.is_arrow; + + ScopeIndex enclosingIndex(function.enclosing); + if (!ScopeStencil::createForFunctionScope( + cx, stencil, compilationState, data, hasParameterExprs, + needsEnvironment, functionIndex, isArrow, + mozilla::Some(enclosingIndex), &index)) { + return false; + } + break; + } + } + + // `ConvertGCThings` depends on this condition. + MOZ_ASSERT(index == i); + } + + return true; +} + +// Given the result of SmooshMonkey's parser, convert a list of RegExp data +// into a list of RegExpStencil. +bool ConvertRegExpData(JSContext* cx, const SmooshResult& result, + CompilationStencil& stencil, + CompilationState& compilationState) { + auto len = result.regexps.len; + if (len == 0) { + return true; + } + + if (len > TaggedScriptThingIndex::IndexLimit) { + ReportAllocationOverflow(cx); + return false; + } + + auto* p = stencil.alloc.newArrayUninitialized<RegExpStencil>(len); + if (!p) { + js::ReportOutOfMemory(cx); + return false; + } + stencil.regExpData = mozilla::Span(p, len); + + for (size_t i = 0; i < len; i++) { + SmooshRegExpItem& item = result.regexps.data[i]; + auto s = smoosh_get_slice_at(result, item.pattern); + auto len = smoosh_get_slice_len_at(result, item.pattern); + + JS::RegExpFlags::Flag flags = JS::RegExpFlag::NoFlags; + if (item.global) { + flags |= JS::RegExpFlag::Global; + } + if (item.ignore_case) { + flags |= JS::RegExpFlag::IgnoreCase; + } + if (item.multi_line) { + flags |= JS::RegExpFlag::Multiline; + } + if (item.dot_all) { + flags |= JS::RegExpFlag::DotAll; + } + if (item.sticky) { + flags |= JS::RegExpFlag::Sticky; + } + if (item.unicode) { + flags |= JS::RegExpFlag::Unicode; + } + + // FIXME: This check should be done at parse time. + size_t length; + JS::UniqueTwoByteChars pattern( + UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(s, len), &length, + StringBufferArena) + .get()); + if (!pattern) { + return false; + } + + mozilla::Range<const char16_t> range(pattern.get(), length); + + TokenStreamAnyChars ts(cx, stencil.input.options, + /* smg = */ nullptr); + + // See Parser<FullParseHandler, Unit>::newRegExp. + + LifoAllocScope allocScope(&cx->tempLifoAlloc()); + if (!irregexp::CheckPatternSyntax(cx, ts, range, flags)) { + return false; + } + + const mozilla::Utf8Unit* sUtf8 = + reinterpret_cast<const mozilla::Utf8Unit*>(s); + const ParserAtom* atom = + compilationState.parserAtoms.internUtf8(cx, sUtf8, len); + if (!atom) { + return false; + } + atom->markUsedByStencil(); + + new (mozilla::KnownNotNull, &stencil.regExpData[i]) + RegExpStencil(atom->toIndex(), JS::RegExpFlags(flags)); + } + + return true; +} + +// Convert SmooshImmutableScriptData into ImmutableScriptData. +UniquePtr<ImmutableScriptData> ConvertImmutableScriptData( + JSContext* cx, const SmooshImmutableScriptData& smooshScriptData, + bool isFunction) { + Vector<ScopeNote, 0, SystemAllocPolicy> scopeNotes; + if (!scopeNotes.resize(smooshScriptData.scope_notes.len)) { + return nullptr; + } + for (size_t i = 0; i < smooshScriptData.scope_notes.len; i++) { + SmooshScopeNote& scopeNote = smooshScriptData.scope_notes.data[i]; + scopeNotes[i].index = GCThingIndex(scopeNote.index); + scopeNotes[i].start = scopeNote.start; + scopeNotes[i].length = scopeNote.length; + scopeNotes[i].parent = scopeNote.parent; + } + + return ImmutableScriptData::new_( + cx, smooshScriptData.main_offset, smooshScriptData.nfixed, + smooshScriptData.nslots, GCThingIndex(smooshScriptData.body_scope_index), + smooshScriptData.num_ic_entries, isFunction, smooshScriptData.fun_length, + mozilla::Span(smooshScriptData.bytecode.data, + smooshScriptData.bytecode.len), + mozilla::Span<const SrcNote>(), mozilla::Span<const uint32_t>(), + scopeNotes, mozilla::Span<const TryNote>()); +} + +// Given the result of SmooshMonkey's parser, convert a list of GC things +// used by a script into ScriptThingsVector. +bool ConvertGCThings(JSContext* cx, const SmooshResult& result, + const SmooshScriptStencil& smooshScript, + CompilationStencil& stencil, + CompilationState& compilationState, + Vector<const ParserAtom*>& allAtoms, + ScriptIndex scriptIndex) { + size_t ngcthings = smooshScript.gcthings.len; + + // If there are no things, avoid the allocation altogether. + if (ngcthings == 0) { + return true; + } + + TaggedScriptThingIndex* cursor = nullptr; + if (!compilationState.allocateGCThingsUninitialized(cx, scriptIndex, + ngcthings, &cursor)) { + return false; + } + + for (size_t i = 0; i < ngcthings; i++) { + SmooshGCThing& item = smooshScript.gcthings.data[i]; + + // Pointer to the uninitialized element. + void* raw = &cursor[i]; + + switch (item.tag) { + case SmooshGCThing::Tag::Null: { + new (raw) TaggedScriptThingIndex(); + break; + } + case SmooshGCThing::Tag::Atom: { + new (raw) TaggedScriptThingIndex(allAtoms[item.AsAtom()]->toIndex()); + break; + } + case SmooshGCThing::Tag::Function: { + new (raw) TaggedScriptThingIndex(ScriptIndex(item.AsFunction())); + break; + } + case SmooshGCThing::Tag::Scope: { + new (raw) TaggedScriptThingIndex(ScopeIndex(item.AsScope())); + break; + } + case SmooshGCThing::Tag::RegExp: { + new (raw) TaggedScriptThingIndex(RegExpIndex(item.AsRegExp())); + break; + } + } + } + + return true; +} + +// Given the result of SmooshMonkey's parser, convert a specific script +// or function to a StencilScript, given a fixed set of source atoms. +// +// The StencilScript would then be in charge of handling the lifetime and +// (until GC things gets removed from stencil) tracing API of the GC. +bool ConvertScriptStencil(JSContext* cx, const SmooshResult& result, + const SmooshScriptStencil& smooshScript, + Vector<const ParserAtom*>& allAtoms, + CompilationStencil& stencil, + CompilationState& compilationState, + ScriptIndex scriptIndex) { + using ImmutableFlags = js::ImmutableScriptFlagsEnum; + + const JS::ReadOnlyCompileOptions& options = stencil.input.options; + + ScriptStencil& script = stencil.scriptData[scriptIndex]; + ScriptStencilExtra& scriptExtra = stencil.scriptExtra[scriptIndex]; + + scriptExtra.immutableFlags = smooshScript.immutable_flags; + + // FIXME: The following flags should be set in jsparagus. + scriptExtra.immutableFlags.setFlag(ImmutableFlags::SelfHosted, + options.selfHostingMode); + scriptExtra.immutableFlags.setFlag(ImmutableFlags::ForceStrict, + options.forceStrictMode()); + scriptExtra.immutableFlags.setFlag(ImmutableFlags::HasNonSyntacticScope, + options.nonSyntacticScope); + + if (&smooshScript == &result.scripts.data[0]) { + scriptExtra.immutableFlags.setFlag(ImmutableFlags::TreatAsRunOnce, + options.isRunOnce); + scriptExtra.immutableFlags.setFlag(ImmutableFlags::NoScriptRval, + options.noScriptRval); + } + + bool isFunction = + scriptExtra.immutableFlags.hasFlag(ImmutableFlags::IsFunction); + + if (smooshScript.immutable_script_data.IsSome()) { + auto index = smooshScript.immutable_script_data.AsSome(); + auto immutableScriptData = ConvertImmutableScriptData( + cx, result.script_data_list.data[index], isFunction); + if (!immutableScriptData) { + return false; + } + + auto sharedData = SharedImmutableScriptData::createWith( + cx, std::move(immutableScriptData)); + if (!sharedData) { + return false; + } + + if (!stencil.sharedData.addAndShare(cx, scriptIndex, sharedData)) { + return false; + } + + script.setHasSharedData(); + } + + scriptExtra.extent.sourceStart = smooshScript.extent.source_start; + scriptExtra.extent.sourceEnd = smooshScript.extent.source_end; + scriptExtra.extent.toStringStart = smooshScript.extent.to_string_start; + scriptExtra.extent.toStringEnd = smooshScript.extent.to_string_end; + scriptExtra.extent.lineno = smooshScript.extent.lineno; + scriptExtra.extent.column = smooshScript.extent.column; + + if (isFunction) { + if (smooshScript.fun_name.IsSome()) { + script.functionAtom = allAtoms[smooshScript.fun_name.AsSome()]->toIndex(); + } + script.functionFlags = FunctionFlags(smooshScript.fun_flags); + scriptExtra.nargs = smooshScript.fun_nargs; + if (smooshScript.lazy_function_enclosing_scope_index.IsSome()) { + script.setLazyFunctionEnclosingScopeIndex(ScopeIndex( + smooshScript.lazy_function_enclosing_scope_index.AsSome())); + } + if (smooshScript.was_function_emitted) { + script.setWasFunctionEmitted(); + } + } + + if (!ConvertGCThings(cx, result, smooshScript, stencil, compilationState, + allAtoms, scriptIndex)) { + return false; + } + + return true; +} + +// Free given SmooshResult on leaving scope. +class AutoFreeSmooshResult { + SmooshResult* result_; + + public: + AutoFreeSmooshResult() = delete; + + explicit AutoFreeSmooshResult(SmooshResult* result) : result_(result) {} + ~AutoFreeSmooshResult() { + if (result_) { + smoosh_free(*result_); + } + } +}; + +// Free given SmooshParseResult on leaving scope. +class AutoFreeSmooshParseResult { + SmooshParseResult* result_; + + public: + AutoFreeSmooshParseResult() = delete; + + explicit AutoFreeSmooshParseResult(SmooshParseResult* result) + : result_(result) {} + ~AutoFreeSmooshParseResult() { + if (result_) { + smoosh_free_parse_result(*result_); + } + } +}; + +void InitSmoosh() { smoosh_init(); } + +void ReportSmooshCompileError(JSContext* cx, ErrorMetadata&& metadata, + int errorNumber, ...) { + va_list args; + va_start(args, errorNumber); + ReportCompileErrorUTF8(cx, std::move(metadata), /* notes = */ nullptr, + errorNumber, &args); + va_end(args); +} + +/* static */ +bool Smoosh::compileGlobalScriptToStencil(JSContext* cx, + CompilationStencil& stencil, + JS::SourceText<Utf8Unit>& srcBuf, + bool* unimplemented) { + // FIXME: check info members and return with *unimplemented = true + // if any field doesn't match to smoosh_run. + + auto bytes = reinterpret_cast<const uint8_t*>(srcBuf.get()); + size_t length = srcBuf.length(); + + const auto& options = stencil.input.options; + SmooshCompileOptions compileOptions; + compileOptions.no_script_rval = options.noScriptRval; + + SmooshResult result = smoosh_run(bytes, length, &compileOptions); + AutoFreeSmooshResult afsr(&result); + + if (result.error.data) { + *unimplemented = false; + ErrorMetadata metadata; + metadata.filename = "<unknown>"; + metadata.lineNumber = 1; + metadata.columnNumber = 0; + metadata.isMuted = false; + ReportSmooshCompileError(cx, std::move(metadata), + JSMSG_SMOOSH_COMPILE_ERROR, + reinterpret_cast<const char*>(result.error.data)); + return false; + } + + if (result.unimplemented) { + *unimplemented = true; + return false; + } + + *unimplemented = false; + + LifoAllocScope allocScope(&cx->tempLifoAlloc()); + + Vector<const ParserAtom*> allAtoms(cx); + CompilationState compilationState(cx, allocScope, stencil.input.options, + stencil); + if (!ConvertAtoms(cx, result, compilationState, allAtoms)) { + return false; + } + + if (!ConvertScopeStencil(cx, result, allAtoms, stencil, compilationState)) { + return false; + } + + if (!ConvertRegExpData(cx, result, stencil, compilationState)) { + return false; + } + + auto len = result.scripts.len; + if (len == 0) { + return true; + } + + if (len > TaggedScriptThingIndex::IndexLimit) { + ReportAllocationOverflow(cx); + return false; + } + + auto* pscript = stencil.alloc.newArrayUninitialized<ScriptStencil>(len); + if (!pscript) { + js::ReportOutOfMemory(cx); + return false; + } + stencil.scriptData = mozilla::Span(pscript, len); + + auto* pextra = stencil.alloc.newArrayUninitialized<ScriptStencilExtra>(len); + if (!pextra) { + js::ReportOutOfMemory(cx); + return false; + } + stencil.scriptExtra = mozilla::Span(pextra, len); + + // NOTE: Currently we don't support delazification or standalone function. + // Once we support, fix the following loop to include 0-th item + // and check if it's function. + MOZ_ASSERT_IF(result.scripts.len > 0, result.scripts.data[0].fun_flags == 0); + for (size_t i = 1; i < result.scripts.len; i++) { + auto& script = result.scripts.data[i]; + if (script.immutable_script_data.IsSome()) { + compilationState.nonLazyFunctionCount++; + } + } + + stencil.prepareStorageFor(cx, compilationState); + + for (size_t i = 0; i < len; i++) { + new (mozilla::KnownNotNull, &stencil.scriptData[i]) + BaseCompilationStencil(); + + if (!ConvertScriptStencil(cx, result, result.scripts.data[i], allAtoms, + stencil, compilationState, ScriptIndex(i))) { + return false; + } + } + + if (!compilationState.finish(cx, stencil)) { + return true; + } + + return true; +} + +/* static */ +UniquePtr<CompilationStencil> Smoosh::compileGlobalScriptToStencil( + JSContext* cx, const JS::ReadOnlyCompileOptions& options, + JS::SourceText<Utf8Unit>& srcBuf, bool* unimplemented) { + Rooted<UniquePtr<frontend::CompilationStencil>> stencil( + cx, js_new<frontend::CompilationStencil>(cx, options)); + if (!stencil) { + ReportOutOfMemory(cx); + return nullptr; + } + + if (!stencil.get()->input.initForGlobal(cx)) { + return nullptr; + } + + if (!compileGlobalScriptToStencil(cx, *stencil.get().get(), srcBuf, + unimplemented)) { + return nullptr; + } + + return std::move(stencil.get()); +} + +/* static */ +bool Smoosh::compileGlobalScript(JSContext* cx, CompilationStencil& stencil, + JS::SourceText<Utf8Unit>& srcBuf, + CompilationGCOutput& gcOutput, + bool* unimplemented) { + if (!compileGlobalScriptToStencil(cx, stencil, srcBuf, unimplemented)) { + return false; + } + + if (!CompilationStencil::instantiateStencils(cx, stencil, gcOutput)) { + return false; + } + +#if defined(DEBUG) || defined(JS_JITSPEW) + Sprinter sprinter(cx); + Rooted<JSScript*> script(cx, gcOutput.script); + if (!sprinter.init()) { + return false; + } + if (!Disassemble(cx, script, true, &sprinter, DisassembleSkeptically::Yes)) { + return false; + } + printf("%s\n", sprinter.string()); + if (!Disassemble(cx, script, true, &sprinter, DisassembleSkeptically::No)) { + return false; + } + // (don't bother printing it) +#endif + + return true; +} + +bool SmooshParseScript(JSContext* cx, const uint8_t* bytes, size_t length) { + SmooshParseResult result = smoosh_test_parse_script(bytes, length); + AutoFreeSmooshParseResult afspr(&result); + if (result.error.data) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, + result.unimplemented ? JSMSG_SMOOSH_UNIMPLEMENTED + : JSMSG_SMOOSH_COMPILE_ERROR, + reinterpret_cast<const char*>(result.error.data)); + return false; + } + + return true; +} + +bool SmooshParseModule(JSContext* cx, const uint8_t* bytes, size_t length) { + SmooshParseResult result = smoosh_test_parse_module(bytes, length); + AutoFreeSmooshParseResult afspr(&result); + if (result.error.data) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, + result.unimplemented ? JSMSG_SMOOSH_UNIMPLEMENTED + : JSMSG_SMOOSH_COMPILE_ERROR, + reinterpret_cast<const char*>(result.error.data)); + return false; + } + + return true; +} + +} // namespace frontend + +} // namespace js |