/* -*- 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 js_experimental_JSStencil_h #define js_experimental_JSStencil_h /* The `JS::Stencil` type holds the output of the JS Parser before it is * allocated on the GC heap as a `JSScript`. This form may be serialized as * part of building a bytecode cache. This `Stencil` is not associated with any * particular Realm and may be generated off-main-thread, making it useful for * building script loaders. */ #include "mozilla/MemoryReporting.h" // mozilla::MallocSizeOf #include "mozilla/RefPtr.h" // RefPtr, already_AddRefed #include "mozilla/Utf8.h" // mozilla::Utf8Unit #include "mozilla/Vector.h" // mozilla::Vector #include // size_t #include "jstypes.h" // JS_PUBLIC_API #include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions, JS::InstantiateOptions, JS::DecodeOptions #include "js/OffThreadScriptCompilation.h" // JS::OffThreadCompileCallback #include "js/SourceText.h" // JS::SourceText #include "js/Transcoding.h" // JS::TranscodeSources, JS::TranscodeBuffer, JS::TranscodeRange struct JS_PUBLIC_API JSContext; class JS_PUBLIC_API JSTracer; // Underlying opaque type. namespace js { struct ParseTask; class FrontendContext; namespace frontend { struct CompilationStencil; struct CompilationGCOutput; struct CompilationInput; } // namespace frontend } // namespace js // ************************************************************************ // Types // ************************************************************************ namespace JS { struct CompilationStorage; using Stencil = js::frontend::CompilationStencil; using FrontendContext = js::FrontendContext; // Temporary storage used during instantiating Stencil. // // Off-thread APIs can allocate this instance off main thread, and pass it back // to the main thread, in order to reduce the main thread allocation. struct InstantiationStorage { private: // Owned CompilationGCOutput. // // This uses raw pointer instead of UniquePtr because CompilationGCOutput // is opaque. js::frontend::CompilationGCOutput* gcOutput_ = nullptr; friend JS_PUBLIC_API JSScript* InstantiateGlobalStencil( JSContext* cx, const InstantiateOptions& options, Stencil* stencil, InstantiationStorage* storage); friend JS_PUBLIC_API JSObject* InstantiateModuleStencil( JSContext* cx, const InstantiateOptions& options, Stencil* stencil, InstantiationStorage* storage); friend JS_PUBLIC_API bool PrepareForInstantiate( JS::FrontendContext* fc, JS::CompilationStorage& compileStorage, JS::Stencil& stencil, JS::InstantiationStorage& storage); friend struct js::ParseTask; public: InstantiationStorage() = default; InstantiationStorage(InstantiationStorage&& other) : gcOutput_(other.gcOutput_) { other.gcOutput_ = nullptr; } ~InstantiationStorage(); private: InstantiationStorage(const InstantiationStorage& other) = delete; void operator=(const InstantiationStorage& aOther) = delete; public: bool isValid() const { return !!gcOutput_; } void trace(JSTracer* trc); }; } // namespace JS // ************************************************************************ // Reference Count // ************************************************************************ namespace JS { // These non-member functions let us manipulate the ref counts of the opaque // Stencil type. The RefPtrTraits below calls these for use when using the // RefPtr type. JS_PUBLIC_API void StencilAddRef(Stencil* stencil); JS_PUBLIC_API void StencilRelease(Stencil* stencil); } // namespace JS namespace mozilla { template <> struct RefPtrTraits { static void AddRef(JS::Stencil* stencil) { JS::StencilAddRef(stencil); } static void Release(JS::Stencil* stencil) { JS::StencilRelease(stencil); } }; } // namespace mozilla // ************************************************************************ // Properties // ************************************************************************ namespace JS { // Return true if the stencil relies on external data as a result of XDR // decoding. extern JS_PUBLIC_API bool StencilIsBorrowed(Stencil* stencil); extern JS_PUBLIC_API size_t SizeOfStencil(Stencil* stencil, mozilla::MallocSizeOf mallocSizeOf); } // namespace JS // ************************************************************************ // Compilation // ************************************************************************ namespace JS { // Compile the source text into a JS::Stencil using the provided options. The // resulting stencil may be instantiated into any Realm on the current runtime // and may be used multiple times. // // NOTE: On error, a null will be returned and an exception will be set on the // JSContext. extern JS_PUBLIC_API already_AddRefed CompileGlobalScriptToStencil( JSContext* cx, const ReadOnlyCompileOptions& options, SourceText& srcBuf); extern JS_PUBLIC_API already_AddRefed CompileGlobalScriptToStencil( JSContext* cx, const ReadOnlyCompileOptions& options, SourceText& srcBuf); // Compile the source text into a JS::Stencil using "module" parse goal. The // ECMAScript spec defines special semantics so we use a seperate entry point // here for clarity. The result is still a JS::Stencil, but should use the // appropriate instantiate API below. extern JS_PUBLIC_API already_AddRefed CompileModuleScriptToStencil( JSContext* cx, const ReadOnlyCompileOptions& options, SourceText& srcBuf); extern JS_PUBLIC_API already_AddRefed CompileModuleScriptToStencil( JSContext* cx, const ReadOnlyCompileOptions& options, SourceText& srcBuf); } // namespace JS // ************************************************************************ // Instantiation // ************************************************************************ namespace JS { // Instantiate the Stencil into current Realm and return the JSScript. extern JS_PUBLIC_API JSScript* InstantiateGlobalStencil( JSContext* cx, const InstantiateOptions& options, Stencil* stencil, InstantiationStorage* storage = nullptr); // Instantiate a module Stencil and return the associated object. Inside the // engine this is a js::ModuleObject. extern JS_PUBLIC_API JSObject* InstantiateModuleStencil( JSContext* cx, const InstantiateOptions& options, Stencil* stencil, InstantiationStorage* storage = nullptr); } // namespace JS // ************************************************************************ // Transcoding // ************************************************************************ namespace JS { class OffThreadToken; // Serialize the Stencil into the transcode buffer. extern JS_PUBLIC_API TranscodeResult EncodeStencil(JSContext* cx, Stencil* stencil, TranscodeBuffer& buffer); // Deserialize data and create a new Stencil. extern JS_PUBLIC_API TranscodeResult DecodeStencil(JSContext* cx, const DecodeOptions& options, const TranscodeRange& range, Stencil** stencilOut); extern JS_PUBLIC_API TranscodeResult DecodeStencil(JS::FrontendContext* fc, const DecodeOptions& options, const TranscodeRange& range, Stencil** stencilOut); // Register an encoder on its script source, such that all functions can be // encoded as they are delazified. extern JS_PUBLIC_API bool StartIncrementalEncoding(JSContext* cx, RefPtr&& stencil); } // namespace JS // ************************************************************************ // Off-thread compilation/transcoding // ************************************************************************ namespace JS { // Start an off-thread task to compile the source text into a JS::Stencil, // using the provided options. extern JS_PUBLIC_API OffThreadToken* CompileToStencilOffThread( JSContext* cx, const ReadOnlyCompileOptions& options, SourceText& srcBuf, OffThreadCompileCallback callback, void* callbackData); extern JS_PUBLIC_API OffThreadToken* CompileToStencilOffThread( JSContext* cx, const ReadOnlyCompileOptions& options, SourceText& srcBuf, OffThreadCompileCallback callback, void* callbackData); // Start an off-thread task to compile the module source text into a // JS::Stencil, using the provided options. extern JS_PUBLIC_API OffThreadToken* CompileModuleToStencilOffThread( JSContext* cx, const ReadOnlyCompileOptions& options, SourceText& srcBuf, OffThreadCompileCallback callback, void* callbackData); extern JS_PUBLIC_API OffThreadToken* CompileModuleToStencilOffThread( JSContext* cx, const ReadOnlyCompileOptions& options, SourceText& srcBuf, OffThreadCompileCallback callback, void* callbackData); // Start an off-thread task to decode stencil. // // The start of `buffer` and `cursor` should meet // IsTranscodingBytecodeAligned and IsTranscodingBytecodeOffsetAligned. // (This should be handled while encoding). // // `buffer` should be alive until the end of `FinishDecodeStencilOffThread`. extern JS_PUBLIC_API OffThreadToken* DecodeStencilOffThread( JSContext* cx, const DecodeOptions& options, const TranscodeBuffer& buffer, size_t cursor, OffThreadCompileCallback callback, void* callbackData); // The start of `range` should meet IsTranscodingBytecodeAligned and // AlignTranscodingBytecodeOffset. // (This should be handled while encoding). // // `range` should be alive until the end of `FinishDecodeStencilOffThread`. extern JS_PUBLIC_API OffThreadToken* DecodeStencilOffThread( JSContext* cx, const DecodeOptions& options, const TranscodeRange& range, OffThreadCompileCallback callback, void* callbackData); // Start an off-thread task to decode multiple stencils. // // The start of `TranscodeSource.range` in `sources` should meet // IsTranscodingBytecodeAligned and AlignTranscodingBytecodeOffset // // `sources` should be alive until the end of // `FinishDecodeMultiStencilsOffThread`. extern JS_PUBLIC_API OffThreadToken* DecodeMultiStencilsOffThread( JSContext* cx, const DecodeOptions& options, TranscodeSources& sources, OffThreadCompileCallback callback, void* callbackData); // Finish the off-thread task to compile the source text into a JS::Stencil, // started by JS::CompileToStencilOffThread, and return the result JS::Stencil. // // If `options.allocateInstantiationStorage` was true in // JS::CompileToStencilOffThread, pre-allocated JS::InstantiationStorage // is returned as `storage` out parameter. extern JS_PUBLIC_API already_AddRefed FinishOffThreadStencil( JSContext* cx, OffThreadToken* token, InstantiationStorage* storage = nullptr); extern JS_PUBLIC_API bool FinishDecodeMultiStencilsOffThread( JSContext* cx, OffThreadToken* token, mozilla::Vector>* stencils); // Cancel the off-thread task to compile/decode. extern JS_PUBLIC_API void CancelOffThreadToken(JSContext* cx, OffThreadToken* token); } // namespace JS #endif // js_experimental_JSStencil_h