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