StencilXdr.h (8190B)
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/. */ 6 7 #ifndef frontend_StencilXdr_h 8 #define frontend_StencilXdr_h 9 10 #include "mozilla/RefPtr.h" // RefPtr 11 12 #include "frontend/ParserAtom.h" // ParserAtom, ParserAtomSpan 13 #include "frontend/Stencil.h" // BitIntStencil, ScopeStencil, BaseParserScopeData 14 #include "js/CompileOptions.h" // JS::ReadOnlyDecodeOptions, JS::ReadOnlyDecodeOptions 15 #include "js/Transcoding.h" // JS::TranscodeBuffer, JS::TranscodeRange, JS::TranscodeResult 16 #include "vm/Xdr.h" // XDRMode, XDRResult, XDRState 17 18 namespace JS { 19 20 class ReadOnlyDecodeOptions; 21 22 } // namespace JS 23 24 namespace js { 25 26 class LifoAlloc; 27 class ObjLiteralStencil; 28 class ScriptSource; 29 class SharedImmutableScriptData; 30 31 class XDRStencilDecoder; 32 class XDRStencilEncoder; 33 34 namespace frontend { 35 36 struct CompilationStencil; 37 struct ExtensibleCompilationStencil; 38 struct SharedDataContainer; 39 40 // Check that we can copy data to disk and restore it in another instance of 41 // the program in a different address space. 42 template <typename DataT> 43 struct CanCopyDataToDisk { 44 // Check that the object is fully packed, to save disk space. 45 #ifdef __cpp_lib_has_unique_object_representations 46 static constexpr bool unique_repr = 47 std::has_unique_object_representations<DataT>(); 48 #else 49 static constexpr bool unique_repr = true; 50 #endif 51 52 // Approximation which assumes that 32bits variant of the class would not 53 // have pointers if the 64bits variant does not have pointer. 54 static constexpr bool no_pointer = 55 alignof(DataT) < alignof(void*) || sizeof(void*) == sizeof(uint32_t); 56 57 static constexpr bool value = unique_repr && no_pointer; 58 }; 59 60 // This is just a namespace class that can be used in friend declarations, 61 // so that the statically declared XDR methods within have access to the 62 // relevant struct internals. 63 class StencilXDR { 64 private: 65 template <XDRMode mode> 66 [[nodiscard]] static XDRResult codeSourceUnretrievableUncompressed( 67 XDRState<mode>* xdr, ScriptSource* ss, uint8_t sourceCharSize, 68 uint32_t uncompressedLength); 69 70 template <typename Unit, 71 template <typename U, SourceRetrievable CanRetrieve> class Data, 72 XDRMode mode> 73 static void codeSourceRetrievable(ScriptSource* ss); 74 75 template <typename Unit, XDRMode mode> 76 [[nodiscard]] static XDRResult codeSourceUncompressedData( 77 XDRState<mode>* const xdr, ScriptSource* const ss); 78 79 template <typename Unit, XDRMode mode> 80 [[nodiscard]] static XDRResult codeSourceCompressedData( 81 XDRState<mode>* const xdr, ScriptSource* const ss); 82 83 template <typename Unit, XDRMode mode> 84 static void codeSourceRetrievableData(ScriptSource* ss); 85 86 template <XDRMode mode> 87 [[nodiscard]] static XDRResult codeSourceData(XDRState<mode>* const xdr, 88 ScriptSource* const ss); 89 90 public: 91 template <XDRMode mode> 92 static XDRResult codeSource(XDRState<mode>* xdr, 93 const JS::ReadOnlyDecodeOptions* maybeOptions, 94 RefPtr<ScriptSource>& source); 95 96 template <XDRMode mode> 97 static XDRResult codeBigInt(XDRState<mode>* xdr, LifoAlloc& alloc, 98 BigIntStencil& stencil); 99 100 template <XDRMode mode> 101 static XDRResult codeObjLiteral(XDRState<mode>* xdr, LifoAlloc& alloc, 102 ObjLiteralStencil& stencil); 103 104 template <XDRMode mode> 105 static XDRResult codeScopeData(XDRState<mode>* xdr, LifoAlloc& alloc, 106 ScopeStencil& stencil, 107 BaseParserScopeData*& baseScopeData); 108 109 template <XDRMode mode> 110 static XDRResult codeSharedData(XDRState<mode>* xdr, 111 RefPtr<SharedImmutableScriptData>& sisd); 112 113 template <XDRMode mode> 114 static XDRResult codeSharedDataContainer(XDRState<mode>* xdr, 115 SharedDataContainer& sharedData); 116 117 template <XDRMode mode> 118 static XDRResult codeParserAtom(XDRState<mode>* xdr, LifoAlloc& alloc, 119 ParserAtom** atomp); 120 121 template <XDRMode mode> 122 static XDRResult codeParserAtomSpan(XDRState<mode>* xdr, LifoAlloc& alloc, 123 ParserAtomSpan& parserAtomData); 124 125 template <XDRMode mode> 126 static XDRResult codeModuleRequest(XDRState<mode>* xdr, 127 StencilModuleRequest& stencil); 128 129 template <XDRMode mode> 130 static XDRResult codeModuleRequestVector( 131 XDRState<mode>* xdr, StencilModuleMetadata::RequestVector& vector); 132 133 template <XDRMode mode> 134 static XDRResult codeModuleEntry(XDRState<mode>* xdr, 135 StencilModuleEntry& stencil); 136 137 template <XDRMode mode> 138 static XDRResult codeModuleEntryVector( 139 XDRState<mode>* xdr, StencilModuleMetadata::EntryVector& vector); 140 141 template <XDRMode mode> 142 static XDRResult codeModuleMetadata(XDRState<mode>* xdr, 143 StencilModuleMetadata& stencil); 144 145 static XDRResult checkCompilationStencil(XDRStencilEncoder* encoder, 146 const CompilationStencil& stencil); 147 148 static XDRResult checkCompilationStencil( 149 const ExtensibleCompilationStencil& stencil); 150 151 template <XDRMode mode> 152 static XDRResult codeCompilationStencil(XDRState<mode>* xdr, 153 CompilationStencil& stencil); 154 }; 155 156 } /* namespace frontend */ 157 158 /* 159 * The structure of the Stencil XDR buffer is: 160 * 161 * 1. Version 162 * 2. length of content 163 * 3. checksum of content 164 * 4. content 165 * a. ScriptSource 166 * b. CompilationStencil 167 */ 168 169 /* 170 * The stencil decoder accepts `range` as input. 171 * 172 * The decoded stencils are outputted to the default-initialized 173 * `stencil` parameter of `codeStencil` method. 174 * 175 * The decoded stencils borrow the input `buffer`/`range`, and the consumer 176 * has to keep the buffer alive while the decoded stencils are alive. 177 */ 178 class XDRStencilDecoder : public XDRState<XDR_DECODE> { 179 using Base = XDRState<XDR_DECODE>; 180 181 public: 182 XDRStencilDecoder(FrontendContext* fc, const JS::TranscodeRange& range) 183 : Base(fc, range) { 184 MOZ_ASSERT(JS::IsTranscodingBytecodeAligned(range.begin().get())); 185 } 186 187 XDRResult codeStencil(const JS::ReadOnlyDecodeOptions& options, 188 frontend::CompilationStencil& stencil); 189 190 const JS::ReadOnlyDecodeOptions& options() { 191 MOZ_ASSERT(options_); 192 return *options_; 193 } 194 195 private: 196 const JS::ReadOnlyDecodeOptions* options_ = nullptr; 197 }; 198 199 class XDRStencilEncoder : public XDRState<XDR_ENCODE> { 200 using Base = XDRState<XDR_ENCODE>; 201 202 public: 203 XDRStencilEncoder(FrontendContext* fc, JS::TranscodeBuffer& buffer) 204 : Base(fc, buffer, buffer.length()) { 205 // NOTE: If buffer is empty, buffer.begin() doesn't point valid buffer. 206 MOZ_ASSERT_IF(!buffer.empty(), 207 JS::IsTranscodingBytecodeAligned(buffer.begin())); 208 MOZ_ASSERT(JS::IsTranscodingBytecodeOffsetAligned(buffer.length())); 209 } 210 211 XDRResult codeStencil(const RefPtr<ScriptSource>& source, 212 const frontend::CompilationStencil& stencil); 213 214 XDRResult codeStencil(const frontend::CompilationStencil& stencil); 215 }; 216 217 JS::TranscodeResult EncodeStencil(JSContext* cx, 218 frontend::CompilationStencil* stencil, 219 JS::TranscodeBuffer& buffer); 220 221 JS::TranscodeResult EncodeStencil(JS::FrontendContext* fc, 222 frontend::CompilationStencil* stencil, 223 JS::TranscodeBuffer& buffer); 224 225 JS::TranscodeResult DecodeStencil(JS::FrontendContext* fc, 226 const JS::ReadOnlyDecodeOptions& options, 227 const JS::TranscodeRange& range, 228 frontend::CompilationStencil** stencilOut); 229 230 } /* namespace js */ 231 232 #endif /* frontend_StencilXdr_h */