1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/snapshot/natives.h"
6 
7 #include "src/base/logging.h"
8 #include "src/list.h"
9 #include "src/list-inl.h"
10 #include "src/snapshot/snapshot-source-sink.h"
11 #include "src/vector.h"
12 
13 #ifndef V8_USE_EXTERNAL_STARTUP_DATA
14 #error natives-external.cc is used only for the external snapshot build.
15 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
16 
17 
18 namespace v8 {
19 namespace internal {
20 
21 
22 /**
23  * NativesStore stores the 'native' (builtin) JS libraries.
24  *
25  * NativesStore needs to be initialized before using V8, usually by the
26  * embedder calling v8::SetNativesDataBlob, which calls SetNativesFromFile
27  * below.
28  */
29 class NativesStore {
30  public:
~NativesStore()31   ~NativesStore() {
32     for (int i = 0; i < native_names_.length(); i++) {
33       native_names_[i].Dispose();
34     }
35   }
36 
GetBuiltinsCount()37   int GetBuiltinsCount() { return native_ids_.length(); }
GetDebuggerCount()38   int GetDebuggerCount() { return debugger_count_; }
39 
GetScriptSource(int index)40   Vector<const char> GetScriptSource(int index) {
41     return native_source_[index];
42   }
43 
GetScriptName(int index)44   Vector<const char> GetScriptName(int index) { return native_names_[index]; }
45 
GetIndex(const char * id)46   int GetIndex(const char* id) {
47     for (int i = 0; i < native_ids_.length(); ++i) {
48       int native_id_length = native_ids_[i].length();
49       if ((static_cast<int>(strlen(id)) == native_id_length) &&
50           (strncmp(id, native_ids_[i].start(), native_id_length) == 0)) {
51         return i;
52       }
53     }
54     DCHECK(false);
55     return -1;
56   }
57 
GetScriptsSource()58   Vector<const char> GetScriptsSource() {
59     DCHECK(false);  // Not implemented.
60     return Vector<const char>();
61   }
62 
MakeFromScriptsSource(SnapshotByteSource * source)63   static NativesStore* MakeFromScriptsSource(SnapshotByteSource* source) {
64     NativesStore* store = new NativesStore;
65 
66     // We expect the libraries in the following format:
67     //   int: # of debugger sources.
68     //   2N blobs: N pairs of source name + actual source.
69     //   then, repeat for non-debugger sources.
70     int debugger_count = source->GetInt();
71     for (int i = 0; i < debugger_count; ++i)
72       store->ReadNameAndContentPair(source);
73     int library_count = source->GetInt();
74     for (int i = 0; i < library_count; ++i)
75       store->ReadNameAndContentPair(source);
76 
77     store->debugger_count_ = debugger_count;
78     return store;
79   }
80 
81  private:
NativesStore()82   NativesStore() : debugger_count_(0) {}
83 
NameFromId(const byte * id,int id_length)84   Vector<const char> NameFromId(const byte* id, int id_length) {
85     const char native[] = "native ";
86     const char extension[] = ".js";
87     Vector<char> name(Vector<char>::New(id_length + sizeof(native) - 1 +
88                                         sizeof(extension) - 1));
89     memcpy(name.start(), native, sizeof(native) - 1);
90     memcpy(name.start() + sizeof(native) - 1, id, id_length);
91     memcpy(name.start() + sizeof(native) - 1 + id_length, extension,
92            sizeof(extension) - 1);
93     return Vector<const char>::cast(name);
94   }
95 
ReadNameAndContentPair(SnapshotByteSource * bytes)96   void ReadNameAndContentPair(SnapshotByteSource* bytes) {
97     const byte* id;
98     const byte* source;
99     int id_length = bytes->GetBlob(&id);
100     int source_length = bytes->GetBlob(&source);
101     Vector<const char> id_vector(reinterpret_cast<const char*>(id), id_length);
102     Vector<const char> source_vector(reinterpret_cast<const char*>(source),
103                                      source_length);
104     native_ids_.Add(id_vector);
105     native_source_.Add(source_vector);
106     native_names_.Add(NameFromId(id, id_length));
107   }
108 
109   List<Vector<const char> > native_ids_;
110   List<Vector<const char> > native_names_;
111   List<Vector<const char> > native_source_;
112   int debugger_count_;
113 
114   DISALLOW_COPY_AND_ASSIGN(NativesStore);
115 };
116 
117 
118 template<NativeType type>
119 class NativesHolder {
120  public:
get()121   static NativesStore* get() {
122     CHECK(holder_);
123     return holder_;
124   }
set(NativesStore * store)125   static void set(NativesStore* store) {
126     CHECK(store);
127     holder_ = store;
128   }
empty()129   static bool empty() { return holder_ == NULL; }
Dispose()130   static void Dispose() {
131     delete holder_;
132     holder_ = NULL;
133   }
134 
135  private:
136   static NativesStore* holder_;
137 };
138 
139 template<NativeType type>
140 NativesStore* NativesHolder<type>::holder_ = NULL;
141 
142 
143 // The natives blob. Memory is owned by caller.
144 static StartupData* natives_blob_ = NULL;
145 
146 
147 /**
148  * Read the Natives blob, as previously set by SetNativesFromFile.
149  */
ReadNatives()150 void ReadNatives() {
151   if (natives_blob_ && NativesHolder<CORE>::empty()) {
152     SnapshotByteSource bytes(natives_blob_->data, natives_blob_->raw_size);
153     NativesHolder<CORE>::set(NativesStore::MakeFromScriptsSource(&bytes));
154     NativesHolder<EXPERIMENTAL>::set(
155         NativesStore::MakeFromScriptsSource(&bytes));
156     NativesHolder<EXTRAS>::set(NativesStore::MakeFromScriptsSource(&bytes));
157     NativesHolder<EXPERIMENTAL_EXTRAS>::set(
158         NativesStore::MakeFromScriptsSource(&bytes));
159     DCHECK(!bytes.HasMore());
160   }
161 }
162 
163 
164 /**
165  * Set the Natives (library sources) blob, as generated by js2c + the build
166  * system.
167  */
SetNativesFromFile(StartupData * natives_blob)168 void SetNativesFromFile(StartupData* natives_blob) {
169   DCHECK(!natives_blob_);
170   DCHECK(natives_blob);
171   DCHECK(natives_blob->data);
172   DCHECK(natives_blob->raw_size > 0);
173 
174   natives_blob_ = natives_blob;
175   ReadNatives();
176 }
177 
178 
179 /**
180  * Release memory allocated by SetNativesFromFile.
181  */
DisposeNatives()182 void DisposeNatives() {
183   NativesHolder<CORE>::Dispose();
184   NativesHolder<EXPERIMENTAL>::Dispose();
185   NativesHolder<EXTRAS>::Dispose();
186   NativesHolder<EXPERIMENTAL_EXTRAS>::Dispose();
187 }
188 
189 
190 // Implement NativesCollection<T> bsaed on NativesHolder + NativesStore.
191 //
192 // (The callers expect a purely static interface, since this is how the
193 //  natives are usually compiled in. Since we implement them based on
194 //  runtime content, we have to implement this indirection to offer
195 //  a static interface.)
196 template<NativeType type>
GetBuiltinsCount()197 int NativesCollection<type>::GetBuiltinsCount() {
198   return NativesHolder<type>::get()->GetBuiltinsCount();
199 }
200 
201 template<NativeType type>
GetDebuggerCount()202 int NativesCollection<type>::GetDebuggerCount() {
203   return NativesHolder<type>::get()->GetDebuggerCount();
204 }
205 
206 template<NativeType type>
GetIndex(const char * name)207 int NativesCollection<type>::GetIndex(const char* name) {
208   return NativesHolder<type>::get()->GetIndex(name);
209 }
210 
211 template <NativeType type>
GetScriptSource(int index)212 Vector<const char> NativesCollection<type>::GetScriptSource(int index) {
213   return NativesHolder<type>::get()->GetScriptSource(index);
214 }
215 
216 template<NativeType type>
GetScriptName(int index)217 Vector<const char> NativesCollection<type>::GetScriptName(int index) {
218   return NativesHolder<type>::get()->GetScriptName(index);
219 }
220 
221 template <NativeType type>
GetScriptsSource()222 Vector<const char> NativesCollection<type>::GetScriptsSource() {
223   return NativesHolder<type>::get()->GetScriptsSource();
224 }
225 
226 
227 // Explicit template instantiations.
228 #define INSTANTIATE_TEMPLATES(T)                                            \
229   template int NativesCollection<T>::GetBuiltinsCount();                    \
230   template int NativesCollection<T>::GetDebuggerCount();                    \
231   template int NativesCollection<T>::GetIndex(const char* name);            \
232   template Vector<const char> NativesCollection<T>::GetScriptSource(int i); \
233   template Vector<const char> NativesCollection<T>::GetScriptName(int i);   \
234   template Vector<const char> NativesCollection<T>::GetScriptsSource();
235 INSTANTIATE_TEMPLATES(CORE)
236 INSTANTIATE_TEMPLATES(EXPERIMENTAL)
237 INSTANTIATE_TEMPLATES(EXTRAS)
238 INSTANTIATE_TEMPLATES(EXPERIMENTAL_EXTRAS)
239 #undef INSTANTIATE_TEMPLATES
240 
241 }  // namespace internal
242 }  // namespace v8
243