Commit 7a8da348 authored by Marja Hölttä's avatar Marja Hölttä Committed by Commit Bot

Reland: [web snapshots] Web Snapshots Version 0.01

(Reland: removed the d8 changes, will land them separately.)

The minimal implementation which does something useful. Initial
machinery for serializing / deserializing objects and functions (only
the very simple cases are supported).

For more info, see https://docs.google.com/document/d/1Qierkg3b3klIwCQt-oZCHqhcc1_9DXNIErBwvdpD4wU/edit?usp=sharing

Previous version: Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2716288

TBR=leszeks@chromium.org,syg@chromium.org,hpayer@chromium.org

Bug: v8:11525
Change-Id: Ia61ed7de36f371d931eff68156ab467723915704
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2759510Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarHannes Payer <hpayer@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73401}
parent f02aba94
......@@ -3926,6 +3926,8 @@ v8_source_set("v8_base_without_compiler") {
"src/utils/ostreams.cc",
"src/utils/utils.cc",
"src/utils/version.cc",
"src/web-snapshot/web-snapshot.cc",
"src/web-snapshot/web-snapshot.h",
"src/zone/accounting-allocator.cc",
"src/zone/type-stats.cc",
"src/zone/zone-segment.cc",
......
......@@ -490,6 +490,8 @@ DEFINE_BOOL(trace_block_coverage, false,
"trace collected block coverage information")
DEFINE_BOOL(trace_protector_invalidation, false,
"trace protector cell invalidations")
DEFINE_BOOL(trace_web_snapshot, false, "trace web snapshot deserialization")
DEFINE_BOOL(feedback_normalization, false,
"feed back normalization to constructors")
// TODO(jkummerow): This currently adds too much load on the stub cache.
......
......@@ -217,6 +217,7 @@ class DescriptorArray
using EntryValueField = TaggedField<MaybeObject, kEntryValueOffset>;
private:
friend class WebSnapshotDeserializer;
DECL_INT16_ACCESSORS(filler16bits)
inline void SetKey(InternalIndex descriptor_number, Name key);
......
......@@ -1103,6 +1103,15 @@ ValueDeserializer::ValueDeserializer(Isolate* isolate,
id_map_(isolate->global_handles()->Create(
ReadOnlyRoots(isolate_).empty_fixed_array())) {}
ValueDeserializer::ValueDeserializer(Isolate* isolate, const uint8_t* data,
size_t size)
: isolate_(isolate),
delegate_(nullptr),
position_(data),
end_(data + size),
id_map_(isolate->global_handles()->Create(
ReadOnlyRoots(isolate_).empty_fixed_array())) {}
ValueDeserializer::~ValueDeserializer() {
GlobalHandles::Destroy(id_map_.location());
......
......@@ -94,6 +94,8 @@ class ValueSerializer {
void SetTreatArrayBufferViewsAsHostObjects(bool mode);
private:
friend class WebSnapshotSerializer;
// Managing allocations of the internal buffer.
Maybe<bool> ExpandBuffer(size_t required_capacity);
......@@ -182,6 +184,7 @@ class ValueDeserializer {
public:
ValueDeserializer(Isolate* isolate, Vector<const uint8_t> data,
v8::ValueDeserializer::Delegate* delegate);
ValueDeserializer(Isolate* isolate, const uint8_t* data, size_t size);
~ValueDeserializer();
ValueDeserializer(const ValueDeserializer&) = delete;
ValueDeserializer& operator=(const ValueDeserializer&) = delete;
......@@ -230,6 +233,8 @@ class ValueDeserializer {
bool ReadRawBytes(size_t length, const void** data) V8_WARN_UNUSED_RESULT;
private:
friend class WebSnapshotDeserializer;
// Reading the wire format.
Maybe<SerializationTag> PeekTag() const V8_WARN_UNUSED_RESULT;
void ConsumeTag(SerializationTag peeked_tag);
......
......@@ -152,6 +152,8 @@ class ObjectCacheIndexMap {
return find_result.already_exists;
}
int size() const { return next_index_; }
private:
IdentityMap<int, base::DefaultAllocationPolicy> map_;
int next_index_;
......
marja@chromium.org
leszeks@chromium.org
syg@chromium.org
verwaest@chromium.org
This diff is collapsed.
// Copyright 2021 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.
#ifndef V8_WEB_SNAPSHOT_WEB_SNAPSHOT_H_
#define V8_WEB_SNAPSHOT_WEB_SNAPSHOT_H_
#include <queue>
#include <vector>
#include "src/handles/handles.h"
#include "src/objects/value-serializer.h"
#include "src/snapshot/serializer.h" // For ObjectCacheIndexMap
namespace v8 {
class Context;
class Isolate;
template <typename T>
class Local;
namespace internal {
class Context;
class Map;
class Object;
class String;
struct WebSnapshotData {
uint8_t* buffer = nullptr;
size_t buffer_size = 0;
~WebSnapshotData() { free(buffer); }
};
class WebSnapshotSerializerDeserializer {
public:
bool has_error() const { return error_message_ != nullptr; }
const char* error_message() const { return error_message_; }
enum ValueType : uint8_t { STRING_ID, OBJECT_ID, FUNCTION_ID };
protected:
explicit WebSnapshotSerializerDeserializer(Isolate* isolate)
: isolate_(isolate) {}
void Throw(const char* message);
Isolate* isolate_;
const char* error_message_ = nullptr;
private:
WebSnapshotSerializerDeserializer(const WebSnapshotSerializerDeserializer&) =
delete;
WebSnapshotSerializerDeserializer& operator=(
const WebSnapshotSerializerDeserializer&) = delete;
};
class V8_EXPORT WebSnapshotSerializer
: public WebSnapshotSerializerDeserializer {
public:
explicit WebSnapshotSerializer(v8::Isolate* isolate);
~WebSnapshotSerializer();
bool TakeSnapshot(v8::Local<v8::Context> context,
const std::vector<std::string>& exports,
WebSnapshotData& data_out);
// For inspecting the state after taking a snapshot.
uint32_t string_count() const;
uint32_t map_count() const;
uint32_t function_count() const;
uint32_t object_count() const;
private:
WebSnapshotSerializer(const WebSnapshotSerializer&) = delete;
WebSnapshotSerializer& operator=(const WebSnapshotSerializer&) = delete;
void WriteSnapshot(uint8_t*& buffer, size_t& buffer_size);
// Returns true if the object was already in the map, false if it was added.
bool InsertIntoIndexMap(ObjectCacheIndexMap& map, Handle<HeapObject> object,
uint32_t& id);
void SerializeString(Handle<String> string, uint32_t& id);
void SerializeMap(Handle<Map> map, uint32_t& id);
void SerializeJSFunction(Handle<JSFunction> function, uint32_t& id);
void SerializeJSObject(Handle<JSObject> object, uint32_t& id);
void SerializePendingJSObject(Handle<JSObject> object);
void SerializeExport(Handle<JSObject> object, const std::string& export_name);
void WriteValue(Handle<Object> object, ValueSerializer& serializer);
ValueSerializer string_serializer_;
ValueSerializer map_serializer_;
ValueSerializer function_serializer_;
ValueSerializer object_serializer_;
ValueSerializer export_serializer_;
ObjectCacheIndexMap string_ids_;
ObjectCacheIndexMap map_ids_;
ObjectCacheIndexMap function_ids_;
ObjectCacheIndexMap object_ids_;
uint32_t export_count_ = 0;
std::queue<Handle<JSObject>> pending_objects_;
};
class V8_EXPORT WebSnapshotDeserializer
: public WebSnapshotSerializerDeserializer {
public:
explicit WebSnapshotDeserializer(v8::Isolate* v8_isolate);
bool UseWebSnapshot(const uint8_t* data, size_t buffer_size);
// For inspecting the state after taking a snapshot.
size_t string_count() const { return strings_.size(); }
size_t map_count() const { return maps_.size(); }
size_t function_count() const { return functions_.size(); }
size_t object_count() const { return objects_.size(); }
private:
WebSnapshotDeserializer(const WebSnapshotDeserializer&) = delete;
WebSnapshotDeserializer& operator=(const WebSnapshotDeserializer&) = delete;
void DeserializeStrings(const uint8_t* data, size_t& ix, size_t size);
void DeserializeMaps(const uint8_t* data, size_t& ix, size_t size);
void DeserializeFunctions(const uint8_t* data, size_t& ix, size_t size);
void DeserializeObjects(const uint8_t* data, size_t& ix, size_t size);
void DeserializeExports(const uint8_t* data, size_t& ix, size_t size);
std::vector<Handle<String>> strings_;
std::vector<Handle<Map>> maps_;
std::vector<Handle<JSFunction>> functions_;
std::vector<Handle<JSObject>> objects_;
};
} // namespace internal
} // namespace v8
#endif // V8_WEB_SNAPSHOT_WEB_SNAPSHOT_H_
......@@ -287,6 +287,7 @@ v8_source_set("cctest_sources") {
"test-version.cc",
"test-weakmaps.cc",
"test-weaksets.cc",
"test-web-snapshots.cc",
"torque/test-torque.cc",
"trace-extension.cc",
"trace-extension.h",
......
// Copyright 2018 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/web-snapshot/web-snapshot.h"
#include "test/cctest/cctest-utils.h"
#include "test/cctest/cctest.h"
namespace v8 {
namespace internal {
TEST(Minimal) {
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
CompileRun("var foo = {'key': 'lol'}");
WebSnapshotData snapshot_data;
{
std::vector<std::string> exports;
exports.push_back("foo");
WebSnapshotSerializer serializer(isolate);
CHECK(serializer.TakeSnapshot(context, exports, snapshot_data));
CHECK(!serializer.has_error());
CHECK_NOT_NULL(snapshot_data.buffer);
// Strings: 'foo', 'key', 'lol'
CHECK_EQ(3, serializer.string_count());
CHECK_EQ(1, serializer.map_count());
CHECK_EQ(1, serializer.object_count());
CHECK_EQ(0, serializer.function_count());
}
{
v8::Local<v8::Context> new_context = CcTest::NewContext();
v8::Context::Scope context_scope(new_context);
WebSnapshotDeserializer deserializer(isolate);
CHECK(deserializer.UseWebSnapshot(snapshot_data.buffer,
snapshot_data.buffer_size));
CHECK(!deserializer.has_error());
v8::Local<v8::String> result = CompileRun("foo.key").As<v8::String>();
CHECK(result->Equals(new_context, v8_str("lol")).FromJust());
CHECK_EQ(3, deserializer.string_count());
CHECK_EQ(1, deserializer.map_count());
CHECK_EQ(1, deserializer.object_count());
CHECK_EQ(0, deserializer.function_count());
}
}
TEST(Function) {
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
CompileRun("var foo = {'key': function() { return '11525'; }}");
WebSnapshotData snapshot_data;
{
std::vector<std::string> exports;
exports.push_back("foo");
WebSnapshotSerializer serializer(isolate);
CHECK(serializer.TakeSnapshot(context, exports, snapshot_data));
CHECK(!serializer.has_error());
CHECK_NOT_NULL(snapshot_data.buffer);
// Strings: 'foo', 'key', function source code
CHECK_EQ(3, serializer.string_count());
CHECK_EQ(1, serializer.map_count());
CHECK_EQ(1, serializer.object_count());
CHECK_EQ(1, serializer.function_count());
}
{
v8::Local<v8::Context> new_context = CcTest::NewContext();
v8::Context::Scope context_scope(new_context);
WebSnapshotDeserializer deserializer(isolate);
CHECK(deserializer.UseWebSnapshot(snapshot_data.buffer,
snapshot_data.buffer_size));
CHECK(!deserializer.has_error());
v8::Local<v8::Function> function = CompileRun("foo.key").As<v8::Function>();
v8::Local<v8::Value> result =
function->Call(new_context, new_context->Global(), 0, nullptr)
.ToLocalChecked();
CHECK(result->Equals(new_context, v8_str("11525")).FromJust());
CHECK_EQ(3, deserializer.string_count());
CHECK_EQ(1, deserializer.map_count());
CHECK_EQ(1, deserializer.object_count());
CHECK_EQ(1, deserializer.function_count());
}
}
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment