Coverage Report

Created: 2025-12-12 07:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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