Commit 977e1c9e authored by Marja Hölttä's avatar Marja Hölttä Committed by Commit Bot

[web snapshots] Add inner functions

Bug: v8:11525
Change-Id: I9afd7095764fdb4b15c8a3492078073624b42a11
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2763869Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarShu-yu Guo <syg@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73569}
parent 207577f3
......@@ -255,6 +255,7 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase
Handle<String> MakeOrFindTwoCharacterString(uint16_t c1, uint16_t c2);
private:
friend class WebSnapshotDeserializer;
Impl* impl() { return static_cast<Impl*>(this); }
auto isolate() { return impl()->isolate(); }
ReadOnlyRoots read_only_roots() { return impl()->read_only_roots(); }
......
......@@ -271,6 +271,8 @@ class ScopeInfo : public TorqueGeneratedScopeInfo<ScopeInfo, HeapObject> {
inline ObjectSlot data_start();
private:
friend class WebSnapshotDeserializer;
int ContextLocalNamesIndex() const;
int ContextLocalInfosIndex() const;
int SavedClassVariableInfoIndex() const;
......
......@@ -658,6 +658,8 @@ class SharedFunctionInfo
Isolate* isolate);
private:
friend class WebSnapshotDeserializer;
#ifdef VERIFY_HEAP
void SharedFunctionInfoVerify(ReadOnlyRoots roots);
#endif
......
......@@ -152,6 +152,15 @@ class ObjectCacheIndexMap {
return find_result.already_exists;
}
bool Lookup(Handle<HeapObject> obj, int* index_out) const {
int* index = map_.Find(obj);
if (index == nullptr) {
return false;
}
*index_out = *index;
return true;
}
int size() const { return next_index_; }
private:
......
This diff is collapsed.
......@@ -65,10 +65,23 @@ class V8_EXPORT WebSnapshotSerializer
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;
uint32_t string_count() const {
return static_cast<uint32_t>(string_ids_.size());
}
uint32_t map_count() const { return static_cast<uint32_t>(map_ids_.size()); }
uint32_t context_count() const {
return static_cast<uint32_t>(context_ids_.size());
}
uint32_t function_count() const {
return static_cast<uint32_t>(function_ids_.size());
}
uint32_t object_count() const {
return static_cast<uint32_t>(object_ids_.size());
}
private:
WebSnapshotSerializer(const WebSnapshotSerializer&) = delete;
......@@ -82,20 +95,23 @@ class V8_EXPORT WebSnapshotSerializer
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 SerializeFunction(Handle<JSFunction> function, uint32_t& id);
void SerializeContext(Handle<Context> context, uint32_t& id);
void SerializeObject(Handle<JSObject> object, uint32_t& id);
void SerializePendingObject(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 context_serializer_;
ValueSerializer function_serializer_;
ValueSerializer object_serializer_;
ValueSerializer export_serializer_;
ObjectCacheIndexMap string_ids_;
ObjectCacheIndexMap map_ids_;
ObjectCacheIndexMap context_ids_;
ObjectCacheIndexMap function_ids_;
ObjectCacheIndexMap object_ids_;
uint32_t export_count_ = 0;
......@@ -112,6 +128,7 @@ class V8_EXPORT WebSnapshotDeserializer
// 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 context_count() const { return contexts_.size(); }
size_t function_count() const { return functions_.size(); }
size_t object_count() const { return objects_.size(); }
......@@ -120,13 +137,21 @@ class V8_EXPORT WebSnapshotDeserializer
WebSnapshotDeserializer& operator=(const WebSnapshotDeserializer&) = delete;
void DeserializeStrings(const uint8_t* data, size_t& ix, size_t size);
Handle<String> ReadString(ValueDeserializer& deserializer,
bool internalize = false);
void DeserializeMaps(const uint8_t* data, size_t& ix, size_t size);
void DeserializeContexts(const uint8_t* data, size_t& ix, size_t size);
Handle<ScopeInfo> CreateScopeInfo(uint32_t variable_count, bool has_parent);
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);
void ReadValue(ValueDeserializer& deserializer, Handle<Object>& value,
Representation& representation);
// TODO(v8:11525): Make these FixedArrays.
std::vector<Handle<String>> strings_;
std::vector<Handle<Map>> maps_;
std::vector<Handle<Context>> contexts_;
std::vector<Handle<JSFunction>> functions_;
std::vector<Handle<JSObject>> objects_;
};
......
......@@ -9,13 +9,18 @@
namespace v8 {
namespace internal {
TEST(Minimal) {
namespace {
void TestWebSnapshot(const char* snapshot_source, const char* test_source,
const char* expected_result, uint32_t string_count,
uint32_t map_count, uint32_t context_count,
uint32_t function_count, uint32_t object_count) {
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
CompileRun("var foo = {'key': 'lol'}");
CompileRun(snapshot_source);
WebSnapshotData snapshot_data;
{
std::vector<std::string> exports;
......@@ -24,11 +29,11 @@ TEST(Minimal) {
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());
CHECK_EQ(string_count, serializer.string_count());
CHECK_EQ(map_count, serializer.map_count());
CHECK_EQ(context_count, serializer.context_count());
CHECK_EQ(function_count, serializer.function_count());
CHECK_EQ(object_count, serializer.object_count());
}
{
......@@ -38,54 +43,88 @@ TEST(Minimal) {
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());
v8::Local<v8::String> result = CompileRun(test_source).As<v8::String>();
CHECK(result->Equals(new_context, v8_str(expected_result)).FromJust());
CHECK_EQ(string_count, deserializer.string_count());
CHECK_EQ(map_count, deserializer.map_count());
CHECK_EQ(context_count, deserializer.context_count());
CHECK_EQ(function_count, deserializer.function_count());
CHECK_EQ(object_count, deserializer.object_count());
}
}
} // namespace
TEST(Minimal) {
const char* snapshot_source = "var foo = {'key': 'lol'};";
const char* test_source = "foo.key";
const char* expected_result = "lol";
uint32_t kStringCount = 3; // 'foo', 'key', 'lol'
uint32_t kMapCount = 1;
uint32_t kContextCount = 0;
uint32_t kFunctionCount = 0;
uint32_t kObjectCount = 1;
TestWebSnapshot(snapshot_source, test_source, expected_result, kStringCount,
kMapCount, kContextCount, kFunctionCount, kObjectCount);
}
TEST(Function) {
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
const char* snapshot_source =
"var foo = {'key': function() { return '11525'; }};";
const char* test_source = "foo.key()";
const char* expected_result = "11525";
uint32_t kStringCount = 3; // 'foo', 'key', function source code
uint32_t kMapCount = 1;
uint32_t kContextCount = 0;
uint32_t kFunctionCount = 1;
uint32_t kObjectCount = 1;
TestWebSnapshot(snapshot_source, test_source, expected_result, kStringCount,
kMapCount, kContextCount, kFunctionCount, kObjectCount);
}
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());
}
TEST(InnerFunctionWithContext) {
const char* snapshot_source =
"var foo = {'key': (function() {\n"
" let result = '11525';\n"
" function inner() { return result; }\n"
" return inner;\n"
" })()};";
const char* test_source = "foo.key()";
const char* expected_result = "11525";
// Strings: 'foo', 'key', function source code (inner), 'result', '11525'
uint32_t kStringCount = 5;
uint32_t kMapCount = 1;
uint32_t kContextCount = 1;
uint32_t kFunctionCount = 1;
uint32_t kObjectCount = 1;
TestWebSnapshot(snapshot_source, test_source, expected_result, kStringCount,
kMapCount, kContextCount, kFunctionCount, kObjectCount);
}
{
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());
}
TEST(InnerFunctionWithContextAndParentContext) {
const char* snapshot_source =
"var foo = {'key': (function() {\n"
" let part1 = '11';\n"
" function inner() {\n"
" let part2 = '525';\n"
" function innerinner() {\n"
" return part1 + part2;\n"
" }\n"
" return innerinner;\n"
" }\n"
" return inner();\n"
" })()};";
const char* test_source = "foo.key()";
const char* expected_result = "11525";
// Strings: 'foo', 'key', function source code (innerinner), 'part1', 'part2',
// '11', '525'
uint32_t kStringCount = 7;
uint32_t kMapCount = 1;
uint32_t kContextCount = 2;
uint32_t kFunctionCount = 1;
uint32_t kObjectCount = 1;
TestWebSnapshot(snapshot_source, test_source, expected_result, kStringCount,
kMapCount, kContextCount, kFunctionCount, kObjectCount);
}
} // namespace internal
......
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