#include "src/snapshot/context-deserializer.h"
#include "src/api/api-inl.h"
#include "src/base/logging.h"
#include "src/common/assert-scope.h"
#include "src/logging/counters-scopes.h"
#include "src/snapshot/serializer-deserializer.h"
namespace v8 {
namespace internal {
MaybeDirectHandle<Context> ContextDeserializer::DeserializeContext(
Isolate* isolate, const SnapshotData* data, size_t context_index,
bool can_rehash, DirectHandle<JSGlobalProxy> global_proxy,
DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
TRACE_EVENT0("v8", "V8.DeserializeContext");
RCS_SCOPE(isolate, RuntimeCallCounterId::kDeserializeContext);
base::ElapsedTimer timer;
if (V8_UNLIKELY(v8_flags.profile_deserialization)) timer.Start();
NestedTimedHistogramScope histogram_timer(
isolate->counters()->snapshot_deserialize_context());
ContextDeserializer d(isolate, data, can_rehash);
MaybeDirectHandle<Object> maybe_result =
d.Deserialize(isolate, global_proxy, embedder_fields_deserializer);
if (V8_UNLIKELY(v8_flags.profile_deserialization)) {
const int bytes = static_cast<int>(data->RawData().size());
const double ms = timer.Elapsed().InMillisecondsF();
PrintF("[Deserializing context #%zu (%d bytes) took %0.3f ms]\n",
context_index, bytes, ms);
}
DirectHandle<Object> result;
if (!maybe_result.ToHandle(&result)) return {};
return Cast<Context>(result);
}
MaybeDirectHandle<Object> ContextDeserializer::Deserialize(
Isolate* isolate, DirectHandle<JSGlobalProxy> global_proxy,
DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
AddAttachedObject(global_proxy);
AddAttachedObject(direct_handle(global_proxy->map(), isolate));
DirectHandle<Object> result;
{
DisallowCodeAllocation no_code_allocation;
result = ReadObject();
DCHECK(IsNativeContext(*result));
DeserializeDeferredObjects();
DeserializeEmbedderFields(Cast<NativeContext>(result),
embedder_fields_deserializer);
DeserializeApiWrapperFields(
embedder_fields_deserializer.api_wrapper_callback);
LogNewMapEvents();
WeakenDescriptorArrays();
}
if (should_rehash()) Rehash();
return result;
}
template <typename T>
class PlainBuffer {
public:
T* data() { return data_.get(); }
void EnsureCapacity(size_t new_capacity) {
if (new_capacity > capacity_) {
data_.reset(new T[new_capacity]);
capacity_ = new_capacity;
}
}
private:
std::unique_ptr<T[]> data_;
size_t capacity_{0};
};
void ContextDeserializer::DeserializeEmbedderFields(
DirectHandle<NativeContext> context,
DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
if (!source()->HasMore() || source()->Peek() != kEmbedderFieldsData) {
return;
}
source()->Get();
DisallowGarbageCollection no_gc;
DisallowJavascriptExecution no_js(isolate());
DisallowCompilation no_compile(isolate());
PlainBuffer<char> buffer;
for (int code = source()->Get(); code != kSynchronize;
code = source()->Get()) {
HandleScope scope(isolate());
DirectHandle<HeapObject> heap_object =
Cast<HeapObject>(GetBackReferencedObject());
const int index = source()->GetUint30();
const int size = source()->GetUint30();
buffer.EnsureCapacity(size);
source()->CopyRaw(buffer.data(), size);
if (IsJSObject(*heap_object)) {
DirectHandle<JSObject> obj = Cast<JSObject>(heap_object);
v8::DeserializeInternalFieldsCallback callback =
embedder_fields_deserializer.js_object_callback;
DCHECK_NOT_NULL(callback.callback);
callback.callback(v8::Utils::ToLocal(obj), index, {buffer.data(), size},
callback.data);
} else {
DCHECK(IsEmbedderDataArray(*heap_object));
v8::DeserializeContextDataCallback callback =
embedder_fields_deserializer.context_callback;
DCHECK_NOT_NULL(callback.callback);
callback.callback(v8::Utils::ToLocal(context), index,
{buffer.data(), size}, callback.data);
}
}
}
void ContextDeserializer::DeserializeApiWrapperFields(
const v8::DeserializeAPIWrapperCallback& api_wrapper_callback) {
if (!source()->HasMore() || source()->Peek() != kApiWrapperFieldsData) {
return;
}
source()->Get();
DisallowGarbageCollection no_gc;
DisallowJavascriptExecution no_js(isolate());
DisallowCompilation no_compile(isolate());
PlainBuffer<char> buffer;
for (int code = source()->Get(); code != kSynchronize;
code = source()->Get()) {
HandleScope scope(isolate());
DirectHandle<JSObject> js_object =
Cast<JSObject>(GetBackReferencedObject());
const int size = source()->GetUint30();
buffer.EnsureCapacity(size);
source()->CopyRaw(buffer.data(), size);
DCHECK_NOT_NULL(api_wrapper_callback.callback);
api_wrapper_callback.callback(v8::Utils::ToLocal(js_object),
{buffer.data(), size},
api_wrapper_callback.data);
}
}
}
}