1 // Copyright 2021 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 #ifndef INCLUDE_V8_SNAPSHOT_H_
6 #define INCLUDE_V8_SNAPSHOT_H_
7 
8 #include <vector>
9 
10 #include "v8-internal.h"      // NOLINT(build/include_directory)
11 #include "v8-local-handle.h"  // NOLINT(build/include_directory)
12 #include "v8config.h"         // NOLINT(build/include_directory)
13 
14 namespace v8 {
15 
16 class Object;
17 
18 class V8_EXPORT StartupData {
19  public:
20   /**
21    * Whether the data created can be rehashed and and the hash seed can be
22    * recomputed when deserialized.
23    * Only valid for StartupData returned by SnapshotCreator::CreateBlob().
24    */
25   bool CanBeRehashed() const;
26   /**
27    * Allows embedders to verify whether the data is valid for the current
28    * V8 instance.
29    */
30   bool IsValid() const;
31 
32   const char* data;
33   int raw_size;
34 };
35 
36 /**
37  * Callback and supporting data used in SnapshotCreator to implement embedder
38  * logic to serialize internal fields.
39  * Internal fields that directly reference V8 objects are serialized without
40  * calling this callback. Internal fields that contain aligned pointers are
41  * serialized by this callback if it returns non-zero result. Otherwise it is
42  * serialized verbatim.
43  */
44 struct SerializeInternalFieldsCallback {
45   using CallbackFunction = StartupData (*)(Local<Object> holder, int index,
46                                            void* data);
47   SerializeInternalFieldsCallback(CallbackFunction function = nullptr,
48                                   void* data_arg = nullptr)
callbackSerializeInternalFieldsCallback49       : callback(function), data(data_arg) {}
50   CallbackFunction callback;
51   void* data;
52 };
53 // Note that these fields are called "internal fields" in the API and called
54 // "embedder fields" within V8.
55 using SerializeEmbedderFieldsCallback = SerializeInternalFieldsCallback;
56 
57 /**
58  * Callback and supporting data used to implement embedder logic to deserialize
59  * internal fields.
60  */
61 struct DeserializeInternalFieldsCallback {
62   using CallbackFunction = void (*)(Local<Object> holder, int index,
63                                     StartupData payload, void* data);
64   DeserializeInternalFieldsCallback(CallbackFunction function = nullptr,
65                                     void* data_arg = nullptr)
callbackDeserializeInternalFieldsCallback66       : callback(function), data(data_arg) {}
67   void (*callback)(Local<Object> holder, int index, StartupData payload,
68                    void* data);
69   void* data;
70 };
71 
72 using DeserializeEmbedderFieldsCallback = DeserializeInternalFieldsCallback;
73 
74 /**
75  * Helper class to create a snapshot data blob.
76  *
77  * The Isolate used by a SnapshotCreator is owned by it, and will be entered
78  * and exited by the constructor and destructor, respectively; The destructor
79  * will also destroy the Isolate. Experimental language features, including
80  * those available by default, are not available while creating a snapshot.
81  */
82 class V8_EXPORT SnapshotCreator {
83  public:
84   enum class FunctionCodeHandling { kClear, kKeep };
85 
86   /**
87    * Initialize and enter an isolate, and set it up for serialization.
88    * The isolate is either created from scratch or from an existing snapshot.
89    * The caller keeps ownership of the argument snapshot.
90    * \param existing_blob existing snapshot from which to create this one.
91    * \param external_references a null-terminated array of external references
92    *        that must be equivalent to CreateParams::external_references.
93    */
94   SnapshotCreator(Isolate* isolate,
95                   const intptr_t* external_references = nullptr,
96                   StartupData* existing_blob = nullptr);
97 
98   /**
99    * Create and enter an isolate, and set it up for serialization.
100    * The isolate is either created from scratch or from an existing snapshot.
101    * The caller keeps ownership of the argument snapshot.
102    * \param existing_blob existing snapshot from which to create this one.
103    * \param external_references a null-terminated array of external references
104    *        that must be equivalent to CreateParams::external_references.
105    */
106   SnapshotCreator(const intptr_t* external_references = nullptr,
107                   StartupData* existing_blob = nullptr);
108 
109   /**
110    * Destroy the snapshot creator, and exit and dispose of the Isolate
111    * associated with it.
112    */
113   ~SnapshotCreator();
114 
115   /**
116    * \returns the isolate prepared by the snapshot creator.
117    */
118   Isolate* GetIsolate();
119 
120   /**
121    * Set the default context to be included in the snapshot blob.
122    * The snapshot will not contain the global proxy, and we expect one or a
123    * global object template to create one, to be provided upon deserialization.
124    *
125    * \param callback optional callback to serialize internal fields.
126    */
127   void SetDefaultContext(Local<Context> context,
128                          SerializeInternalFieldsCallback callback =
129                              SerializeInternalFieldsCallback());
130 
131   /**
132    * Add additional context to be included in the snapshot blob.
133    * The snapshot will include the global proxy.
134    *
135    * \param callback optional callback to serialize internal fields.
136    *
137    * \returns the index of the context in the snapshot blob.
138    */
139   size_t AddContext(Local<Context> context,
140                     SerializeInternalFieldsCallback callback =
141                         SerializeInternalFieldsCallback());
142 
143   /**
144    * Attach arbitrary V8::Data to the context snapshot, which can be retrieved
145    * via Context::GetDataFromSnapshotOnce after deserialization. This data does
146    * not survive when a new snapshot is created from an existing snapshot.
147    * \returns the index for retrieval.
148    */
149   template <class T>
150   V8_INLINE size_t AddData(Local<Context> context, Local<T> object);
151 
152   /**
153    * Attach arbitrary V8::Data to the isolate snapshot, which can be retrieved
154    * via Isolate::GetDataFromSnapshotOnce after deserialization. This data does
155    * not survive when a new snapshot is created from an existing snapshot.
156    * \returns the index for retrieval.
157    */
158   template <class T>
159   V8_INLINE size_t AddData(Local<T> object);
160 
161   /**
162    * Created a snapshot data blob.
163    * This must not be called from within a handle scope.
164    * \param function_code_handling whether to include compiled function code
165    *        in the snapshot.
166    * \returns { nullptr, 0 } on failure, and a startup snapshot on success. The
167    *        caller acquires ownership of the data array in the return value.
168    */
169   StartupData CreateBlob(FunctionCodeHandling function_code_handling);
170 
171   // Disallow copying and assigning.
172   SnapshotCreator(const SnapshotCreator&) = delete;
173   void operator=(const SnapshotCreator&) = delete;
174 
175  private:
176   size_t AddData(Local<Context> context, internal::Address object);
177   size_t AddData(internal::Address object);
178 
179   void* data_;
180 };
181 
182 template <class T>
AddData(Local<Context> context,Local<T> object)183 size_t SnapshotCreator::AddData(Local<Context> context, Local<T> object) {
184   T* object_ptr = *object;
185   internal::Address* p = reinterpret_cast<internal::Address*>(object_ptr);
186   return AddData(context, *p);
187 }
188 
189 template <class T>
AddData(Local<T> object)190 size_t SnapshotCreator::AddData(Local<T> object) {
191   T* object_ptr = *object;
192   internal::Address* p = reinterpret_cast<internal::Address*>(object_ptr);
193   return AddData(*p);
194 }
195 
196 }  // namespace v8
197 
198 #endif  // INCLUDE_V8_SNAPSHOT_H_
199