| // Copyright 2014 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/snapshot/natives.h" |
| |
| #include "src/base/logging.h" |
| #include "src/snapshot/snapshot-source-sink.h" |
| #include "src/utils/vector.h" |
| |
| #ifndef V8_USE_EXTERNAL_STARTUP_DATA |
| #error natives-external.cc is used only for the external snapshot build. |
| #endif // V8_USE_EXTERNAL_STARTUP_DATA |
| |
| |
| namespace v8 { |
| namespace internal { |
| |
| |
| /** |
| * NativesStore stores the 'native' (builtin) JS libraries. |
| * |
| * NativesStore needs to be initialized before using V8, usually by the |
| * embedder calling v8::SetNativesDataBlob, which calls SetNativesFromFile |
| * below. |
| */ |
| class NativesStore { |
| public: |
| ~NativesStore() { |
| for (size_t i = 0; i < native_names_.size(); i++) { |
| native_names_[i].Dispose(); |
| } |
| } |
| |
| int GetBuiltinsCount() { return static_cast<int>(native_ids_.size()); } |
| |
| Vector<const char> GetScriptSource(int index) { |
| return native_source_[index]; |
| } |
| |
| Vector<const char> GetScriptName(int index) { return native_names_[index]; } |
| |
| int GetIndex(const char* id) { |
| for (int i = 0; i < static_cast<int>(native_ids_.size()); ++i) { |
| int native_id_length = native_ids_[i].length(); |
| if ((static_cast<int>(strlen(id)) == native_id_length) && |
| (strncmp(id, native_ids_[i].begin(), native_id_length) == 0)) { |
| return i; |
| } |
| } |
| UNREACHABLE(); |
| } |
| |
| Vector<const char> GetScriptsSource() { |
| UNREACHABLE(); // Not implemented. |
| } |
| |
| static NativesStore* MakeFromScriptsSource(SnapshotByteSource* source) { |
| NativesStore* store = new NativesStore; |
| |
| // We expect the libraries in the following format: |
| // int: # of sources. |
| // 2N blobs: N pairs of source name + actual source. |
| // Cobalt's manual cherry-pick of Chromium V8 change 1809374. |
| int library_count = source->GetIntSlow(); |
| for (int i = 0; i < library_count; ++i) { |
| store->ReadNameAndContentPair(source); |
| } |
| |
| return store; |
| } |
| |
| private: |
| NativesStore() = default; |
| |
| Vector<const char> NameFromId(const byte* id, int id_length) { |
| const char native[] = "native "; |
| const char extension[] = ".js"; |
| Vector<char> name(Vector<char>::New(id_length + sizeof(native) - 1 + |
| sizeof(extension) - 1)); |
| memcpy(name.begin(), native, sizeof(native) - 1); |
| memcpy(name.begin() + sizeof(native) - 1, id, id_length); |
| memcpy(name.begin() + sizeof(native) - 1 + id_length, extension, |
| sizeof(extension) - 1); |
| return Vector<const char>::cast(name); |
| } |
| |
| void ReadNameAndContentPair(SnapshotByteSource* bytes) { |
| const byte* id; |
| const byte* source; |
| int id_length = bytes->GetBlob(&id); |
| int source_length = bytes->GetBlob(&source); |
| native_ids_.emplace_back(reinterpret_cast<const char*>(id), id_length); |
| native_source_.emplace_back(reinterpret_cast<const char*>(source), |
| source_length); |
| native_names_.push_back(NameFromId(id, id_length)); |
| } |
| |
| std::vector<Vector<const char>> native_ids_; |
| std::vector<Vector<const char>> native_names_; |
| std::vector<Vector<const char>> native_source_; |
| |
| DISALLOW_COPY_AND_ASSIGN(NativesStore); |
| }; |
| |
| |
| template<NativeType type> |
| class NativesHolder { |
| public: |
| static NativesStore* get() { |
| CHECK(holder_); |
| return holder_; |
| } |
| static void set(NativesStore* store) { |
| CHECK(store); |
| holder_ = store; |
| } |
| static bool empty() { return holder_ == nullptr; } |
| static void Dispose() { |
| delete holder_; |
| holder_ = nullptr; |
| } |
| |
| private: |
| static NativesStore* holder_; |
| }; |
| |
| template <NativeType type> |
| NativesStore* NativesHolder<type>::holder_ = nullptr; |
| |
| // The natives blob. Memory is owned by caller. |
| static StartupData* natives_blob_ = nullptr; |
| |
| /** |
| * Read the Natives blob, as previously set by SetNativesFromFile. |
| */ |
| void ReadNatives() { |
| if (natives_blob_ && NativesHolder<EXTRAS>::empty()) { |
| SnapshotByteSource bytes(natives_blob_->data, natives_blob_->raw_size); |
| NativesHolder<EXTRAS>::set(NativesStore::MakeFromScriptsSource(&bytes)); |
| DCHECK(!bytes.HasMore()); |
| } |
| } |
| |
| |
| /** |
| * Set the Natives (library sources) blob, as generated by js2c + the build |
| * system. |
| */ |
| void SetNativesFromFile(StartupData* natives_blob) { |
| DCHECK(!natives_blob_); |
| DCHECK(natives_blob); |
| DCHECK(natives_blob->data); |
| DCHECK_GT(natives_blob->raw_size, 0); |
| |
| natives_blob_ = natives_blob; |
| ReadNatives(); |
| } |
| |
| |
| /** |
| * Release memory allocated by SetNativesFromFile. |
| */ |
| void DisposeNatives() { |
| NativesHolder<EXTRAS>::Dispose(); |
| } |
| |
| |
| // Implement NativesCollection<T> bsaed on NativesHolder + NativesStore. |
| // |
| // (The callers expect a purely static interface, since this is how the |
| // natives are usually compiled in. Since we implement them based on |
| // runtime content, we have to implement this indirection to offer |
| // a static interface.) |
| template<NativeType type> |
| int NativesCollection<type>::GetBuiltinsCount() { |
| return NativesHolder<type>::get()->GetBuiltinsCount(); |
| } |
| |
| template<NativeType type> |
| int NativesCollection<type>::GetIndex(const char* name) { |
| return NativesHolder<type>::get()->GetIndex(name); |
| } |
| |
| template <NativeType type> |
| Vector<const char> NativesCollection<type>::GetScriptSource(int index) { |
| return NativesHolder<type>::get()->GetScriptSource(index); |
| } |
| |
| template<NativeType type> |
| Vector<const char> NativesCollection<type>::GetScriptName(int index) { |
| return NativesHolder<type>::get()->GetScriptName(index); |
| } |
| |
| template <NativeType type> |
| Vector<const char> NativesCollection<type>::GetScriptsSource() { |
| return NativesHolder<type>::get()->GetScriptsSource(); |
| } |
| |
| |
| // Explicit template instantiations. |
| #define INSTANTIATE_TEMPLATES(T) \ |
| template int NativesCollection<T>::GetBuiltinsCount(); \ |
| template int NativesCollection<T>::GetIndex(const char* name); \ |
| template Vector<const char> NativesCollection<T>::GetScriptSource(int i); \ |
| template Vector<const char> NativesCollection<T>::GetScriptName(int i); \ |
| template Vector<const char> NativesCollection<T>::GetScriptsSource(); |
| INSTANTIATE_TEMPLATES(EXTRAS) |
| #undef INSTANTIATE_TEMPLATES |
| |
| } // namespace internal |
| } // namespace v8 |