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/. */
5 
6 /*
7  * Structures and functions for transcoding compiled scripts and functions to
8  * and from memory.
9  */
10 
11 #ifndef js_Transcoding_h
12 #define js_Transcoding_h
13 
14 #include "mozilla/Range.h"   // mozilla::Range
15 #include "mozilla/Vector.h"  // mozilla::Vector
16 
17 #include <stddef.h>  // size_t
18 #include <stdint.h>  // uint8_t, uint32_t
19 
20 #include "js/TypeDecls.h"
21 
22 namespace JS {
23 
24 class ReadOnlyCompileOptions;
25 
26 using TranscodeBuffer = mozilla::Vector<uint8_t>;
27 using TranscodeRange = mozilla::Range<const uint8_t>;
28 
29 struct TranscodeSource final {
TranscodeSourcefinal30   TranscodeSource(const TranscodeRange& range_, const char* file, uint32_t line)
31       : range(range_), filename(file), lineno(line) {}
32 
33   const TranscodeRange range;
34   const char* filename;
35   const uint32_t lineno;
36 };
37 
38 using TranscodeSources = mozilla::Vector<TranscodeSource>;
39 
40 enum class TranscodeResult : uint8_t {
41   // Successful encoding / decoding.
42   Ok = 0,
43 
44   // A warning message, is set to the message out-param.
45   Failure = 0x10,
46   Failure_BadBuildId = Failure | 0x1,
47   Failure_AsmJSNotSupported = Failure | 0x2,
48   Failure_BadDecode = Failure | 0x3,
49 
50   // There is a pending exception on the context.
51   Throw = 0x20
52 };
53 
IsTranscodeFailureResult(const TranscodeResult result)54 inline bool IsTranscodeFailureResult(const TranscodeResult result) {
55   uint8_t raw_result = static_cast<uint8_t>(result);
56   uint8_t raw_failure = static_cast<uint8_t>(TranscodeResult::Failure);
57   TranscodeResult masked =
58       static_cast<TranscodeResult>(raw_result & raw_failure);
59   return masked == TranscodeResult::Failure;
60 }
61 
62 static constexpr size_t BytecodeOffsetAlignment = 4;
63 static_assert(BytecodeOffsetAlignment <= alignof(std::max_align_t),
64               "Alignment condition requires a custom allocator.");
65 
66 // Align the bytecode offset for transcoding for the requirement.
AlignTranscodingBytecodeOffset(size_t offset)67 inline size_t AlignTranscodingBytecodeOffset(size_t offset) {
68   size_t extra = offset % BytecodeOffsetAlignment;
69   if (extra == 0) {
70     return offset;
71   }
72   size_t padding = BytecodeOffsetAlignment - extra;
73   return offset + padding;
74 }
75 
IsTranscodingBytecodeOffsetAligned(size_t offset)76 inline bool IsTranscodingBytecodeOffsetAligned(size_t offset) {
77   return offset % BytecodeOffsetAlignment == 0;
78 }
79 
IsTranscodingBytecodeAligned(const void * offset)80 inline bool IsTranscodingBytecodeAligned(const void* offset) {
81   return IsTranscodingBytecodeOffsetAligned(size_t(offset));
82 }
83 
84 // Finish incremental encoding started by one of:
85 //   * JS::CompileAndStartIncrementalEncoding
86 //   * JS::FinishOffThreadScriptAndStartIncrementalEncoding
87 //
88 // The |script| argument of |FinishIncrementalEncoding| should be the top-level
89 // script returned from one of the above.
90 //
91 // The |buffer| argument of |FinishIncrementalEncoding| is used for appending
92 // the encoded bytecode into the buffer. If any of these functions failed, the
93 // content of |buffer| would be undefined.
94 //
95 // |buffer| contains encoded CompilationStencil.
96 //
97 // If the `buffer` isn't empty, the start of the `buffer` should meet
98 // IsTranscodingBytecodeAligned, and the length should meet
99 // IsTranscodingBytecodeOffsetAligned.
100 //
101 // NOTE: As long as IsTranscodingBytecodeOffsetAligned is met, that means
102 //       there's JS::BytecodeOffsetAlignment+extra bytes in the buffer,
103 //       IsTranscodingBytecodeAligned should be guaranteed to meet by
104 //       malloc, used by MallocAllocPolicy in mozilla::Vector.
105 extern JS_PUBLIC_API bool FinishIncrementalEncoding(JSContext* cx,
106                                                     Handle<JSScript*> script,
107                                                     TranscodeBuffer& buffer);
108 
109 // Check if the compile options and script's flag matches.
110 //
111 // JS::DecodeScript* and JS::DecodeOffThreadScript internally check this.
112 //
113 // JS::DecodeMultiStencilsOffThread checks some options shared across multiple
114 // scripts. Caller is responsible for checking each script with this API when
115 // using the decoded script instead of compiling a new script wiht the given
116 // options.
117 extern JS_PUBLIC_API bool CheckCompileOptionsMatch(
118     const ReadOnlyCompileOptions& options, JSScript* script);
119 
120 }  // namespace JS
121 
122 #endif /* js_Transcoding_h */
123