// 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/list.h" #include "src/list-inl.h" #include "src/snapshot/snapshot-source-sink.h" #include "src/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 (int i = 0; i < native_names_.length(); i++) { native_names_[i].Dispose(); } } int GetBuiltinsCount() { return native_ids_.length(); } int GetDebuggerCount() { return debugger_count_; } Vector GetScriptSource(int index) { return native_source_[index]; } Vector GetScriptName(int index) { return native_names_[index]; } int GetIndex(const char* id) { for (int i = 0; i < native_ids_.length(); ++i) { int native_id_length = native_ids_[i].length(); if ((static_cast(strlen(id)) == native_id_length) && (strncmp(id, native_ids_[i].start(), native_id_length) == 0)) { return i; } } DCHECK(false); return -1; } Vector GetScriptsSource() { DCHECK(false); // Not implemented. return Vector(); } static NativesStore* MakeFromScriptsSource(SnapshotByteSource* source) { NativesStore* store = new NativesStore; // We expect the libraries in the following format: // int: # of debugger sources. // 2N blobs: N pairs of source name + actual source. // then, repeat for non-debugger sources. int debugger_count = source->GetInt(); for (int i = 0; i < debugger_count; ++i) store->ReadNameAndContentPair(source); int library_count = source->GetInt(); for (int i = 0; i < library_count; ++i) store->ReadNameAndContentPair(source); store->debugger_count_ = debugger_count; return store; } private: NativesStore() : debugger_count_(0) {} Vector NameFromId(const byte* id, int id_length) { const char native[] = "native "; const char extension[] = ".js"; Vector name(Vector::New(id_length + sizeof(native) - 1 + sizeof(extension) - 1)); memcpy(name.start(), native, sizeof(native) - 1); memcpy(name.start() + sizeof(native) - 1, id, id_length); memcpy(name.start() + sizeof(native) - 1 + id_length, extension, sizeof(extension) - 1); return Vector::cast(name); } void ReadNameAndContentPair(SnapshotByteSource* bytes) { const byte* id; const byte* source; int id_length = bytes->GetBlob(&id); int source_length = bytes->GetBlob(&source); Vector id_vector(reinterpret_cast(id), id_length); Vector source_vector(reinterpret_cast(source), source_length); native_ids_.Add(id_vector); native_source_.Add(source_vector); native_names_.Add(NameFromId(id, id_length)); } List > native_ids_; List > native_names_; List > native_source_; int debugger_count_; DISALLOW_COPY_AND_ASSIGN(NativesStore); }; template class NativesHolder { public: static NativesStore* get() { CHECK(holder_); return holder_; } static void set(NativesStore* store) { CHECK(store); holder_ = store; } static bool empty() { return holder_ == NULL; } static void Dispose() { delete holder_; holder_ = NULL; } private: static NativesStore* holder_; }; template NativesStore* NativesHolder::holder_ = NULL; // The natives blob. Memory is owned by caller. static StartupData* natives_blob_ = NULL; /** * Read the Natives blob, as previously set by SetNativesFromFile. */ void ReadNatives() { if (natives_blob_ && NativesHolder::empty()) { SnapshotByteSource bytes(natives_blob_->data, natives_blob_->raw_size); NativesHolder::set(NativesStore::MakeFromScriptsSource(&bytes)); NativesHolder::set(NativesStore::MakeFromScriptsSource(&bytes)); NativesHolder::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(natives_blob->raw_size > 0); natives_blob_ = natives_blob; ReadNatives(); } /** * Release memory allocated by SetNativesFromFile. */ void DisposeNatives() { NativesHolder::Dispose(); NativesHolder::Dispose(); NativesHolder::Dispose(); } // Implement NativesCollection 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 int NativesCollection::GetBuiltinsCount() { return NativesHolder::get()->GetBuiltinsCount(); } template int NativesCollection::GetDebuggerCount() { return NativesHolder::get()->GetDebuggerCount(); } template int NativesCollection::GetIndex(const char* name) { return NativesHolder::get()->GetIndex(name); } template Vector NativesCollection::GetScriptSource(int index) { return NativesHolder::get()->GetScriptSource(index); } template Vector NativesCollection::GetScriptName(int index) { return NativesHolder::get()->GetScriptName(index); } template Vector NativesCollection::GetScriptsSource() { return NativesHolder::get()->GetScriptsSource(); } // Explicit template instantiations. #define INSTANTIATE_TEMPLATES(T) \ template int NativesCollection::GetBuiltinsCount(); \ template int NativesCollection::GetDebuggerCount(); \ template int NativesCollection::GetIndex(const char* name); \ template Vector NativesCollection::GetScriptSource(int i); \ template Vector NativesCollection::GetScriptName(int i); \ template Vector NativesCollection::GetScriptsSource(); INSTANTIATE_TEMPLATES(CORE) INSTANTIATE_TEMPLATES(EXTRAS) INSTANTIATE_TEMPLATES(EXPERIMENTAL_EXTRAS) #undef INSTANTIATE_TEMPLATES } // namespace internal } // namespace v8