blob: 9cfb1e042b94281fb632db4ebe8f6bdc6978ccdf [file] [log] [blame]
// 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