/src/hermes/include/hermes/BCGen/HBC/BytecodeProviderFromSrc.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) Meta Platforms, Inc. and affiliates. |
3 | | * |
4 | | * This source code is licensed under the MIT license found in the |
5 | | * LICENSE file in the root directory of this source tree. |
6 | | */ |
7 | | |
8 | | #ifndef HERMES_BCGEN_HBC_BYTECODEPROVIDERFROMSRC_H |
9 | | #define HERMES_BCGEN_HBC_BYTECODEPROVIDERFROMSRC_H |
10 | | |
11 | | #include "hermes/BCGen/HBC/Bytecode.h" |
12 | | #include "hermes/BCGen/HBC/BytecodeDataProvider.h" |
13 | | |
14 | | #include "llvh/ADT/Optional.h" |
15 | | |
16 | | namespace hermes { |
17 | | namespace hbc { |
18 | | |
19 | | /// Flags passed to createBCProviderFromSrc to set parameters on execution. |
20 | | struct CompileFlags { |
21 | | bool debug{false}; |
22 | | bool lazy{false}; |
23 | | bool enableBlockScoping{false}; |
24 | | |
25 | | /// Eagerly compile files under this number of bytes, even when lazy. |
26 | | // Lazy compilation has significant per-module overhead, and is best applied |
27 | | // to large bundles with a lot of unused code. Eager compilation is more |
28 | | // efficient when compiling many small bundles with little unused code, such |
29 | | // as when the API user loads smaller chunks of JS code on demand. |
30 | | unsigned preemptiveFileCompilationThreshold{1 << 16}; |
31 | | /// Eagerly compile functions under this number of bytes, even when lazy. |
32 | | unsigned preemptiveFunctionCompilationThreshold{160}; |
33 | | |
34 | | bool strict{false}; |
35 | | /// The value is optional; when it is set, the optimization setting is based |
36 | | /// on the value; when it is unset, it means the parser needs to automatically |
37 | | /// detect the 'use static builtin' directive and set the optimization setting |
38 | | /// accordingly. |
39 | | llvh::Optional<bool> staticBuiltins; |
40 | | bool verifyIR{false}; |
41 | | /// If set, the compiler emits async break check instructions. These may be |
42 | | /// used for several purposes, for example, to enforce a time limit on |
43 | | /// execution. Other flags may also cause these instructions to be emitted, |
44 | | /// for example debugging. |
45 | | bool emitAsyncBreakCheck{false}; |
46 | | /// Include libhermes declarations when compiling the file. This is done in |
47 | | /// normal compilation, but not for eval(). |
48 | | bool includeLibHermes{true}; |
49 | | /// If set, instrument the IR for dynamic checks. |
50 | | bool instrumentIR{false}; |
51 | | /// Enable generators. |
52 | | bool enableGenerator{true}; |
53 | | /// Enable ES6 classes support |
54 | | bool enableES6Classes{false}; |
55 | | /// Define the output format of the generated bytecode. For instance, whether |
56 | | /// the bytecode is intended for execution or serialisation. |
57 | | OutputFormatKind format{Execute}; |
58 | | }; |
59 | | |
60 | | #ifndef HERMESVM_LEAN |
61 | | /// BCProviderFromSrc is used when we are construction the bytecode from |
62 | | /// source compilation, i.e. we generate BytecodeModule/BytecodeFunction |
63 | | /// in this code path, and all the data are stored in those classes. |
64 | | /// We should only depend on this when running from eval code path to |
65 | | /// make sure maximum efficiency when loading from bytecode file. |
66 | | class BCProviderFromSrc final : public BCProviderBase { |
67 | | /// The BytecodeModule that provides the bytecode data. |
68 | | std::unique_ptr<hbc::BytecodeModule> module_; |
69 | | |
70 | | /// Whether the module constitutes a single function |
71 | | bool singleFunction_; |
72 | | |
73 | | /// Hash of all source files. |
74 | | SHA1 sourceHash_{SHA1{}}; |
75 | | |
76 | | explicit BCProviderFromSrc(std::unique_ptr<hbc::BytecodeModule> module); |
77 | | |
78 | | /// No need to do anything since it's already created as part of |
79 | | /// BytecodeModule and set to the local member. |
80 | 0 | void createDebugInfo() override {} |
81 | | |
82 | | /// Creates a BCProviderFromSrc by compiling the given JavaScript and |
83 | | /// optionally optimizing it with the supplied callback. |
84 | | /// \param buffer the JavaScript source to compile, encoded in utf-8. It is |
85 | | /// required to have null termination ('\0') in the byte past the end, |
86 | | /// in other words `assert(buffer.data()[buffer.size()] == 0)`. |
87 | | /// \param sourceURL this will be used as the "file name" of the buffer for |
88 | | /// errors, stack traces, etc. |
89 | | /// \param sourceMap optional input source map for \p buffer. |
90 | | /// \param compileFlags self explanatory |
91 | | /// \param scopeChain a scope chain for local variable resolution |
92 | | /// \param diagHandler handler for errors/warnings/notes. |
93 | | /// \param diagContext opaque data that will be passed to diagHandler. |
94 | | /// \param runOptimizationPasses if optimization is enabled in the settings |
95 | | /// and this is non-null, invoke this callback with the IR module to |
96 | | /// perform optimizations. This allows us to defer the decision of |
97 | | /// whether to link all optimizations to the caller. |
98 | | /// \param defaultBytecodeGenerationOptions the starting bytecode generation |
99 | | /// options that will be used during the bytecode generation phase. |
100 | | /// Some options will be overriden depending on other arguments passed in. |
101 | | /// |
102 | | /// \return a BCProvider and an empty error, or a null BCProvider and an error |
103 | | /// message (if diagHandler was provided, the error message is "error"). |
104 | | static std::pair<std::unique_ptr<BCProviderFromSrc>, std::string> |
105 | | createBCProviderFromSrcImpl( |
106 | | std::unique_ptr<Buffer> buffer, |
107 | | llvh::StringRef sourceURL, |
108 | | std::unique_ptr<SourceMap> sourceMap, |
109 | | const CompileFlags &compileFlags, |
110 | | const ScopeChain &scopeChain, |
111 | | SourceErrorManager::DiagHandlerTy diagHandler, |
112 | | void *diagContext, |
113 | | const std::function<void(Module &)> &runOptimizationPasses, |
114 | | const BytecodeGenerationOptions &defaultBytecodeGenerationOptions); |
115 | | |
116 | | public: |
117 | | static std::unique_ptr<BCProviderFromSrc> createBCProviderFromSrc( |
118 | 147 | std::unique_ptr<hbc::BytecodeModule> module) { |
119 | 147 | return std::unique_ptr<BCProviderFromSrc>( |
120 | 147 | new BCProviderFromSrc(std::move(module))); |
121 | 147 | } |
122 | | |
123 | | /// Creates a BCProviderFromSrc by compiling the given JavaScript. |
124 | | /// \param buffer the JavaScript source to compile, encoded in utf-8. It is |
125 | | /// required to have null termination ('\0') in the byte past the end, |
126 | | /// in other words `assert(buffer.data()[buffer.size()] == 0)`. |
127 | | /// \param sourceURL this will be used as the "file name" of the buffer for |
128 | | /// errors, stack traces, etc. |
129 | | /// \param compileFlags self explanatory |
130 | | /// |
131 | | /// \return a BCProvider and an empty error, or a null BCProvider and an error |
132 | | /// message. |
133 | | static std::pair<std::unique_ptr<BCProviderFromSrc>, std::string> |
134 | | createBCProviderFromSrc( |
135 | | std::unique_ptr<Buffer> buffer, |
136 | | llvh::StringRef sourceURL, |
137 | | const CompileFlags &compileFlags); |
138 | | |
139 | | /// Creates a BCProviderFromSrc by compiling the given JavaScript. |
140 | | /// \param buffer the JavaScript source to compile, encoded in utf-8. It is |
141 | | /// required to have null termination ('\0') in the byte past the end, |
142 | | /// in other words `assert(buffer.data()[buffer.size()] == 0)`. |
143 | | /// \param sourceURL this will be used as the "file name" of the buffer for |
144 | | /// errors, stack traces, etc. |
145 | | /// \param sourceMap optional input source map for \p buffer. |
146 | | /// \param compileFlags self explanatory |
147 | | /// |
148 | | /// \return a BCProvider and an empty error, or a null BCProvider and an error |
149 | | /// message. |
150 | | static std::pair<std::unique_ptr<BCProviderFromSrc>, std::string> |
151 | | createBCProviderFromSrc( |
152 | | std::unique_ptr<Buffer> buffer, |
153 | | llvh::StringRef sourceURL, |
154 | | std::unique_ptr<SourceMap> sourceMap, |
155 | | const CompileFlags &compileFlags); |
156 | | |
157 | | /// Creates a BCProviderFromSrc by compiling the given JavaScript. |
158 | | /// \param buffer the JavaScript source to compile, encoded in utf-8. It is |
159 | | /// required to have null termination ('\0') in the byte past the end, |
160 | | /// in other words `assert(buffer.data()[buffer.size()] == 0)`. |
161 | | /// \param sourceURL this will be used as the "file name" of the buffer for |
162 | | /// errors, stack traces, etc. |
163 | | /// \param sourceMap optional input source map for \p buffer. |
164 | | /// \param compileFlags self explanatory |
165 | | /// \param scopeChain a scope chain for local variable resolution |
166 | | /// \param diagHandler optional handler for errors/warnings/notes. |
167 | | /// \param diagContext opaque data that will be passed to diagHandler. |
168 | | /// |
169 | | /// \return a BCProvider and an empty error, or a null BCProvider and an error |
170 | | /// message (if diagHandler was provided, the error message is "error"). |
171 | | static std::pair<std::unique_ptr<BCProviderFromSrc>, std::string> |
172 | | createBCProviderFromSrc( |
173 | | std::unique_ptr<Buffer> buffer, |
174 | | llvh::StringRef sourceURL, |
175 | | std::unique_ptr<SourceMap> sourceMap, |
176 | | const CompileFlags &compileFlags, |
177 | | const ScopeChain &scopeChain, |
178 | | SourceErrorManager::DiagHandlerTy diagHandler = nullptr, |
179 | | void *diagContext = nullptr, |
180 | | const std::function<void(Module &)> &runOptimizationPasses = {}, |
181 | | const BytecodeGenerationOptions &defaultBytecodeGenerationOptions = |
182 | | BytecodeGenerationOptions::defaults()); |
183 | | |
184 | 151 | RuntimeFunctionHeader getFunctionHeader(uint32_t functionID) const override { |
185 | 151 | return RuntimeFunctionHeader(&module_->getFunction(functionID).getHeader()); |
186 | 151 | } |
187 | | |
188 | 7.37k | StringTableEntry getStringTableEntry(uint32_t index) const override { |
189 | 7.37k | assert(index < stringCount_ && "invalid string table index"); |
190 | 7.37k | return module_->getStringTable()[index]; |
191 | 7.37k | } |
192 | | |
193 | 151 | const uint8_t *getBytecode(uint32_t functionID) const override { |
194 | 151 | return module_->getFunction(functionID).getOpcodeArray().data(); |
195 | 151 | } |
196 | | |
197 | | llvh::ArrayRef<hbc::HBCExceptionHandlerInfo> getExceptionTable( |
198 | 41 | uint32_t functionID) const override { |
199 | 41 | return module_->getFunction(functionID).getExceptionHandlers(); |
200 | 41 | } |
201 | | |
202 | 43 | const hbc::DebugOffsets *getDebugOffsets(uint32_t functionID) const override { |
203 | 43 | return module_->getFunction(functionID).getDebugOffsets(); |
204 | 43 | } |
205 | | |
206 | 231 | bool isFunctionLazy(uint32_t functionID) const override { |
207 | 231 | return module_->getFunction(functionID).isLazy(); |
208 | 231 | } |
209 | | |
210 | 231 | bool isLazy() const override { |
211 | 231 | return false; |
212 | 231 | } |
213 | | |
214 | 80 | bool isSingleFunction() const { |
215 | 80 | return singleFunction_; |
216 | 80 | } |
217 | | |
218 | 80 | hbc::BytecodeModule *getBytecodeModule() { |
219 | 80 | return module_.get(); |
220 | 80 | } |
221 | | |
222 | 0 | SHA1 getSourceHash() const override { |
223 | 0 | return sourceHash_; |
224 | 0 | }; |
225 | | |
226 | 0 | void setSourceHash(const SHA1 &hash) { |
227 | 0 | sourceHash_ = hash; |
228 | 0 | }; |
229 | | }; |
230 | | |
231 | | /// BCProviderLazy is used during lazy compilation. When a function is created |
232 | | /// to be lazily compiled later, we create a BCProviderLazy object with |
233 | | /// a pointer to such BytecodeFunction. |
234 | | class BCProviderLazy final : public BCProviderBase { |
235 | | /// Pointer to the BytecodeFunction. |
236 | | hbc::BytecodeFunction *bytecodeFunction_; |
237 | | |
238 | | explicit BCProviderLazy(hbc::BytecodeFunction *bytecodeFunction); |
239 | | |
240 | | /// No debug information will be available without compiling it. |
241 | 0 | void createDebugInfo() override { |
242 | 0 | hermes_fatal("Accessing debug info from a lazy module"); |
243 | 0 | } |
244 | | |
245 | | public: |
246 | | static std::unique_ptr<BCProviderBase> createBCProviderLazy( |
247 | 80 | hbc::BytecodeFunction *bytecodeFunction) { |
248 | 80 | return std::unique_ptr<BCProviderBase>( |
249 | 80 | new BCProviderLazy(bytecodeFunction)); |
250 | 80 | } |
251 | | |
252 | 80 | RuntimeFunctionHeader getFunctionHeader(uint32_t) const override { |
253 | 80 | return RuntimeFunctionHeader(&bytecodeFunction_->getHeader()); |
254 | 80 | } |
255 | | |
256 | 0 | StringTableEntry getStringTableEntry(uint32_t index) const override { |
257 | 0 | hermes_fatal("Accessing string table from a lazy module"); |
258 | 0 | } |
259 | | |
260 | 0 | const uint8_t *getBytecode(uint32_t) const override { |
261 | 0 | hermes_fatal("Accessing bytecode from a lazy module"); |
262 | 0 | } |
263 | | |
264 | | llvh::ArrayRef<hbc::HBCExceptionHandlerInfo> getExceptionTable( |
265 | 0 | uint32_t) const override { |
266 | 0 | hermes_fatal("Accessing exception info from a lazy module"); |
267 | 0 | } |
268 | | |
269 | 0 | const hbc::DebugOffsets *getDebugOffsets(uint32_t) const override { |
270 | 0 | hermes_fatal("Accessing debug offsets from a lazy module"); |
271 | 0 | } |
272 | | |
273 | 0 | bool isFunctionLazy(uint32_t) const override { |
274 | 0 | return true; |
275 | 0 | } |
276 | | |
277 | 80 | bool isLazy() const override { |
278 | 80 | return true; |
279 | 80 | } |
280 | | |
281 | | /// \return the pointer to the BytecodeFunction. |
282 | 0 | hbc::BytecodeFunction *getBytecodeFunction() { |
283 | 0 | return bytecodeFunction_; |
284 | 0 | } |
285 | | }; |
286 | | #endif // HERMESVM_LEAN |
287 | | } // namespace hbc |
288 | | } // namespace hermes |
289 | | |
290 | | #endif // HERMES_BCGEN_HBC_BYTECODEPROVIDERFROMSRC_H |