// 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. int library_count = source->GetInt(); 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