/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 |