| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 106dc61 commit 190596c
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -213,18 +213,18 @@ MaybeLocal<String> BuiltinLoader::LoadBuiltinSource(Isolate* isolate, | |||
| 213 | 213 | ||
| 214 | 214 | namespace { | |
| 215 | 215 | static Mutex externalized_builtins_mutex; | |
| 216 | - std::unordered_map<std::string, std::string> externalized_builtin_sources; | ||
| 216 | + std::unordered_map<std::string, std::unique_ptr<StaticExternalTwoByteResource>> | ||
| 217 | + externalized_builtin_sources; | ||
| 217 | 218 | } // namespace | |
| 218 | 219 | ||
| 219 | 220 | void BuiltinLoader::AddExternalizedBuiltin(const char* id, | |
| 220 | 221 | const char* filename) { | |
| 221 | - std::string source; | ||
| 222 | + StaticExternalTwoByteResource* resource; | ||
| 222 | 223 | { | |
| 223 | 224 | Mutex::ScopedLock lock(externalized_builtins_mutex); | |
| 224 | 225 | auto it = externalized_builtin_sources.find(id); | |
| 225 | - if (it != externalized_builtin_sources.end()) { | ||
| 226 | - source = it->second; | ||
| 227 | - } else { | ||
| 226 | + if (it == externalized_builtin_sources.end()) { | ||
| 227 | + std::string source; | ||
| 228 | 228 | int r = ReadFileSync(&source, filename); | |
| 229 | 229 | if (r != 0) { | |
| 230 | 230 | fprintf(stderr, | |
@@ -233,23 +233,29 @@ void BuiltinLoader::AddExternalizedBuiltin(const char* id, | |||
| 233 | 233 | filename); | |
| 234 | 234 | ABORT(); | |
| 235 | 235 | } | |
| 236 | - externalized_builtin_sources[id] = source; | ||
| 236 | + size_t expected_u16_length = | ||
| 237 | + simdutf::utf16_length_from_utf8(source.data(), source.length()); | ||
| 238 | + auto out = std::make_shared<std::vector<uint16_t>>(expected_u16_length); | ||
| 239 | + size_t u16_length = simdutf::convert_utf8_to_utf16( | ||
| 240 | + source.data(), | ||
| 241 | + source.length(), | ||
| 242 | + reinterpret_cast<char16_t*>(out->data())); | ||
| 243 | + out->resize(u16_length); | ||
| 244 | + | ||
| 245 | + auto result = externalized_builtin_sources.emplace( | ||
| 246 | + id, | ||
| 247 | + std::make_unique<StaticExternalTwoByteResource>( | ||
| 248 | + out->data(), out->size(), out)); | ||
| 249 | + CHECK(result.second); | ||
| 250 | + it = result.first; | ||
| 237 | 251 | } | |
| 252 | + // OK to get the raw pointer, since externalized_builtin_sources owns | ||
| 253 | + // the resource, resources are never removed from the map, and | ||
| 254 | + // externalized_builtin_sources has static lifetime. | ||
| 255 | + resource = it->second.get(); | ||
| 238 | 256 | } | |
| 239 | 257 | ||
| 240 | - Add(id, source); | ||
| 241 | - } | ||
| 242 | - | ||
| 243 | - bool BuiltinLoader::Add(const char* id, std::string_view utf8source) { | ||
| 244 | - size_t expected_u16_length = | ||
| 245 | - simdutf::utf16_length_from_utf8(utf8source.data(), utf8source.length()); | ||
| 246 | - auto out = std::make_shared<std::vector<uint16_t>>(expected_u16_length); | ||
| 247 | - size_t u16_length = | ||
| 248 | - simdutf::convert_utf8_to_utf16(utf8source.data(), | ||
| 249 | - utf8source.length(), | ||
| 250 | - reinterpret_cast<char16_t*>(out->data())); | ||
| 251 | - out->resize(u16_length); | ||
| 252 | - return Add(id, UnionBytes(out)); | ||
| 258 | + Add(id, UnionBytes(resource)); | ||
| 253 | 259 | } | |
| 254 | 260 | ||
| 255 | 261 | MaybeLocal<Function> BuiltinLoader::LookupAndCompileInternal( | |
@@ -719,6 +725,8 @@ void BuiltinLoader::RegisterExternalReferences( | |||
| 719 | 725 | registry->Register(CompileFunction); | |
| 720 | 726 | registry->Register(HasCachedBuiltins); | |
| 721 | 727 | registry->Register(SetInternalLoaders); | |
| 728 | + | ||
| 729 | + RegisterExternalReferencesForInternalizedBuiltinCode(registry); | ||
| 722 | 730 | } | |
| 723 | 731 | ||
| 724 | 732 | } // namespace builtins | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -10,6 +10,7 @@ | |||
| 10 | 10 | #include <set> | |
| 11 | 11 | #include <string> | |
| 12 | 12 | #include <vector> | |
| 13 | + #include "node_external_reference.h" | ||
| 13 | 14 | #include "node_mutex.h" | |
| 14 | 15 | #include "node_threadsafe_cow.h" | |
| 15 | 16 | #include "node_union_bytes.h" | |
@@ -30,6 +31,10 @@ using BuiltinCodeCacheMap = | |||
| 30 | 31 | std::unordered_map<std::string, | |
| 31 | 32 | std::unique_ptr<v8::ScriptCompiler::CachedData>>; | |
| 32 | 33 | ||
| 34 | + // Generated by tools/js2c.py as node_javascript.cc | ||
| 35 | + void RegisterExternalReferencesForInternalizedBuiltinCode( | ||
| 36 | + ExternalReferenceRegistry* registry); | ||
| 37 | + | ||
| 33 | 38 | struct CodeCacheInfo { | |
| 34 | 39 | std::string id; | |
| 35 | 40 | std::vector<uint8_t> data; | |
@@ -72,7 +77,6 @@ class NODE_EXTERN_PRIVATE BuiltinLoader { | |||
| 72 | 77 | v8::Local<v8::String> GetConfigString(v8::Isolate* isolate); | |
| 73 | 78 | bool Exists(const char* id); | |
| 74 | 79 | bool Add(const char* id, const UnionBytes& source); | |
| 75 | - bool Add(const char* id, std::string_view utf8source); | ||
| 76 | 80 | ||
| 77 | 81 | bool CompileAllBuiltins(v8::Local<v8::Context> context); | |
| 78 | 82 | void RefreshCodeCache(const std::vector<CodeCacheInfo>& in); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -50,7 +50,8 @@ class ExternalReferenceRegistry { | |||
| 50 | 50 | V(v8::IndexedPropertyDefinerCallback) \ | |
| 51 | 51 | V(v8::IndexedPropertyDeleterCallback) \ | |
| 52 | 52 | V(v8::IndexedPropertyQueryCallback) \ | |
| 53 | - V(v8::IndexedPropertyDescriptorCallback) | ||
| 53 | + V(v8::IndexedPropertyDescriptorCallback) \ | ||
| 54 | + V(const v8::String::ExternalStringResourceBase*) | ||
| 54 | 55 | ||
| 55 | 56 | #define V(ExternalReferenceType) \ | |
| 56 | 57 | void Register(ExternalReferenceType addr) { RegisterT(addr); } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,50 +4,74 @@ | |||
| 4 | 4 | ||
| 5 | 5 | #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS | |
| 6 | 6 | ||
| 7 | - // A union of const uint8_t* or const uint16_t* data that can be | ||
| 8 | - // turned into external v8::String when given an isolate. | ||
| 9 | - | ||
| 10 | 7 | #include "v8.h" | |
| 11 | 8 | ||
| 12 | 9 | namespace node { | |
| 13 | 10 | ||
| 11 | + // An external resource intended to be used with static lifetime. | ||
| 12 | + template <typename Char, typename IChar, typename Base> | ||
| 13 | + class StaticExternalByteResource : public Base { | ||
| 14 | + static_assert(sizeof(IChar) == sizeof(Char), | ||
| 15 | + "incompatible interface and internal pointers"); | ||
| 16 | + | ||
| 17 | + public: | ||
| 18 | + explicit StaticExternalByteResource(const Char* data, | ||
| 19 | + size_t length, | ||
| 20 | + std::shared_ptr<void> owning_ptr) | ||
| 21 | + : data_(data), length_(length), owning_ptr_(owning_ptr) {} | ||
| 22 | + | ||
| 23 | + const IChar* data() const override { | ||
| 24 | + return reinterpret_cast<const IChar*>(data_); | ||
| 25 | + } | ||
| 26 | + size_t length() const override { return length_; } | ||
| 27 | + | ||
| 28 | + void Dispose() override { | ||
| 29 | + // We ignore Dispose calls from V8, even if we "own" a resource via | ||
| 30 | + // owning_ptr_. All instantiations of this class are static or owned by a | ||
| 31 | + // static map, and will be destructed when static variables are destructed. | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + StaticExternalByteResource(const StaticExternalByteResource&) = delete; | ||
| 35 | + StaticExternalByteResource& operator=(const StaticExternalByteResource&) = | ||
| 36 | + delete; | ||
| 37 | + | ||
| 38 | + private: | ||
| 39 | + const Char* data_; | ||
| 40 | + const size_t length_; | ||
| 41 | + std::shared_ptr<void> owning_ptr_; | ||
| 42 | + }; | ||
| 43 | + | ||
| 44 | + using StaticExternalOneByteResource = | ||
| 45 | + StaticExternalByteResource<uint8_t, | ||
| 46 | + char, | ||
| 47 | + v8::String::ExternalOneByteStringResource>; | ||
| 48 | + using StaticExternalTwoByteResource = | ||
| 49 | + StaticExternalByteResource<uint16_t, | ||
| 50 | + uint16_t, | ||
| 51 | + v8::String::ExternalStringResource>; | ||
| 52 | + | ||
| 14 | 53 | // Similar to a v8::String, but it's independent from Isolates | |
| 15 | 54 | // and can be materialized in Isolates as external Strings | |
| 16 | 55 | // via ToStringChecked. | |
| 17 | 56 | class UnionBytes { | |
| 18 | 57 | public: | |
| 19 | - UnionBytes(const uint16_t* data, size_t length) | ||
| 20 | - : one_bytes_(nullptr), two_bytes_(data), length_(length) {} | ||
| 21 | - UnionBytes(const uint8_t* data, size_t length) | ||
| 22 | - : one_bytes_(data), two_bytes_(nullptr), length_(length) {} | ||
| 23 | - template <typename T> // T = uint8_t or uint16_t | ||
| 24 | - explicit UnionBytes(std::shared_ptr<std::vector</*const*/ T>> data) | ||
| 25 | - : UnionBytes(data->data(), data->size()) { | ||
| 26 | - owning_ptr_ = data; | ||
| 27 | - } | ||
| 58 | + explicit UnionBytes(StaticExternalOneByteResource* one_byte_resource) | ||
| 59 | + : one_byte_resource_(one_byte_resource), two_byte_resource_(nullptr) {} | ||
| 60 | + explicit UnionBytes(StaticExternalTwoByteResource* two_byte_resource) | ||
| 61 | + : one_byte_resource_(nullptr), two_byte_resource_(two_byte_resource) {} | ||
| 28 | 62 | ||
| 29 | 63 | UnionBytes(const UnionBytes&) = default; | |
| 30 | 64 | UnionBytes& operator=(const UnionBytes&) = default; | |
| 31 | 65 | UnionBytes(UnionBytes&&) = default; | |
| 32 | 66 | UnionBytes& operator=(UnionBytes&&) = default; | |
| 33 | 67 | ||
| 34 | - bool is_one_byte() const { return one_bytes_ != nullptr; } | ||
| 35 | - const uint16_t* two_bytes_data() const { | ||
| 36 | - CHECK_NOT_NULL(two_bytes_); | ||
| 37 | - return two_bytes_; | ||
| 38 | - } | ||
| 39 | - const uint8_t* one_bytes_data() const { | ||
| 40 | - CHECK_NOT_NULL(one_bytes_); | ||
| 41 | - return one_bytes_; | ||
| 42 | - } | ||
| 68 | + bool is_one_byte() const { return one_byte_resource_ != nullptr; } | ||
| 69 | + | ||
| 43 | 70 | v8::Local<v8::String> ToStringChecked(v8::Isolate* isolate) const; | |
| 44 | - size_t length() const { return length_; } | ||
| 45 | 71 | ||
| 46 | 72 | private: | |
| 47 | - const uint8_t* one_bytes_; | ||
| 48 | - const uint16_t* two_bytes_; | ||
| 49 | - size_t length_; | ||
| 50 | - std::shared_ptr<void> owning_ptr_; | ||
| 73 | + StaticExternalOneByteResource* one_byte_resource_; | ||
| 74 | + StaticExternalTwoByteResource* two_byte_resource_; | ||
| 51 | 75 | }; | |
| 52 | 76 | ||
| 53 | 77 | } // namespace node | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -606,65 +606,13 @@ void SetConstructorFunction(Isolate* isolate, | |||
| 606 | 606 | that->Set(name, tmpl); | |
| 607 | 607 | } | |
| 608 | 608 | ||
| 609 | - namespace { | ||
| 610 | - | ||
| 611 | - class NonOwningExternalOneByteResource | ||
| 612 | - : public v8::String::ExternalOneByteStringResource { | ||
| 613 | - public: | ||
| 614 | - explicit NonOwningExternalOneByteResource(const UnionBytes& source) | ||
| 615 | - : source_(source) {} | ||
| 616 | - ~NonOwningExternalOneByteResource() override = default; | ||
| 617 | - | ||
| 618 | - const char* data() const override { | ||
| 619 | - return reinterpret_cast<const char*>(source_.one_bytes_data()); | ||
| 620 | - } | ||
| 621 | - size_t length() const override { return source_.length(); } | ||
| 622 | - | ||
| 623 | - NonOwningExternalOneByteResource(const NonOwningExternalOneByteResource&) = | ||
| 624 | - delete; | ||
| 625 | - NonOwningExternalOneByteResource& operator=( | ||
| 626 | - const NonOwningExternalOneByteResource&) = delete; | ||
| 627 | - | ||
| 628 | - private: | ||
| 629 | - const UnionBytes source_; | ||
| 630 | - }; | ||
| 631 | - | ||
| 632 | - class NonOwningExternalTwoByteResource | ||
| 633 | - : public v8::String::ExternalStringResource { | ||
| 634 | - public: | ||
| 635 | - explicit NonOwningExternalTwoByteResource(const UnionBytes& source) | ||
| 636 | - : source_(source) {} | ||
| 637 | - ~NonOwningExternalTwoByteResource() override = default; | ||
| 638 | - | ||
| 639 | - const uint16_t* data() const override { return source_.two_bytes_data(); } | ||
| 640 | - size_t length() const override { return source_.length(); } | ||
| 641 | - | ||
| 642 | - NonOwningExternalTwoByteResource(const NonOwningExternalTwoByteResource&) = | ||
| 643 | - delete; | ||
| 644 | - NonOwningExternalTwoByteResource& operator=( | ||
| 645 | - const NonOwningExternalTwoByteResource&) = delete; | ||
| 646 | - | ||
| 647 | - private: | ||
| 648 | - const UnionBytes source_; | ||
| 649 | - }; | ||
| 650 | - | ||
| 651 | - } // anonymous namespace | ||
| 652 | - | ||
| 653 | 609 | Local<String> UnionBytes::ToStringChecked(Isolate* isolate) const { | |
| 654 | - if (UNLIKELY(length() == 0)) { | ||
| 655 | - // V8 requires non-null data pointers for empty external strings, | ||
| 656 | - // but we don't guarantee that. Solve this by not creating an | ||
| 657 | - // external string at all in that case. | ||
| 658 | - return String::Empty(isolate); | ||
| 659 | - } | ||
| 660 | 610 | if (is_one_byte()) { | |
| 661 | - NonOwningExternalOneByteResource* source = | ||
| 662 | - new NonOwningExternalOneByteResource(*this); | ||
| 663 | - return String::NewExternalOneByte(isolate, source).ToLocalChecked(); | ||
| 611 | + return String::NewExternalOneByte(isolate, one_byte_resource_) | ||
| 612 | + .ToLocalChecked(); | ||
| 664 | 613 | } else { | |
| 665 | - NonOwningExternalTwoByteResource* source = | ||
| 666 | - new NonOwningExternalTwoByteResource(*this); | ||
| 667 | - return String::NewExternalTwoByte(isolate, source).ToLocalChecked(); | ||
| 614 | + return String::NewExternalTwoByte(isolate, two_byte_resource_) | ||
| 615 | + .ToLocalChecked(); | ||
| 668 | 616 | } | |
| 669 | 617 | } | |
| 670 | 618 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments