Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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/. */
#ifndef frontend_StencilXdr_h
#define frontend_StencilXdr_h
#include "mozilla/RefPtr.h" // RefPtr
#include "frontend/ParserAtom.h" // ParserAtom, ParserAtomSpan
#include "frontend/Stencil.h" // BitIntStencil, ScopeStencil, BaseParserScopeData
#include "js/CompileOptions.h" // JS::ReadOnlyDecodeOptions, JS::ReadOnlyDecodeOptions
#include "js/Transcoding.h" // JS::TranscodeBuffer, JS::TranscodeRange, JS::TranscodeResult
#include "vm/Xdr.h" // XDRMode, XDRResult, XDRState
namespace JS {
class ReadOnlyDecodeOptions;
} // namespace JS
namespace js {
class LifoAlloc;
class ObjLiteralStencil;
class ScriptSource;
class SharedImmutableScriptData;
class XDRStencilDecoder;
class XDRStencilEncoder;
namespace frontend {
struct CompilationStencil;
struct ExtensibleCompilationStencil;
struct SharedDataContainer;
// Check that we can copy data to disk and restore it in another instance of
// the program in a different address space.
template <typename DataT>
struct CanCopyDataToDisk {
// Check that the object is fully packed, to save disk space.
#ifdef __cpp_lib_has_unique_object_representations
static constexpr bool unique_repr =
std::has_unique_object_representations<DataT>();
#else
static constexpr bool unique_repr = true;
#endif
// Approximation which assumes that 32bits variant of the class would not
// have pointers if the 64bits variant does not have pointer.
static constexpr bool no_pointer =
alignof(DataT) < alignof(void*) || sizeof(void*) == sizeof(uint32_t);
static constexpr bool value = unique_repr && no_pointer;
};
// This is just a namespace class that can be used in friend declarations,
// so that the statically declared XDR methods within have access to the
// relevant struct internals.
class StencilXDR {
private:
template <XDRMode mode>
[[nodiscard]] static XDRResult codeSourceUnretrievableUncompressed(
XDRState<mode>* xdr, ScriptSource* ss, uint8_t sourceCharSize,
uint32_t uncompressedLength);
template <typename Unit,
template <typename U, SourceRetrievable CanRetrieve> class Data,
XDRMode mode>
static void codeSourceRetrievable(ScriptSource* ss);
template <typename Unit, XDRMode mode>
[[nodiscard]] static XDRResult codeSourceUncompressedData(
XDRState<mode>* const xdr, ScriptSource* const ss);
template <typename Unit, XDRMode mode>
[[nodiscard]] static XDRResult codeSourceCompressedData(
XDRState<mode>* const xdr, ScriptSource* const ss);
template <typename Unit, XDRMode mode>
static void codeSourceRetrievableData(ScriptSource* ss);
template <XDRMode mode>
[[nodiscard]] static XDRResult codeSourceData(XDRState<mode>* const xdr,
ScriptSource* const ss);
public:
template <XDRMode mode>
static XDRResult codeSource(XDRState<mode>* xdr,
const JS::ReadOnlyDecodeOptions* maybeOptions,
RefPtr<ScriptSource>& source);
template <XDRMode mode>
static XDRResult codeBigInt(XDRState<mode>* xdr, LifoAlloc& alloc,
BigIntStencil& stencil);
template <XDRMode mode>
static XDRResult codeObjLiteral(XDRState<mode>* xdr, LifoAlloc& alloc,
ObjLiteralStencil& stencil);
template <XDRMode mode>
static XDRResult codeScopeData(XDRState<mode>* xdr, LifoAlloc& alloc,
ScopeStencil& stencil,
BaseParserScopeData*& baseScopeData);
template <XDRMode mode>
static XDRResult codeSharedData(XDRState<mode>* xdr,
RefPtr<SharedImmutableScriptData>& sisd);
template <XDRMode mode>
static XDRResult codeSharedDataContainer(XDRState<mode>* xdr,
SharedDataContainer& sharedData);
template <XDRMode mode>
static XDRResult codeParserAtom(XDRState<mode>* xdr, LifoAlloc& alloc,
ParserAtom** atomp);
template <XDRMode mode>
static XDRResult codeParserAtomSpan(XDRState<mode>* xdr, LifoAlloc& alloc,
ParserAtomSpan& parserAtomData);
template <XDRMode mode>
static XDRResult codeModuleRequest(XDRState<mode>* xdr,
StencilModuleRequest& stencil);
template <XDRMode mode>
static XDRResult codeModuleRequestVector(
XDRState<mode>* xdr, StencilModuleMetadata::RequestVector& vector);
template <XDRMode mode>
static XDRResult codeModuleEntry(XDRState<mode>* xdr,
StencilModuleEntry& stencil);
template <XDRMode mode>
static XDRResult codeModuleEntryVector(
XDRState<mode>* xdr, StencilModuleMetadata::EntryVector& vector);
template <XDRMode mode>
static XDRResult codeModuleMetadata(XDRState<mode>* xdr,
StencilModuleMetadata& stencil);
static XDRResult checkCompilationStencil(XDRStencilEncoder* encoder,
const CompilationStencil& stencil);
static XDRResult checkCompilationStencil(
const ExtensibleCompilationStencil& stencil);
template <XDRMode mode>
static XDRResult codeCompilationStencil(XDRState<mode>* xdr,
CompilationStencil& stencil);
};
} /* namespace frontend */
/*
* The structure of the Stencil XDR buffer is:
*
* 1. Version
* 2. length of content
* 3. checksum of content
* 4. content
* a. ScriptSource
* b. CompilationStencil
*/
/*
* The stencil decoder accepts `range` as input.
*
* The decoded stencils are outputted to the default-initialized
* `stencil` parameter of `codeStencil` method.
*
* The decoded stencils borrow the input `buffer`/`range`, and the consumer
* has to keep the buffer alive while the decoded stencils are alive.
*/
class XDRStencilDecoder : public XDRState<XDR_DECODE> {
using Base = XDRState<XDR_DECODE>;
public:
XDRStencilDecoder(FrontendContext* fc, const JS::TranscodeRange& range)
: Base(fc, range) {
MOZ_ASSERT(JS::IsTranscodingBytecodeAligned(range.begin().get()));
}
XDRResult codeStencil(const JS::ReadOnlyDecodeOptions& options,
frontend::CompilationStencil& stencil);
const JS::ReadOnlyDecodeOptions& options() {
MOZ_ASSERT(options_);
return *options_;
}
private:
const JS::ReadOnlyDecodeOptions* options_ = nullptr;
};
class XDRStencilEncoder : public XDRState<XDR_ENCODE> {
using Base = XDRState<XDR_ENCODE>;
public:
XDRStencilEncoder(FrontendContext* fc, JS::TranscodeBuffer& buffer)
: Base(fc, buffer, buffer.length()) {
// NOTE: If buffer is empty, buffer.begin() doesn't point valid buffer.
MOZ_ASSERT_IF(!buffer.empty(),
JS::IsTranscodingBytecodeAligned(buffer.begin()));
MOZ_ASSERT(JS::IsTranscodingBytecodeOffsetAligned(buffer.length()));
}
XDRResult codeStencil(const RefPtr<ScriptSource>& source,
const frontend::CompilationStencil& stencil);
XDRResult codeStencil(const frontend::CompilationStencil& stencil);
};
JS::TranscodeResult EncodeStencil(JSContext* cx,
frontend::CompilationStencil* stencil,
JS::TranscodeBuffer& buffer);
JS::TranscodeResult DecodeStencil(JS::FrontendContext* fc,
const JS::ReadOnlyDecodeOptions& options,
const JS::TranscodeRange& range,
frontend::CompilationStencil** stencilOut);
} /* namespace js */
#endif /* frontend_StencilXdr_h */