Coverage Report

Created: 2025-12-12 07:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hermes/lib/BCGen/HBC/BytecodeDataProvider.cpp
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
#include "hermes/BCGen/HBC/BytecodeDataProvider.h"
9
#include "hermes/BCGen/HBC/BytecodeFileFormat.h"
10
#include "hermes/Support/ErrorHandling.h"
11
#include "hermes/Support/OSCompat.h"
12
13
#include "llvh/Support/MathExtras.h"
14
#include "llvh/Support/SHA1.h"
15
16
namespace hermes {
17
namespace hbc {
18
19
namespace {
20
21
/// Given a valid bytecode buffer aref, returns whether its stored fileHash
22
/// matches the actual hash of the buffer.
23
226
static bool hashIsValid(llvh::ArrayRef<uint8_t> aref) {
24
226
  const auto *header =
25
226
      reinterpret_cast<const hbc::BytecodeFileHeader *>(aref.data());
26
226
  assert(
27
226
      header->version == hbc::BYTECODE_VERSION &&
28
226
      "must perform basic checks first");
29
  // Use fileLength rather than aref.end() since there may be an epilogue.
30
226
  const auto *footer = reinterpret_cast<const hbc::BytecodeFileFooter *>(
31
226
      aref.data() + header->fileLength - sizeof(BytecodeFileFooter));
32
226
  SHA1 actual = llvh::SHA1::hash(
33
226
      llvh::ArrayRef<uint8_t>(
34
226
          aref.begin(), reinterpret_cast<const uint8_t *>(footer)));
35
226
  return std::equal(actual.begin(), actual.end(), footer->fileHash);
36
226
}
37
38
0
static void updateHash(llvh::MutableArrayRef<uint8_t> aref) {
39
0
  const auto *header =
40
0
      reinterpret_cast<const hbc::BytecodeFileHeader *>(aref.data());
41
0
  assert(
42
0
      header->version == hbc::BYTECODE_VERSION &&
43
0
      "must perform basic checks first");
44
  // Use fileLength rather than aref.end() since there may be an epilogue.
45
0
  auto *footer = reinterpret_cast<hbc::BytecodeFileFooter *>(
46
0
      aref.data() + header->fileLength - sizeof(BytecodeFileFooter));
47
0
  SHA1 actual = llvh::SHA1::hash(
48
0
      llvh::ArrayRef<uint8_t>(
49
0
          aref.begin(), reinterpret_cast<const uint8_t *>(footer)));
50
0
  std::copy(actual.begin(), actual.end(), footer->fileHash);
51
0
}
52
53
/// Returns if aref points to valid bytecode and specifies why it may not
54
/// in errorMessage (if supplied).
55
static bool sanityCheck(
56
    llvh::ArrayRef<uint8_t> aref,
57
    BytecodeForm form,
58
226
    std::string *errorMessage) {
59
226
  if (aref.size() < sizeof(hbc::BytecodeFileHeader)) {
60
0
    if (errorMessage) {
61
0
      llvh::raw_string_ostream errs(*errorMessage);
62
0
      errs << "Buffer smaller than a bytecode file header. Expected at least "
63
0
           << sizeof(hbc::BytecodeFileHeader) << " bytes but got "
64
0
           << aref.size() << " bytes";
65
0
    }
66
0
    return false;
67
0
  }
68
69
  // Ensure the data is aligned to be able to read an int from the start.
70
226
  if (llvh::alignAddr(aref.data(), BYTECODE_ALIGNMENT) !=
71
226
      (uintptr_t)aref.data()) {
72
0
    if (errorMessage) {
73
0
      *errorMessage = "Buffer misaligned.";
74
0
    }
75
0
    return false;
76
0
  }
77
78
226
  const auto *header =
79
226
      reinterpret_cast<const hbc::BytecodeFileHeader *>(aref.data());
80
81
226
  auto magic = (form == BytecodeForm::Delta ? DELTA_MAGIC : MAGIC);
82
226
  if (header->magic != magic) {
83
0
    if (errorMessage) {
84
0
      *errorMessage = "Incorrect magic number";
85
0
    }
86
0
    return false;
87
0
  }
88
226
  if (header->version != hbc::BYTECODE_VERSION) {
89
0
    if (errorMessage) {
90
0
      llvh::raw_string_ostream errs(*errorMessage);
91
0
      errs << "Wrong bytecode version. Expected " << hbc::BYTECODE_VERSION
92
0
           << " but got " << header->version;
93
0
    }
94
0
    return false;
95
0
  }
96
226
  if (header->functionCount == 0) {
97
0
    if (errorMessage) {
98
0
      *errorMessage = "Bytecode does not contain any functions";
99
0
    }
100
0
    return false;
101
0
  }
102
226
  if (aref.size() < header->fileLength) {
103
0
    if (errorMessage) {
104
0
      llvh::raw_string_ostream errs(*errorMessage);
105
0
      errs
106
0
          << "Buffer is smaller than the size stated in the file header. Expected at least "
107
0
          << header->fileLength << " bytes but got " << aref.size() << " bytes";
108
0
    }
109
0
    return false;
110
0
  }
111
226
#ifdef HERMES_SLOW_DEBUG
112
226
  if (!hashIsValid(aref)) {
113
0
    if (errorMessage) {
114
0
      *errorMessage = "Bytecode hash mismatch";
115
0
    }
116
0
    return false;
117
0
  }
118
226
#endif
119
226
  return true;
120
226
}
121
122
/// Assert that \p buf has the proper alignment for T, and then cast it to a
123
/// pointer to T. \return the pointer to T.
124
template <typename T>
125
3.61k
const T *alignCheckCast(const uint8_t *buf) {
126
  // We pad the offset of each data structure by BYTECODE_ALIGNMENT bytes, hence
127
  // we cannot support casting to any data structure that requires more than 4
128
  // bytes alignment, which may lead to undefined behavior.
129
3.61k
  static_assert(
130
3.61k
      alignof(T) <= BYTECODE_ALIGNMENT, "Cannot handle the alignment");
131
3.61k
  assert(
132
3.61k
      (llvh::alignAddr(buf, alignof(T)) == (uintptr_t)buf) &&
133
3.61k
      "buf is not properly aligned");
134
3.61k
  return reinterpret_cast<const T *>(buf);
135
3.61k
}
BytecodeDataProvider.cpp:hermes::hbc::BytecodeFileHeader const* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::hbc::BytecodeFileHeader>(unsigned char const*)
Line
Count
Source
125
226
const T *alignCheckCast(const uint8_t *buf) {
126
  // We pad the offset of each data structure by BYTECODE_ALIGNMENT bytes, hence
127
  // we cannot support casting to any data structure that requires more than 4
128
  // bytes alignment, which may lead to undefined behavior.
129
226
  static_assert(
130
226
      alignof(T) <= BYTECODE_ALIGNMENT, "Cannot handle the alignment");
131
226
  assert(
132
226
      (llvh::alignAddr(buf, alignof(T)) == (uintptr_t)buf) &&
133
226
      "buf is not properly aligned");
134
226
  return reinterpret_cast<const T *>(buf);
135
226
}
BytecodeDataProvider.cpp:unsigned char const* hermes::hbc::(anonymous namespace)::alignCheckCast<unsigned char>(unsigned char const*)
Line
Count
Source
125
1.35k
const T *alignCheckCast(const uint8_t *buf) {
126
  // We pad the offset of each data structure by BYTECODE_ALIGNMENT bytes, hence
127
  // we cannot support casting to any data structure that requires more than 4
128
  // bytes alignment, which may lead to undefined behavior.
129
1.35k
  static_assert(
130
1.35k
      alignof(T) <= BYTECODE_ALIGNMENT, "Cannot handle the alignment");
131
1.35k
  assert(
132
1.35k
      (llvh::alignAddr(buf, alignof(T)) == (uintptr_t)buf) &&
133
1.35k
      "buf is not properly aligned");
134
1.35k
  return reinterpret_cast<const T *>(buf);
135
1.35k
}
BytecodeDataProvider.cpp:hermes::hbc::SmallFuncHeader const* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::hbc::SmallFuncHeader>(unsigned char const*)
Line
Count
Source
125
226
const T *alignCheckCast(const uint8_t *buf) {
126
  // We pad the offset of each data structure by BYTECODE_ALIGNMENT bytes, hence
127
  // we cannot support casting to any data structure that requires more than 4
128
  // bytes alignment, which may lead to undefined behavior.
129
226
  static_assert(
130
226
      alignof(T) <= BYTECODE_ALIGNMENT, "Cannot handle the alignment");
131
226
  assert(
132
226
      (llvh::alignAddr(buf, alignof(T)) == (uintptr_t)buf) &&
133
226
      "buf is not properly aligned");
134
226
  return reinterpret_cast<const T *>(buf);
135
226
}
BytecodeDataProvider.cpp:hermes::StringKind::Entry const* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::StringKind::Entry>(unsigned char const*)
Line
Count
Source
125
226
const T *alignCheckCast(const uint8_t *buf) {
126
  // We pad the offset of each data structure by BYTECODE_ALIGNMENT bytes, hence
127
  // we cannot support casting to any data structure that requires more than 4
128
  // bytes alignment, which may lead to undefined behavior.
129
226
  static_assert(
130
226
      alignof(T) <= BYTECODE_ALIGNMENT, "Cannot handle the alignment");
131
226
  assert(
132
226
      (llvh::alignAddr(buf, alignof(T)) == (uintptr_t)buf) &&
133
226
      "buf is not properly aligned");
134
226
  return reinterpret_cast<const T *>(buf);
135
226
}
BytecodeDataProvider.cpp:unsigned int const* hermes::hbc::(anonymous namespace)::alignCheckCast<unsigned int>(unsigned char const*)
Line
Count
Source
125
226
const T *alignCheckCast(const uint8_t *buf) {
126
  // We pad the offset of each data structure by BYTECODE_ALIGNMENT bytes, hence
127
  // we cannot support casting to any data structure that requires more than 4
128
  // bytes alignment, which may lead to undefined behavior.
129
226
  static_assert(
130
226
      alignof(T) <= BYTECODE_ALIGNMENT, "Cannot handle the alignment");
131
226
  assert(
132
226
      (llvh::alignAddr(buf, alignof(T)) == (uintptr_t)buf) &&
133
226
      "buf is not properly aligned");
134
226
  return reinterpret_cast<const T *>(buf);
135
226
}
BytecodeDataProvider.cpp:hermes::hbc::SmallStringTableEntry const* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::hbc::SmallStringTableEntry>(unsigned char const*)
Line
Count
Source
125
226
const T *alignCheckCast(const uint8_t *buf) {
126
  // We pad the offset of each data structure by BYTECODE_ALIGNMENT bytes, hence
127
  // we cannot support casting to any data structure that requires more than 4
128
  // bytes alignment, which may lead to undefined behavior.
129
226
  static_assert(
130
226
      alignof(T) <= BYTECODE_ALIGNMENT, "Cannot handle the alignment");
131
226
  assert(
132
226
      (llvh::alignAddr(buf, alignof(T)) == (uintptr_t)buf) &&
133
226
      "buf is not properly aligned");
134
226
  return reinterpret_cast<const T *>(buf);
135
226
}
BytecodeDataProvider.cpp:hermes::hbc::OverflowStringTableEntry const* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::hbc::OverflowStringTableEntry>(unsigned char const*)
Line
Count
Source
125
226
const T *alignCheckCast(const uint8_t *buf) {
126
  // We pad the offset of each data structure by BYTECODE_ALIGNMENT bytes, hence
127
  // we cannot support casting to any data structure that requires more than 4
128
  // bytes alignment, which may lead to undefined behavior.
129
226
  static_assert(
130
226
      alignof(T) <= BYTECODE_ALIGNMENT, "Cannot handle the alignment");
131
226
  assert(
132
226
      (llvh::alignAddr(buf, alignof(T)) == (uintptr_t)buf) &&
133
226
      "buf is not properly aligned");
134
226
  return reinterpret_cast<const T *>(buf);
135
226
}
BytecodeDataProvider.cpp:hermes::bigint::BigIntTableEntry const* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::bigint::BigIntTableEntry>(unsigned char const*)
Line
Count
Source
125
226
const T *alignCheckCast(const uint8_t *buf) {
126
  // We pad the offset of each data structure by BYTECODE_ALIGNMENT bytes, hence
127
  // we cannot support casting to any data structure that requires more than 4
128
  // bytes alignment, which may lead to undefined behavior.
129
226
  static_assert(
130
226
      alignof(T) <= BYTECODE_ALIGNMENT, "Cannot handle the alignment");
131
226
  assert(
132
226
      (llvh::alignAddr(buf, alignof(T)) == (uintptr_t)buf) &&
133
226
      "buf is not properly aligned");
134
226
  return reinterpret_cast<const T *>(buf);
135
226
}
BytecodeDataProvider.cpp:hermes::RegExpTableEntry const* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::RegExpTableEntry>(unsigned char const*)
Line
Count
Source
125
226
const T *alignCheckCast(const uint8_t *buf) {
126
  // We pad the offset of each data structure by BYTECODE_ALIGNMENT bytes, hence
127
  // we cannot support casting to any data structure that requires more than 4
128
  // bytes alignment, which may lead to undefined behavior.
129
226
  static_assert(
130
226
      alignof(T) <= BYTECODE_ALIGNMENT, "Cannot handle the alignment");
131
226
  assert(
132
226
      (llvh::alignAddr(buf, alignof(T)) == (uintptr_t)buf) &&
133
226
      "buf is not properly aligned");
134
226
  return reinterpret_cast<const T *>(buf);
135
226
}
BytecodeDataProvider.cpp:std::__1::pair<unsigned int, unsigned int> const* hermes::hbc::(anonymous namespace)::alignCheckCast<std::__1::pair<unsigned int, unsigned int> >(unsigned char const*)
Line
Count
Source
125
452
const T *alignCheckCast(const uint8_t *buf) {
126
  // We pad the offset of each data structure by BYTECODE_ALIGNMENT bytes, hence
127
  // we cannot support casting to any data structure that requires more than 4
128
  // bytes alignment, which may lead to undefined behavior.
129
452
  static_assert(
130
452
      alignof(T) <= BYTECODE_ALIGNMENT, "Cannot handle the alignment");
131
452
  assert(
132
452
      (llvh::alignAddr(buf, alignof(T)) == (uintptr_t)buf) &&
133
452
      "buf is not properly aligned");
134
452
  return reinterpret_cast<const T *>(buf);
135
452
}
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::hbc::DebugInfoHeader const* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::hbc::DebugInfoHeader>(unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::StringTableEntry const* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::StringTableEntry>(unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::hbc::DebugFileRegion const* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::hbc::DebugFileRegion>(unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::hbc::ExceptionHandlerTableHeader const* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::hbc::ExceptionHandlerTableHeader>(unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::hbc::HBCExceptionHandlerInfo const* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::hbc::HBCExceptionHandlerInfo>(unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::hbc::DebugOffsets const* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::hbc::DebugOffsets>(unsigned char const*)
136
137
/// Variant of alignCheckCast() for non-const pointers.
138
template <typename T>
139
0
T *alignCheckCast(uint8_t *buf) {
140
0
  static_assert(
141
0
      alignof(T) <= BYTECODE_ALIGNMENT, "Cannot handle the alignment");
142
0
  assert(
143
0
      (llvh::alignAddr(buf, alignof(T)) == (uintptr_t)buf) &&
144
0
      "buf is not properly aligned");
145
0
  return reinterpret_cast<T *>(buf);
146
0
}
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::hbc::BytecodeFileHeader* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::hbc::BytecodeFileHeader>(unsigned char*)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::hbc::SmallFuncHeader* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::hbc::SmallFuncHeader>(unsigned char*)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::StringKind::Entry* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::StringKind::Entry>(unsigned char*)
Unexecuted instantiation: BytecodeDataProvider.cpp:unsigned int* hermes::hbc::(anonymous namespace)::alignCheckCast<unsigned int>(unsigned char*)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::hbc::SmallStringTableEntry* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::hbc::SmallStringTableEntry>(unsigned char*)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::hbc::OverflowStringTableEntry* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::hbc::OverflowStringTableEntry>(unsigned char*)
Unexecuted instantiation: BytecodeDataProvider.cpp:unsigned char* hermes::hbc::(anonymous namespace)::alignCheckCast<unsigned char>(unsigned char*)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::bigint::BigIntTableEntry* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::bigint::BigIntTableEntry>(unsigned char*)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::RegExpTableEntry* hermes::hbc::(anonymous namespace)::alignCheckCast<hermes::RegExpTableEntry>(unsigned char*)
Unexecuted instantiation: BytecodeDataProvider.cpp:std::__1::pair<unsigned int, unsigned int>* hermes::hbc::(anonymous namespace)::alignCheckCast<std::__1::pair<unsigned int, unsigned int> >(unsigned char*)
147
148
/// Cast the pointer at \p buf to type T, increment \p buf by
149
/// the size of T.
150
template <typename T>
151
226
const T *castData(const uint8_t *&buf) {
152
226
  auto ret = alignCheckCast<T>(buf);
153
226
  buf += sizeof(T);
154
226
  return ret;
155
226
}
BytecodeDataProvider.cpp:hermes::hbc::BytecodeFileHeader const* hermes::hbc::(anonymous namespace)::castData<hermes::hbc::BytecodeFileHeader>(unsigned char const*&)
Line
Count
Source
151
226
const T *castData(const uint8_t *&buf) {
152
226
  auto ret = alignCheckCast<T>(buf);
153
226
  buf += sizeof(T);
154
226
  return ret;
155
226
}
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::hbc::DebugInfoHeader const* hermes::hbc::(anonymous namespace)::castData<hermes::hbc::DebugInfoHeader>(unsigned char const*&)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::hbc::DebugFileRegion const* hermes::hbc::(anonymous namespace)::castData<hermes::hbc::DebugFileRegion>(unsigned char const*&)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::hbc::ExceptionHandlerTableHeader const* hermes::hbc::(anonymous namespace)::castData<hermes::hbc::ExceptionHandlerTableHeader>(unsigned char const*&)
Unexecuted instantiation: BytecodeDataProvider.cpp:hermes::hbc::DebugOffsets const* hermes::hbc::(anonymous namespace)::castData<hermes::hbc::DebugOffsets>(unsigned char const*&)
156
157
/// Variant of castData() for non-const pointers.
158
template <typename T>
159
0
T *castData(uint8_t *&buf) {
160
0
  auto ret = alignCheckCast<T>(buf);
161
0
  buf += sizeof(T);
162
0
  return ret;
163
0
}
164
165
/// Cast the pointer at \p buf to an array of type T, with \p size.
166
/// Fatals if the end of the array extends past \p end.
167
/// Increment \p buf by the total size of the array.
168
template <typename T>
169
llvh::ArrayRef<T>
170
3.39k
castArrayRef(const uint8_t *&buf, size_t size, const uint8_t *end) {
171
3.39k
  auto ptr = alignCheckCast<T>(buf);
172
3.39k
  if (LLVM_UNLIKELY(buf > end || size > (end - buf) / sizeof(T)))
173
0
    hermes_fatal("overflow past end of bytecode");
174
3.39k
  buf += size * sizeof(T);
175
3.39k
  return {ptr, size};
176
3.39k
}
BytecodeDataProvider.cpp:llvh::ArrayRef<unsigned char> hermes::hbc::(anonymous namespace)::castArrayRef<unsigned char>(unsigned char const*&, unsigned long, unsigned char const*)
Line
Count
Source
170
1.35k
castArrayRef(const uint8_t *&buf, size_t size, const uint8_t *end) {
171
1.35k
  auto ptr = alignCheckCast<T>(buf);
172
1.35k
  if (LLVM_UNLIKELY(buf > end || size > (end - buf) / sizeof(T)))
173
0
    hermes_fatal("overflow past end of bytecode");
174
1.35k
  buf += size * sizeof(T);
175
1.35k
  return {ptr, size};
176
1.35k
}
BytecodeDataProvider.cpp:llvh::ArrayRef<hermes::hbc::SmallFuncHeader> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::hbc::SmallFuncHeader>(unsigned char const*&, unsigned long, unsigned char const*)
Line
Count
Source
170
226
castArrayRef(const uint8_t *&buf, size_t size, const uint8_t *end) {
171
226
  auto ptr = alignCheckCast<T>(buf);
172
226
  if (LLVM_UNLIKELY(buf > end || size > (end - buf) / sizeof(T)))
173
0
    hermes_fatal("overflow past end of bytecode");
174
226
  buf += size * sizeof(T);
175
226
  return {ptr, size};
176
226
}
BytecodeDataProvider.cpp:llvh::ArrayRef<hermes::StringKind::Entry> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::StringKind::Entry>(unsigned char const*&, unsigned long, unsigned char const*)
Line
Count
Source
170
226
castArrayRef(const uint8_t *&buf, size_t size, const uint8_t *end) {
171
226
  auto ptr = alignCheckCast<T>(buf);
172
226
  if (LLVM_UNLIKELY(buf > end || size > (end - buf) / sizeof(T)))
173
0
    hermes_fatal("overflow past end of bytecode");
174
226
  buf += size * sizeof(T);
175
226
  return {ptr, size};
176
226
}
BytecodeDataProvider.cpp:llvh::ArrayRef<unsigned int> hermes::hbc::(anonymous namespace)::castArrayRef<unsigned int>(unsigned char const*&, unsigned long, unsigned char const*)
Line
Count
Source
170
226
castArrayRef(const uint8_t *&buf, size_t size, const uint8_t *end) {
171
226
  auto ptr = alignCheckCast<T>(buf);
172
226
  if (LLVM_UNLIKELY(buf > end || size > (end - buf) / sizeof(T)))
173
0
    hermes_fatal("overflow past end of bytecode");
174
226
  buf += size * sizeof(T);
175
226
  return {ptr, size};
176
226
}
BytecodeDataProvider.cpp:llvh::ArrayRef<hermes::hbc::SmallStringTableEntry> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::hbc::SmallStringTableEntry>(unsigned char const*&, unsigned long, unsigned char const*)
Line
Count
Source
170
226
castArrayRef(const uint8_t *&buf, size_t size, const uint8_t *end) {
171
226
  auto ptr = alignCheckCast<T>(buf);
172
226
  if (LLVM_UNLIKELY(buf > end || size > (end - buf) / sizeof(T)))
173
0
    hermes_fatal("overflow past end of bytecode");
174
226
  buf += size * sizeof(T);
175
226
  return {ptr, size};
176
226
}
BytecodeDataProvider.cpp:llvh::ArrayRef<hermes::hbc::OverflowStringTableEntry> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::hbc::OverflowStringTableEntry>(unsigned char const*&, unsigned long, unsigned char const*)
Line
Count
Source
170
226
castArrayRef(const uint8_t *&buf, size_t size, const uint8_t *end) {
171
226
  auto ptr = alignCheckCast<T>(buf);
172
226
  if (LLVM_UNLIKELY(buf > end || size > (end - buf) / sizeof(T)))
173
0
    hermes_fatal("overflow past end of bytecode");
174
226
  buf += size * sizeof(T);
175
226
  return {ptr, size};
176
226
}
BytecodeDataProvider.cpp:llvh::ArrayRef<hermes::bigint::BigIntTableEntry> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::bigint::BigIntTableEntry>(unsigned char const*&, unsigned long, unsigned char const*)
Line
Count
Source
170
226
castArrayRef(const uint8_t *&buf, size_t size, const uint8_t *end) {
171
226
  auto ptr = alignCheckCast<T>(buf);
172
226
  if (LLVM_UNLIKELY(buf > end || size > (end - buf) / sizeof(T)))
173
0
    hermes_fatal("overflow past end of bytecode");
174
226
  buf += size * sizeof(T);
175
226
  return {ptr, size};
176
226
}
BytecodeDataProvider.cpp:llvh::ArrayRef<hermes::RegExpTableEntry> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::RegExpTableEntry>(unsigned char const*&, unsigned long, unsigned char const*)
Line
Count
Source
170
226
castArrayRef(const uint8_t *&buf, size_t size, const uint8_t *end) {
171
226
  auto ptr = alignCheckCast<T>(buf);
172
226
  if (LLVM_UNLIKELY(buf > end || size > (end - buf) / sizeof(T)))
173
0
    hermes_fatal("overflow past end of bytecode");
174
226
  buf += size * sizeof(T);
175
226
  return {ptr, size};
176
226
}
BytecodeDataProvider.cpp:llvh::ArrayRef<std::__1::pair<unsigned int, unsigned int> > hermes::hbc::(anonymous namespace)::castArrayRef<std::__1::pair<unsigned int, unsigned int> >(unsigned char const*&, unsigned long, unsigned char const*)
Line
Count
Source
170
452
castArrayRef(const uint8_t *&buf, size_t size, const uint8_t *end) {
171
452
  auto ptr = alignCheckCast<T>(buf);
172
452
  if (LLVM_UNLIKELY(buf > end || size > (end - buf) / sizeof(T)))
173
0
    hermes_fatal("overflow past end of bytecode");
174
452
  buf += size * sizeof(T);
175
452
  return {ptr, size};
176
452
}
Unexecuted instantiation: BytecodeDataProvider.cpp:llvh::ArrayRef<hermes::StringTableEntry> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::StringTableEntry>(unsigned char const*&, unsigned long, unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:llvh::ArrayRef<hermes::hbc::HBCExceptionHandlerInfo> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::hbc::HBCExceptionHandlerInfo>(unsigned char const*&, unsigned long, unsigned char const*)
177
178
/// Variant of castArrayRef() for non-const pointers.
179
template <typename T>
180
llvh::MutableArrayRef<T>
181
0
castArrayRef(uint8_t *&buf, size_t size, const uint8_t *end) {
182
0
  auto ptr = alignCheckCast<T>(buf);
183
0
  if (LLVM_UNLIKELY(buf > end || size > (end - buf) / sizeof(T)))
184
0
    hermes_fatal("overflow past end of bytecode");
185
0
  buf += size * sizeof(T);
186
0
  return {ptr, size};
187
0
}
Unexecuted instantiation: BytecodeDataProvider.cpp:llvh::MutableArrayRef<hermes::hbc::SmallFuncHeader> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::hbc::SmallFuncHeader>(unsigned char*&, unsigned long, unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:llvh::MutableArrayRef<hermes::StringKind::Entry> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::StringKind::Entry>(unsigned char*&, unsigned long, unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:llvh::MutableArrayRef<unsigned int> hermes::hbc::(anonymous namespace)::castArrayRef<unsigned int>(unsigned char*&, unsigned long, unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:llvh::MutableArrayRef<hermes::hbc::SmallStringTableEntry> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::hbc::SmallStringTableEntry>(unsigned char*&, unsigned long, unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:llvh::MutableArrayRef<hermes::hbc::OverflowStringTableEntry> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::hbc::OverflowStringTableEntry>(unsigned char*&, unsigned long, unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:llvh::MutableArrayRef<unsigned char> hermes::hbc::(anonymous namespace)::castArrayRef<unsigned char>(unsigned char*&, unsigned long, unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:llvh::MutableArrayRef<hermes::bigint::BigIntTableEntry> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::bigint::BigIntTableEntry>(unsigned char*&, unsigned long, unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:llvh::MutableArrayRef<hermes::RegExpTableEntry> hermes::hbc::(anonymous namespace)::castArrayRef<hermes::RegExpTableEntry>(unsigned char*&, unsigned long, unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:llvh::MutableArrayRef<std::__1::pair<unsigned int, unsigned int> > hermes::hbc::(anonymous namespace)::castArrayRef<std::__1::pair<unsigned int, unsigned int> >(unsigned char*&, unsigned long, unsigned char const*)
188
189
/// Align \p buf with the \p alignment.
190
/// \p buf is passed by pointer reference and will be modified.
191
3.39k
void align(const uint8_t *&buf, uint32_t alignment = BYTECODE_ALIGNMENT) {
192
3.39k
  buf = (const uint8_t *)llvh::alignAddr(buf, alignment);
193
3.39k
}
194
195
/// Variant of align() for non-const pointers.
196
0
void align(uint8_t *&buf, uint32_t alignment = BYTECODE_ALIGNMENT) {
197
0
  buf = (uint8_t *)llvh::alignAddr(buf, alignment);
198
0
}
199
200
} // namespace
201
202
template <bool Mutable>
203
bool BytecodeFileFields<Mutable>::populateFromBuffer(
204
    Array<uint8_t> buffer,
205
    std::string *outError,
206
226
    BytecodeForm form) {
207
226
  if (!sanityCheck(buffer, form, outError)) {
208
0
    return false;
209
0
  }
210
211
  // Helper type which populates a BytecodeFileFields. This is nested inside the
212
  // function so we can leverage BytecodeFileFields template types.
213
226
  struct BytecodeFileFieldsPopulator {
214
    /// The fields being populated.
215
226
    BytecodeFileFields &f;
216
217
    /// Current buffer position.
218
226
    Pointer<uint8_t> buf;
219
220
    /// A pointer to the bytecode file header.
221
226
    const BytecodeFileHeader *h;
222
223
    /// End of buffer.
224
226
    const uint8_t *end;
225
226
226
    BytecodeFileFieldsPopulator(
227
226
        BytecodeFileFields &fields,
228
226
        Pointer<uint8_t> buffer,
229
226
        const uint8_t *bufEnd)
230
226
        : f(fields), buf(buffer), end(bufEnd) {
231
226
      f.header = castData<BytecodeFileHeader>(buf);
232
226
      h = f.header;
233
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::BytecodeFileFieldsPopulator(hermes::hbc::BytecodeFileFields<false>&, unsigned char const*, unsigned char const*)
Line
Count
Source
230
226
        : f(fields), buf(buffer), end(bufEnd) {
231
226
      f.header = castData<BytecodeFileHeader>(buf);
232
226
      h = f.header;
233
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::BytecodeFileFieldsPopulator(hermes::hbc::BytecodeFileFields<true>&, unsigned char*, unsigned char const*)
234
235
226
    void visitFunctionHeaders() {
236
226
      align(buf);
237
226
      f.functionHeaders =
238
226
          castArrayRef<SmallFuncHeader>(buf, h->functionCount, end);
239
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitFunctionHeaders()
Line
Count
Source
235
226
    void visitFunctionHeaders() {
236
226
      align(buf);
237
226
      f.functionHeaders =
238
226
          castArrayRef<SmallFuncHeader>(buf, h->functionCount, end);
239
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitFunctionHeaders()
240
241
226
    void visitStringKinds() {
242
226
      align(buf);
243
226
      f.stringKinds =
244
226
          castArrayRef<StringKind::Entry>(buf, h->stringKindCount, end);
245
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitStringKinds()
Line
Count
Source
241
226
    void visitStringKinds() {
242
226
      align(buf);
243
226
      f.stringKinds =
244
226
          castArrayRef<StringKind::Entry>(buf, h->stringKindCount, end);
245
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitStringKinds()
246
247
226
    void visitIdentifierHashes() {
248
226
      align(buf);
249
226
      f.identifierHashes = castArrayRef<uint32_t>(buf, h->identifierCount, end);
250
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitIdentifierHashes()
Line
Count
Source
247
226
    void visitIdentifierHashes() {
248
226
      align(buf);
249
226
      f.identifierHashes = castArrayRef<uint32_t>(buf, h->identifierCount, end);
250
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitIdentifierHashes()
251
252
226
    void visitSmallStringTable() {
253
226
      align(buf);
254
226
      f.stringTableEntries =
255
226
          castArrayRef<SmallStringTableEntry>(buf, h->stringCount, end);
256
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitSmallStringTable()
Line
Count
Source
252
226
    void visitSmallStringTable() {
253
226
      align(buf);
254
226
      f.stringTableEntries =
255
226
          castArrayRef<SmallStringTableEntry>(buf, h->stringCount, end);
256
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitSmallStringTable()
257
258
226
    void visitOverflowStringTable() {
259
226
      align(buf);
260
226
      f.stringTableOverflowEntries = castArrayRef<OverflowStringTableEntry>(
261
226
          buf, h->overflowStringCount, end);
262
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitOverflowStringTable()
Line
Count
Source
258
226
    void visitOverflowStringTable() {
259
226
      align(buf);
260
226
      f.stringTableOverflowEntries = castArrayRef<OverflowStringTableEntry>(
261
226
          buf, h->overflowStringCount, end);
262
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitOverflowStringTable()
263
264
226
    void visitStringStorage() {
265
226
      align(buf);
266
226
      f.stringStorage =
267
226
          castArrayRef<unsigned char>(buf, h->stringStorageSize, end);
268
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitStringStorage()
Line
Count
Source
264
226
    void visitStringStorage() {
265
226
      align(buf);
266
226
      f.stringStorage =
267
226
          castArrayRef<unsigned char>(buf, h->stringStorageSize, end);
268
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitStringStorage()
269
226
    void visitArrayBuffer() {
270
226
      align(buf);
271
226
      f.arrayBuffer = castArrayRef<unsigned char>(buf, h->arrayBufferSize, end);
272
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitArrayBuffer()
Line
Count
Source
269
226
    void visitArrayBuffer() {
270
226
      align(buf);
271
226
      f.arrayBuffer = castArrayRef<unsigned char>(buf, h->arrayBufferSize, end);
272
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitArrayBuffer()
273
226
    void visitObjectKeyBuffer() {
274
226
      align(buf);
275
226
      f.objKeyBuffer =
276
226
          castArrayRef<unsigned char>(buf, h->objKeyBufferSize, end);
277
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitObjectKeyBuffer()
Line
Count
Source
273
226
    void visitObjectKeyBuffer() {
274
226
      align(buf);
275
226
      f.objKeyBuffer =
276
226
          castArrayRef<unsigned char>(buf, h->objKeyBufferSize, end);
277
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitObjectKeyBuffer()
278
226
    void visitObjectValueBuffer() {
279
226
      align(buf);
280
226
      f.objValueBuffer =
281
226
          castArrayRef<unsigned char>(buf, h->objValueBufferSize, end);
282
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitObjectValueBuffer()
Line
Count
Source
278
226
    void visitObjectValueBuffer() {
279
226
      align(buf);
280
226
      f.objValueBuffer =
281
226
          castArrayRef<unsigned char>(buf, h->objValueBufferSize, end);
282
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitObjectValueBuffer()
283
226
    void visitBigIntTable() {
284
226
      align(buf);
285
226
      f.bigIntTable =
286
226
          castArrayRef<bigint::BigIntTableEntry>(buf, h->bigIntCount, end);
287
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitBigIntTable()
Line
Count
Source
283
226
    void visitBigIntTable() {
284
226
      align(buf);
285
226
      f.bigIntTable =
286
226
          castArrayRef<bigint::BigIntTableEntry>(buf, h->bigIntCount, end);
287
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitBigIntTable()
288
226
    void visitBigIntStorage() {
289
226
      align(buf);
290
226
      f.bigIntStorage =
291
226
          castArrayRef<unsigned char>(buf, h->bigIntStorageSize, end);
292
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitBigIntStorage()
Line
Count
Source
288
226
    void visitBigIntStorage() {
289
226
      align(buf);
290
226
      f.bigIntStorage =
291
226
          castArrayRef<unsigned char>(buf, h->bigIntStorageSize, end);
292
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitBigIntStorage()
293
226
    void visitRegExpTable() {
294
226
      align(buf);
295
226
      f.regExpTable = castArrayRef<RegExpTableEntry>(buf, h->regExpCount, end);
296
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitRegExpTable()
Line
Count
Source
293
226
    void visitRegExpTable() {
294
226
      align(buf);
295
226
      f.regExpTable = castArrayRef<RegExpTableEntry>(buf, h->regExpCount, end);
296
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitRegExpTable()
297
226
    void visitRegExpStorage() {
298
226
      align(buf);
299
226
      f.regExpStorage =
300
226
          castArrayRef<unsigned char>(buf, h->regExpStorageSize, end);
301
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitRegExpStorage()
Line
Count
Source
297
226
    void visitRegExpStorage() {
298
226
      align(buf);
299
226
      f.regExpStorage =
300
226
          castArrayRef<unsigned char>(buf, h->regExpStorageSize, end);
301
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitRegExpStorage()
302
226
    void visitCJSModuleTable() {
303
226
      align(buf);
304
226
      if (h->options.cjsModulesStaticallyResolved) {
305
        // Modules have been statically resolved.
306
0
        f.cjsModuleTableStatic = castArrayRef<std::pair<uint32_t, uint32_t>>(
307
0
            buf, h->cjsModuleCount, end);
308
226
      } else {
309
        // Modules are not resolved, use the filename -> function ID mapping.
310
226
        f.cjsModuleTable = castArrayRef<std::pair<uint32_t, uint32_t>>(
311
226
            buf, h->cjsModuleCount, end);
312
226
      }
313
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitCJSModuleTable()
Line
Count
Source
302
226
    void visitCJSModuleTable() {
303
226
      align(buf);
304
226
      if (h->options.cjsModulesStaticallyResolved) {
305
        // Modules have been statically resolved.
306
0
        f.cjsModuleTableStatic = castArrayRef<std::pair<uint32_t, uint32_t>>(
307
0
            buf, h->cjsModuleCount, end);
308
226
      } else {
309
        // Modules are not resolved, use the filename -> function ID mapping.
310
226
        f.cjsModuleTable = castArrayRef<std::pair<uint32_t, uint32_t>>(
311
226
            buf, h->cjsModuleCount, end);
312
226
      }
313
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitCJSModuleTable()
314
226
    void visitFunctionSourceTable() {
315
226
      align(buf);
316
226
      f.functionSourceTable = castArrayRef<std::pair<uint32_t, uint32_t>>(
317
226
          buf, h->functionSourceCount, end);
318
226
    }
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitFunctionSourceTable()
Line
Count
Source
314
226
    void visitFunctionSourceTable() {
315
226
      align(buf);
316
226
      f.functionSourceTable = castArrayRef<std::pair<uint32_t, uint32_t>>(
317
226
          buf, h->functionSourceCount, end);
318
226
    }
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)::BytecodeFileFieldsPopulator::visitFunctionSourceTable()
319
226
  };
320
321
226
  BytecodeFileFieldsPopulator populator{*this, buffer.data(), buffer.end()};
322
226
  visitBytecodeSegmentsInOrder(populator);
323
226
  return true;
324
226
}
hermes::hbc::BytecodeFileFields<false>::populateFromBuffer(llvh::ArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)
Line
Count
Source
206
226
    BytecodeForm form) {
207
226
  if (!sanityCheck(buffer, form, outError)) {
208
0
    return false;
209
0
  }
210
211
  // Helper type which populates a BytecodeFileFields. This is nested inside the
212
  // function so we can leverage BytecodeFileFields template types.
213
226
  struct BytecodeFileFieldsPopulator {
214
    /// The fields being populated.
215
226
    BytecodeFileFields &f;
216
217
    /// Current buffer position.
218
226
    Pointer<uint8_t> buf;
219
220
    /// A pointer to the bytecode file header.
221
226
    const BytecodeFileHeader *h;
222
223
    /// End of buffer.
224
226
    const uint8_t *end;
225
226
226
    BytecodeFileFieldsPopulator(
227
226
        BytecodeFileFields &fields,
228
226
        Pointer<uint8_t> buffer,
229
226
        const uint8_t *bufEnd)
230
226
        : f(fields), buf(buffer), end(bufEnd) {
231
226
      f.header = castData<BytecodeFileHeader>(buf);
232
226
      h = f.header;
233
226
    }
234
235
226
    void visitFunctionHeaders() {
236
226
      align(buf);
237
226
      f.functionHeaders =
238
226
          castArrayRef<SmallFuncHeader>(buf, h->functionCount, end);
239
226
    }
240
241
226
    void visitStringKinds() {
242
226
      align(buf);
243
226
      f.stringKinds =
244
226
          castArrayRef<StringKind::Entry>(buf, h->stringKindCount, end);
245
226
    }
246
247
226
    void visitIdentifierHashes() {
248
226
      align(buf);
249
226
      f.identifierHashes = castArrayRef<uint32_t>(buf, h->identifierCount, end);
250
226
    }
251
252
226
    void visitSmallStringTable() {
253
226
      align(buf);
254
226
      f.stringTableEntries =
255
226
          castArrayRef<SmallStringTableEntry>(buf, h->stringCount, end);
256
226
    }
257
258
226
    void visitOverflowStringTable() {
259
226
      align(buf);
260
226
      f.stringTableOverflowEntries = castArrayRef<OverflowStringTableEntry>(
261
226
          buf, h->overflowStringCount, end);
262
226
    }
263
264
226
    void visitStringStorage() {
265
226
      align(buf);
266
226
      f.stringStorage =
267
226
          castArrayRef<unsigned char>(buf, h->stringStorageSize, end);
268
226
    }
269
226
    void visitArrayBuffer() {
270
226
      align(buf);
271
226
      f.arrayBuffer = castArrayRef<unsigned char>(buf, h->arrayBufferSize, end);
272
226
    }
273
226
    void visitObjectKeyBuffer() {
274
226
      align(buf);
275
226
      f.objKeyBuffer =
276
226
          castArrayRef<unsigned char>(buf, h->objKeyBufferSize, end);
277
226
    }
278
226
    void visitObjectValueBuffer() {
279
226
      align(buf);
280
226
      f.objValueBuffer =
281
226
          castArrayRef<unsigned char>(buf, h->objValueBufferSize, end);
282
226
    }
283
226
    void visitBigIntTable() {
284
226
      align(buf);
285
226
      f.bigIntTable =
286
226
          castArrayRef<bigint::BigIntTableEntry>(buf, h->bigIntCount, end);
287
226
    }
288
226
    void visitBigIntStorage() {
289
226
      align(buf);
290
226
      f.bigIntStorage =
291
226
          castArrayRef<unsigned char>(buf, h->bigIntStorageSize, end);
292
226
    }
293
226
    void visitRegExpTable() {
294
226
      align(buf);
295
226
      f.regExpTable = castArrayRef<RegExpTableEntry>(buf, h->regExpCount, end);
296
226
    }
297
226
    void visitRegExpStorage() {
298
226
      align(buf);
299
226
      f.regExpStorage =
300
226
          castArrayRef<unsigned char>(buf, h->regExpStorageSize, end);
301
226
    }
302
226
    void visitCJSModuleTable() {
303
226
      align(buf);
304
226
      if (h->options.cjsModulesStaticallyResolved) {
305
        // Modules have been statically resolved.
306
226
        f.cjsModuleTableStatic = castArrayRef<std::pair<uint32_t, uint32_t>>(
307
226
            buf, h->cjsModuleCount, end);
308
226
      } else {
309
        // Modules are not resolved, use the filename -> function ID mapping.
310
226
        f.cjsModuleTable = castArrayRef<std::pair<uint32_t, uint32_t>>(
311
226
            buf, h->cjsModuleCount, end);
312
226
      }
313
226
    }
314
226
    void visitFunctionSourceTable() {
315
226
      align(buf);
316
226
      f.functionSourceTable = castArrayRef<std::pair<uint32_t, uint32_t>>(
317
226
          buf, h->functionSourceCount, end);
318
226
    }
319
226
  };
320
321
226
  BytecodeFileFieldsPopulator populator{*this, buffer.data(), buffer.end()};
322
226
  visitBytecodeSegmentsInOrder(populator);
323
226
  return true;
324
226
}
Unexecuted instantiation: hermes::hbc::BytecodeFileFields<true>::populateFromBuffer(llvh::MutableArrayRef<unsigned char>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, hermes::hbc::BytecodeForm)
325
326
// Explicit instantiations of BytecodeFileFields.
327
template struct BytecodeFileFields<false>;
328
template struct BytecodeFileFields<true>;
329
330
int32_t BCProviderBase::findCatchTargetOffset(
331
    uint32_t functionID,
332
41
    uint32_t exceptionOffset) const {
333
41
  auto exceptions = getExceptionTable(functionID);
334
1.52k
  for (unsigned i = 0, e = exceptions.size(); i < e; ++i) {
335
1.48k
    if (exceptions[i].start <= exceptionOffset &&
336
0
        exceptionOffset < exceptions[i].end) {
337
0
      return exceptions[i].target;
338
0
    }
339
1.48k
  }
340
  // No handler is found.
341
41
  return -1;
342
41
}
343
344
uint32_t BCProviderBase::getVirtualOffsetForFunction(
345
0
    uint32_t functionID) const {
346
0
  assert(functionID < functionCount_ && "Invalid functionID");
347
0
  uint32_t virtualOffset = 0;
348
0
  for (uint32_t i = 0; i < functionID; ++i) {
349
0
    virtualOffset += getFunctionHeader(i).bytecodeSizeInBytes();
350
0
  }
351
0
  return virtualOffset;
352
0
}
353
354
llvh::Optional<SourceMapTextLocation> BCProviderBase::getLocationForAddress(
355
    uint32_t funcId,
356
0
    uint32_t offsetInFunction) const {
357
0
  auto *funcDebugOffsets = getDebugOffsets(funcId);
358
0
  if (funcDebugOffsets != nullptr &&
359
0
      funcDebugOffsets->sourceLocations != hbc::DebugOffsets::NO_OFFSET) {
360
0
    const hbc::DebugInfo *debugInfo = getDebugInfo();
361
0
    assert(debugInfo != nullptr && "debugInfo is null");
362
0
    OptValue<DebugSourceLocation> locOpt = debugInfo->getLocationForAddress(
363
0
        funcDebugOffsets->sourceLocations, offsetInFunction);
364
0
    if (locOpt.hasValue()) {
365
0
      DebugSourceLocation loc = locOpt.getValue();
366
0
      std::string fileName = debugInfo->getFilenameByID(loc.filenameId);
367
0
      return SourceMapTextLocation{std::move(fileName), loc.line, loc.column};
368
0
    }
369
0
  }
370
0
  return llvh::None;
371
0
}
372
373
/// Read [data, data + size) sequentially into the OS page cache, but
374
/// abort ASAP if another thread sets \p abortFlag.
375
static void
376
0
warmup(const uint8_t *data, uint32_t size, std::atomic<bool> *abortFlag) {
377
  // The readahead/madvise syscalls are not always enough, so actually read
378
  // a byte from every page in the range.
379
0
  const uint32_t PS = oscompat::page_size();
380
  // Check abort flag every this many bytes, to ensure timely termination.
381
0
  const uint32_t kAbortCheckInterval = 64 * PS;
382
0
  uint32_t nextAbortCheckPoint = kAbortCheckInterval;
383
0
  for (uint32_t i = 0; i < size; i += PS) {
384
    // volatile to prevent the compiler from optimizing the read away.
385
0
    (void)(((volatile const uint8_t *)data)[i]);
386
0
    if (i >= nextAbortCheckPoint) {
387
0
      if (abortFlag->load(std::memory_order_acquire)) {
388
0
        return;
389
0
      }
390
0
      nextAbortCheckPoint += kAbortCheckInterval;
391
0
    }
392
0
  }
393
0
}
394
395
226
void BCProviderFromBuffer::stopWarmup() {
396
226
  if (warmupThread_) {
397
0
    warmupAbortFlag_.store(true, std::memory_order_release);
398
0
    warmupThread_->join();
399
0
    warmupThread_.reset();
400
0
  }
401
226
}
402
403
0
void BCProviderFromBuffer::startWarmup(uint8_t percent) {
404
0
  if (!warmupThread_) {
405
0
    uint32_t warmupSize = buffer_->size();
406
0
    assert(percent <= 100);
407
0
    if (percent < 100) {
408
0
      warmupSize = (uint64_t)warmupSize * percent / 100;
409
0
    }
410
0
    if (warmupSize > 0) {
411
0
      warmupThread_ =
412
0
          std::thread(warmup, buffer_->data(), warmupSize, &warmupAbortFlag_);
413
0
    }
414
0
  }
415
0
}
416
417
namespace {
418
419
/// Cast a pointer of any type to a uint8_t pointer.
420
template <typename T>
421
0
constexpr uint8_t *rawptr_cast(T *p) {
422
0
  return const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(p));
423
0
}
Unexecuted instantiation: BytecodeDataProvider.cpp:unsigned char* hermes::hbc::(anonymous namespace)::rawptr_cast<unsigned char const>(unsigned char const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:unsigned char* hermes::hbc::(anonymous namespace)::rawptr_cast<hermes::StringKind::Entry const>(hermes::StringKind::Entry const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:unsigned char* hermes::hbc::(anonymous namespace)::rawptr_cast<unsigned int const>(unsigned int const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:unsigned char* hermes::hbc::(anonymous namespace)::rawptr_cast<hermes::hbc::SmallStringTableEntry const>(hermes::hbc::SmallStringTableEntry const*)
Unexecuted instantiation: BytecodeDataProvider.cpp:unsigned char* hermes::hbc::(anonymous namespace)::rawptr_cast<hermes::hbc::OverflowStringTableEntry const>(hermes::hbc::OverflowStringTableEntry const*)
424
425
/// Align \p *ptr down to the start of the page it is pointing in to, and
426
/// simultaneously adjust \p *byteLen up by the amount the ptr was shifted down
427
/// by.
428
0
inline void pageAlignDown(uint8_t **ptr, size_t &byteLen) {
429
0
  const auto PS = oscompat::page_size();
430
431
0
  auto orig = *ptr;
432
0
  *ptr = reinterpret_cast<uint8_t *>(llvh::alignAddr(*ptr + 1, PS) - PS);
433
0
  byteLen += orig - *ptr;
434
0
}
435
436
#ifndef NDEBUG
437
438
/// Returns the total size of all array contents in bytes.
439
0
constexpr size_t totalByteSize() {
440
0
  return 0;
441
0
}
442
443
template <typename T, typename... Ts>
444
constexpr size_t totalByteSize(
445
    llvh::ArrayRef<T> arr,
446
0
    llvh::ArrayRef<Ts>... rest) {
447
0
  return sizeof(arr[0]) * arr.size() + totalByteSize(rest...);
448
0
}
Unexecuted instantiation: BytecodeDataProvider.cpp:unsigned long hermes::hbc::(anonymous namespace)::totalByteSize<hermes::StringKind::Entry, unsigned int, hermes::hbc::SmallStringTableEntry, hermes::hbc::OverflowStringTableEntry>(llvh::ArrayRef<hermes::StringKind::Entry>, llvh::ArrayRef<unsigned int>, llvh::ArrayRef<hermes::hbc::SmallStringTableEntry>, llvh::ArrayRef<hermes::hbc::OverflowStringTableEntry>)
Unexecuted instantiation: BytecodeDataProvider.cpp:unsigned long hermes::hbc::(anonymous namespace)::totalByteSize<unsigned int, hermes::hbc::SmallStringTableEntry, hermes::hbc::OverflowStringTableEntry>(llvh::ArrayRef<unsigned int>, llvh::ArrayRef<hermes::hbc::SmallStringTableEntry>, llvh::ArrayRef<hermes::hbc::OverflowStringTableEntry>)
Unexecuted instantiation: BytecodeDataProvider.cpp:unsigned long hermes::hbc::(anonymous namespace)::totalByteSize<hermes::hbc::SmallStringTableEntry, hermes::hbc::OverflowStringTableEntry>(llvh::ArrayRef<hermes::hbc::SmallStringTableEntry>, llvh::ArrayRef<hermes::hbc::OverflowStringTableEntry>)
Unexecuted instantiation: BytecodeDataProvider.cpp:unsigned long hermes::hbc::(anonymous namespace)::totalByteSize<hermes::hbc::OverflowStringTableEntry>(llvh::ArrayRef<hermes::hbc::OverflowStringTableEntry>)
449
450
#endif
451
452
} // namespace
453
454
0
void BCProviderFromBuffer::madvise(oscompat::MAdvice advice) {
455
0
  (void)oscompat::vm_madvise(
456
0
      rawptr_cast(buffer_->data()), buffer_->size(), advice);
457
0
}
458
459
#define ASSERT_BOUNDED(LO, ARRAY, HI)                                       \
460
0
  assert(                                                                   \
461
0
      LO <= rawptr_cast(ARRAY.begin()) && rawptr_cast(ARRAY.end()) <= HI && \
462
0
      #ARRAY " not fully contained.")
463
464
#define ASSERT_TOTAL_ARRAY_LEN(LEN, ...) \
465
0
  assert(LEN == totalByteSize(__VA_ARGS__) && "Mismatched length of region")
466
467
0
void BCProviderFromBuffer::adviseStringTableSequential() {
468
0
  llvh::ArrayRef<SmallStringTableEntry> smallStringTableEntries{
469
0
      stringTableEntries_, stringCount_};
470
471
0
  auto *start = rawptr_cast(stringKinds_.begin());
472
0
  auto *end = rawptr_cast(stringStorage_.begin());
473
0
  size_t adviceLength = end - start;
474
475
0
  ASSERT_BOUNDED(start, stringKinds_, end);
476
0
  ASSERT_BOUNDED(start, identifierHashes_, end);
477
0
  ASSERT_BOUNDED(start, smallStringTableEntries, end);
478
0
  ASSERT_BOUNDED(start, overflowStringTableEntries_, end);
479
480
0
  ASSERT_TOTAL_ARRAY_LEN(
481
0
      adviceLength,
482
0
      stringKinds_,
483
0
      identifierHashes_,
484
0
      smallStringTableEntries,
485
0
      overflowStringTableEntries_);
486
487
0
  pageAlignDown(&start, adviceLength);
488
0
  oscompat::vm_madvise(start, adviceLength, oscompat::MAdvice::Sequential);
489
0
}
490
491
0
void BCProviderFromBuffer::adviseStringTableRandom() {
492
0
  llvh::ArrayRef<SmallStringTableEntry> smallStringTableEntries{
493
0
      stringTableEntries_, stringCount_};
494
495
  // We only advise the small string table entries, overflow string table
496
  // entries and storage.  We do not give advice about the identifier
497
  // hashes or string kinds because they are not referred to after
498
  // initialisation.
499
500
0
  auto *tableStart = rawptr_cast(stringTableEntries_);
501
0
  auto *tableEnd = rawptr_cast(overflowStringTableEntries_.end());
502
0
  size_t tableLength = tableEnd - tableStart;
503
504
0
  auto *storageStart = rawptr_cast(stringStorage_.begin());
505
0
  size_t storageLength = stringStorage_.size();
506
507
0
  ASSERT_BOUNDED(tableStart, smallStringTableEntries, tableEnd);
508
0
  ASSERT_BOUNDED(tableStart, overflowStringTableEntries_, tableEnd);
509
510
0
  ASSERT_TOTAL_ARRAY_LEN(
511
0
      tableLength, smallStringTableEntries, overflowStringTableEntries_);
512
513
0
  pageAlignDown(&tableStart, tableLength);
514
0
  pageAlignDown(&storageStart, storageLength);
515
0
  oscompat::vm_madvise(tableStart, tableLength, oscompat::MAdvice::Random);
516
0
  oscompat::vm_madvise(storageStart, storageLength, oscompat::MAdvice::Random);
517
0
}
518
519
0
void BCProviderFromBuffer::willNeedStringTable() {
520
0
  llvh::ArrayRef<SmallStringTableEntry> smallStringTableEntries{
521
0
      stringTableEntries_, stringCount_};
522
523
0
  auto *start = rawptr_cast(stringKinds_.begin());
524
0
  auto *end = rawptr_cast(overflowStringTableEntries_.end());
525
0
  size_t prefetchLength = end - start;
526
527
0
  ASSERT_BOUNDED(start, stringKinds_, end);
528
0
  ASSERT_BOUNDED(start, identifierHashes_, end);
529
0
  ASSERT_BOUNDED(start, smallStringTableEntries, end);
530
0
  ASSERT_BOUNDED(start, overflowStringTableEntries_, end);
531
532
0
  ASSERT_TOTAL_ARRAY_LEN(
533
0
      prefetchLength,
534
0
      stringKinds_,
535
0
      identifierHashes_,
536
0
      smallStringTableEntries,
537
0
      overflowStringTableEntries_);
538
539
0
  pageAlignDown(&start, prefetchLength);
540
0
  oscompat::vm_prefetch(start, prefetchLength);
541
0
}
542
543
#undef ASSERT_BOUNDED
544
#undef ASSERT_TOTAL_ARRAY_LEN
545
546
0
void BCProviderFromBuffer::startPageAccessTracker() {
547
0
  auto size = buffer_->size();
548
0
  if (!tracker_) {
549
0
    tracker_ =
550
0
        PageAccessTracker::create(const_cast<uint8_t *>(bufferPtr_), size);
551
0
  }
552
0
}
553
554
BCProviderFromBuffer::BCProviderFromBuffer(
555
    std::unique_ptr<const Buffer> buffer,
556
    BytecodeForm form)
557
226
    : buffer_(std::move(buffer)),
558
226
      bufferPtr_(buffer_->data()),
559
226
      end_(bufferPtr_ + buffer_->size()) {
560
226
  ConstBytecodeFileFields fields;
561
226
  if (!fields.populateFromBuffer(
562
226
          {bufferPtr_, buffer_->size()}, &errstr_, form)) {
563
0
    return;
564
0
  }
565
226
  const auto *fileHeader = fields.header;
566
226
  options_ = fileHeader->options;
567
226
  functionCount_ = fileHeader->functionCount;
568
226
  globalFunctionIndex_ = fileHeader->globalCodeIndex;
569
226
  debugInfoOffset_ = fileHeader->debugInfoOffset;
570
226
  functionHeaders_ = fields.functionHeaders.data();
571
226
  stringKinds_ = fields.stringKinds;
572
226
  identifierHashes_ = fields.identifierHashes;
573
226
  stringCount_ = fileHeader->stringCount;
574
226
  stringTableEntries_ = fields.stringTableEntries.data();
575
226
  overflowStringTableEntries_ = fields.stringTableOverflowEntries;
576
226
  stringStorage_ = fields.stringStorage;
577
226
  arrayBuffer_ = fields.arrayBuffer;
578
226
  objKeyBuffer_ = fields.objKeyBuffer;
579
226
  objValueBuffer_ = fields.objValueBuffer;
580
226
  bigIntTable_ = fields.bigIntTable;
581
226
  bigIntStorage_ = fields.bigIntStorage;
582
226
  regExpTable_ = fields.regExpTable;
583
226
  regExpStorage_ = fields.regExpStorage;
584
226
  segmentID_ = fileHeader->segmentID;
585
226
  cjsModuleTable_ = fields.cjsModuleTable;
586
226
  cjsModuleTableStatic_ = fields.cjsModuleTableStatic;
587
226
  functionSourceTable_ = fields.functionSourceTable;
588
226
}
589
590
0
llvh::ArrayRef<uint8_t> BCProviderFromBuffer::getEpilogue() const {
591
0
  return BCProviderFromBuffer::getEpilogueFromBytecode(
592
0
      llvh::ArrayRef<uint8_t>(bufferPtr_, buffer_->size()));
593
0
}
594
595
0
SHA1 BCProviderFromBuffer::getSourceHash() const {
596
0
  return BCProviderFromBuffer::getSourceHashFromBytecode(
597
0
      llvh::ArrayRef<uint8_t>(bufferPtr_, buffer_->size()));
598
0
}
599
600
llvh::ArrayRef<uint8_t> BCProviderFromBuffer::getEpilogueFromBytecode(
601
0
    llvh::ArrayRef<uint8_t> buffer) {
602
0
  const uint8_t *p = buffer.data();
603
0
  const auto *fileHeader = castData<hbc::BytecodeFileHeader>(p);
604
0
  const auto *begin = buffer.data() + fileHeader->fileLength;
605
0
  const auto *end = buffer.data() + buffer.size();
606
0
  return llvh::ArrayRef<uint8_t>(begin, end);
607
0
}
608
609
SHA1 BCProviderFromBuffer::getSourceHashFromBytecode(
610
0
    llvh::ArrayRef<uint8_t> buffer) {
611
0
  SHA1 hash;
612
0
  const uint8_t *p = buffer.data();
613
0
  const auto *fileHeader = castData<hbc::BytecodeFileHeader>(p);
614
0
  std::copy(
615
0
      fileHeader->sourceHash,
616
0
      fileHeader->sourceHash + SHA1_NUM_BYTES,
617
0
      hash.begin());
618
0
  return hash;
619
0
}
620
621
0
void BCProviderFromBuffer::createDebugInfo() {
622
0
  const auto *buf = bufferPtr_ + debugInfoOffset_;
623
0
  const auto *header = castData<hbc::DebugInfoHeader>(buf);
624
625
0
  auto filenameTable =
626
0
      castArrayRef<StringTableEntry>(buf, header->filenameCount, end_);
627
0
  auto filenameStorage =
628
0
      castArrayRef<unsigned char>(buf, header->filenameStorageSize, end_);
629
630
0
  hbc::DebugInfo::DebugFileRegionList files;
631
0
  for (unsigned i = 0; i < header->fileRegionCount; i++) {
632
0
    const auto *region = castData<hbc::DebugFileRegion>(buf);
633
0
    files.push_back(*region);
634
0
  }
635
0
  debugInfo_ = new hbc::DebugInfo(
636
0
      filenameTable,
637
0
      filenameStorage,
638
0
      std::move(files),
639
0
      header->scopeDescDataOffset,
640
0
      header->textifiedCalleeOffset,
641
0
      header->stringTableOffset,
642
0
      hbc::StreamVector<uint8_t>{buf, header->debugDataSize});
643
0
}
644
645
std::pair<
646
    llvh::ArrayRef<hbc::HBCExceptionHandlerInfo>,
647
    const hbc::DebugOffsets *>
648
BCProviderFromBuffer::getExceptionTableAndDebugOffsets(
649
0
    uint32_t functionID) const {
650
0
  const auto &header = functionHeaders_[functionID];
651
0
  const auto *buf = bufferPtr_;
652
653
  // Get the correct offset for function info depending on overflow flag. Skip
654
  // large header if any (we don't need to parse it, since we're only using
655
  // flags below, which are also valid for overflowed small headers).
656
0
  if (header.flags.overflowed) {
657
0
    buf += header.getLargeHeaderOffset();
658
0
    buf += sizeof(hbc::FunctionHeader);
659
0
  } else {
660
0
    buf += header.infoOffset;
661
0
  }
662
663
  // Deserialize exception table.
664
0
  llvh::ArrayRef<hbc::HBCExceptionHandlerInfo> exceptionTable{};
665
0
  if (header.flags.hasExceptionHandler) {
666
0
    align(buf);
667
0
    const auto *exceptionHeader =
668
0
        castData<hbc::ExceptionHandlerTableHeader>(buf);
669
0
    exceptionTable = castArrayRef<hbc::HBCExceptionHandlerInfo>(
670
0
        buf, exceptionHeader->count, end_);
671
0
  }
672
673
  // Deserialize debug offsets.
674
0
  const hbc::DebugOffsets *debugOffsets = nullptr;
675
0
  if (header.flags.hasDebugInfo) {
676
0
    align(buf);
677
0
    debugOffsets = castData<hbc::DebugOffsets>(buf);
678
0
  }
679
0
  return {exceptionTable, debugOffsets};
680
0
}
681
682
namespace {
683
0
void prefetchRegion(const uint8_t *p, size_t sz) {
684
  // Extend start of region down to a page boundary. The region is still inside
685
  // the file since we assert below that the file starts on a page boundary.
686
0
  auto PS = oscompat::page_size();
687
0
  auto roundDownDelta = reinterpret_cast<uintptr_t>(p) & (PS - 1);
688
0
  oscompat::vm_prefetch(
689
0
      const_cast<uint8_t *>(p - roundDownDelta), sz + roundDownDelta);
690
0
}
691
} // namespace
692
693
0
void BCProviderFromBuffer::prefetch(llvh::ArrayRef<uint8_t> aref) {
694
  // We require file start be page-aligned so we can safely round down to page
695
  // size in prefetchRegion.
696
0
  assert(
697
0
      reinterpret_cast<uintptr_t>(aref.data()) % oscompat::page_size() == 0 &&
698
0
      "Precondition: pointer is page-aligned.");
699
0
  ConstBytecodeFileFields fields;
700
0
  std::string errstr;
701
0
  if (!fields.populateFromBuffer(aref, &errstr)) {
702
0
#ifndef NDEBUG
703
0
    hermes_fatal(errstr);
704
#else
705
    return;
706
#endif
707
0
  }
708
0
  const hbc::BytecodeFileHeader *fileHeader = fields.header;
709
710
  // String table.
711
0
  auto stringCount = fileHeader->stringCount;
712
0
  const hbc::SmallStringTableEntry *stringTableEntries =
713
0
      fields.stringTableEntries.data();
714
0
  prefetchRegion(
715
0
      reinterpret_cast<const uint8_t *>(stringTableEntries),
716
0
      stringCount * sizeof(*stringTableEntries));
717
718
  // Global function bytecode.
719
0
  auto globalFunctionIndex = fileHeader->globalCodeIndex;
720
0
  auto functionHeaders = fields.functionHeaders.data();
721
0
  const SmallFuncHeader &globalSmall = functionHeaders[globalFunctionIndex];
722
0
  RuntimeFunctionHeader global = globalSmall.flags.overflowed
723
0
      ? RuntimeFunctionHeader(
724
0
            reinterpret_cast<const hbc::FunctionHeader *>(
725
0
                aref.data() + globalSmall.getLargeHeaderOffset()))
726
0
      : RuntimeFunctionHeader(&globalSmall);
727
0
  prefetchRegion(aref.data() + global.offset(), global.bytecodeSizeInBytes());
728
0
}
729
730
bool BCProviderFromBuffer::bytecodeStreamSanityCheck(
731
    llvh::ArrayRef<uint8_t> aref,
732
0
    std::string *errorMessage) {
733
0
  return sanityCheck(aref, BytecodeForm::Execution, errorMessage);
734
0
}
735
736
0
bool BCProviderFromBuffer::bytecodeHashIsValid(llvh::ArrayRef<uint8_t> aref) {
737
0
  return hashIsValid(aref);
738
0
}
739
740
void BCProviderFromBuffer::updateBytecodeHash(
741
0
    llvh::MutableArrayRef<uint8_t> aref) {
742
0
  updateHash(aref);
743
0
}
744
745
} // namespace hbc
746
} // namespace hermes