1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 * Structures and functions for transcoding compiled scripts and functions to
11 #ifndef js_Transcoding_h
12 #define js_Transcoding_h
14 #include "mozilla/Range.h" // mozilla::Range
15 #include "mozilla/Vector.h" // mozilla::Vector
17 #include <stddef.h> // size_t
18 #include <stdint.h> // uint8_t, uint32_t
20 #include "js/TypeDecls.h"
24 class ReadOnlyCompileOptions
;
26 using TranscodeBuffer
= mozilla::Vector
<uint8_t>;
27 using TranscodeRange
= mozilla::Range
<const uint8_t>;
29 struct TranscodeSource final
{
30 TranscodeSource(const TranscodeRange
& range_
, const char* file
, uint32_t line
)
31 : range(range_
), filename(file
), lineno(line
) {}
33 const TranscodeRange range
;
35 const uint32_t lineno
;
38 using TranscodeSources
= mozilla::Vector
<TranscodeSource
>;
40 enum class TranscodeResult
: uint8_t {
41 // Successful encoding / decoding.
44 // A warning message, is set to the message out-param.
46 Failure_BadBuildId
= Failure
| 0x1,
47 Failure_RunOnceNotSupported
= Failure
| 0x2,
48 Failure_AsmJSNotSupported
= Failure
| 0x3,
49 Failure_BadDecode
= Failure
| 0x4,
50 Failure_WrongCompileOption
= Failure
| 0x5,
51 Failure_NotInterpretedFun
= Failure
| 0x6,
53 // There is a pending exception on the context.
57 inline bool IsTranscodeFailureResult(const TranscodeResult result
) {
58 uint8_t raw_result
= static_cast<uint8_t>(result
);
59 uint8_t raw_failure
= static_cast<uint8_t>(TranscodeResult::Failure
);
60 TranscodeResult masked
=
61 static_cast<TranscodeResult
>(raw_result
& raw_failure
);
62 return masked
== TranscodeResult::Failure
;
65 static constexpr size_t BytecodeOffsetAlignment
= 4;
66 static_assert(BytecodeOffsetAlignment
<= alignof(std::max_align_t
),
67 "Alignment condition requires a custom allocator.");
69 // Align the bytecode offset for transcoding for the requirement.
70 inline size_t AlignTranscodingBytecodeOffset(size_t offset
) {
71 size_t extra
= offset
% BytecodeOffsetAlignment
;
75 size_t padding
= BytecodeOffsetAlignment
- extra
;
76 return offset
+ padding
;
79 inline bool IsTranscodingBytecodeOffsetAligned(size_t offset
) {
80 return offset
% BytecodeOffsetAlignment
== 0;
83 inline bool IsTranscodingBytecodeAligned(const void* offset
) {
84 return IsTranscodingBytecodeOffsetAligned(size_t(offset
));
87 // Decode CompilationStencil from the buffer and instantiate JSScript from it.
89 // The start of `buffer` and `cursorIndex` should meet
90 // IsTranscodingBytecodeAligned and IsTranscodingBytecodeOffsetAligned.
91 // (This should be handled while encoding).
92 extern JS_PUBLIC_API TranscodeResult
DecodeScriptMaybeStencil(
93 JSContext
* cx
, const ReadOnlyCompileOptions
& options
,
94 TranscodeBuffer
& buffer
, MutableHandle
<JSScript
*> scriptp
,
95 size_t cursorIndex
= 0);
97 // Decode CompilationStencil from the buffer and instantiate JSScript from it.
99 // And then register an encoder on its script source, such that all functions
100 // can be encoded as they are parsed. This strategy is used to avoid blocking
101 // the main thread in a non-interruptible way.
103 // See also JS::FinishIncrementalEncoding.
105 // The start of `buffer` and `cursorIndex` should meet
106 // IsTranscodingBytecodeAligned and IsTranscodingBytecodeOffsetAligned.
107 // (This should be handled while encoding).
108 extern JS_PUBLIC_API TranscodeResult
DecodeScriptAndStartIncrementalEncoding(
109 JSContext
* cx
, const ReadOnlyCompileOptions
& options
,
110 TranscodeBuffer
& buffer
, MutableHandle
<JSScript
*> scriptp
,
111 size_t cursorIndex
= 0);
113 // Finish incremental encoding started by one of:
114 // * JS::CompileAndStartIncrementalEncoding
115 // * JS::FinishOffThreadScriptAndStartIncrementalEncoding
116 // * JS::DecodeScriptAndStartIncrementalEncoding
118 // The |script| argument of |FinishIncrementalEncoding| should be the top-level
119 // script returned from one of the above.
121 // The |buffer| argument of |FinishIncrementalEncoding| is used for appending
122 // the encoded bytecode into the buffer. If any of these functions failed, the
123 // content of |buffer| would be undefined.
125 // |buffer| contains encoded CompilationStencil.
127 // If the `buffer` isn't empty, the start of the `buffer` should meet
128 // IsTranscodingBytecodeAligned, and the length should meet
129 // IsTranscodingBytecodeOffsetAligned.
131 // NOTE: As long as IsTranscodingBytecodeOffsetAligned is met, that means
132 // there's JS::BytecodeOffsetAlignment+extra bytes in the buffer,
133 // IsTranscodingBytecodeAligned should be guaranteed to meet by
134 // malloc, used by MallocAllocPolicy in mozilla::Vector.
135 extern JS_PUBLIC_API
bool FinishIncrementalEncoding(JSContext
* cx
,
136 Handle
<JSScript
*> script
,
137 TranscodeBuffer
& buffer
);
139 // Check if the compile options and script's flag matches.
141 // JS::DecodeScript* and JS::DecodeOffThreadScript internally check this.
143 // JS::DecodeMultiOffThreadStencils checks some options shared across multiple
144 // scripts. Caller is responsible for checking each script with this API when
145 // using the decoded script instead of compiling a new script wiht the given
147 extern JS_PUBLIC_API
bool CheckCompileOptionsMatch(
148 const ReadOnlyCompileOptions
& options
, JSScript
* script
);
152 #endif /* js_Transcoding_h */