[web snap] Fix context tree serialization

Enforce the parent context has a smaller id, this time more forcefully.

Bug: v8:11525,v8:12820
Change-Id: I05bf675545b81b818eebfcaa40ee6bb93f5bcf9e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3652792
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80666}
This commit is contained in:
Marja Hölttä 2022-05-20 11:52:59 +02:00 committed by V8 LUCI CQ
parent 67aff19c27
commit 0d57c9a863
3 changed files with 40 additions and 9 deletions

View File

@ -412,14 +412,15 @@ void WebSnapshotSerializer::SerializePendingItems() {
SerializeBuiltinObject(name_id); SerializeBuiltinObject(name_id);
} }
// Serialize the items in the reverse order. The items at the end of the for (int i = 0; i < contexts_->Length(); ++i) {
// contexts_ etc get lower IDs and vice versa. IDs which items use for
// referring to each other are reversed by Get<item>Id functions().
for (int i = contexts_->Length() - 1; i >= 0; --i) {
Handle<Context> context = Handle<Context> context =
handle(Context::cast(contexts_->Get(i)), isolate_); handle(Context::cast(contexts_->Get(i)), isolate_);
SerializeContext(context); SerializeContext(context, static_cast<uint32_t>(i));
} }
// Serialize the items in the reverse order. The items at the end of the
// functions_ etc get lower IDs and vice versa. IDs which items use for
// referring to each other are reversed by Get<item>Id() functions.
for (int i = functions_->Length() - 1; i >= 0; --i) { for (int i = functions_->Length() - 1; i >= 0; --i) {
Handle<JSFunction> function = Handle<JSFunction> function =
handle(JSFunction::cast(functions_->Get(i)), isolate_); handle(JSFunction::cast(functions_->Get(i)), isolate_);
@ -942,6 +943,13 @@ void WebSnapshotSerializer::DiscoverContextAndPrototype(
} }
void WebSnapshotSerializer::DiscoverContext(Handle<Context> context) { void WebSnapshotSerializer::DiscoverContext(Handle<Context> context) {
// Make sure the parent context (if any), gets a smaller ID. This ensures the
// parent context references in the snapshot are not deferred.
if (!context->previous().IsNativeContext() &&
!context->previous().IsScriptContext()) {
DiscoverContext(handle(context->previous(), isolate_));
}
uint32_t id; uint32_t id;
if (InsertIntoIndexMap(context_ids_, *context, id)) return; if (InsertIntoIndexMap(context_ids_, *context, id)) return;
@ -1235,11 +1243,14 @@ void WebSnapshotSerializer::SerializeClass(Handle<JSFunction> function) {
// - String id (name) // - String id (name)
// - For each variable: // - For each variable:
// - Serialized value // - Serialized value
void WebSnapshotSerializer::SerializeContext(Handle<Context> context) { void WebSnapshotSerializer::SerializeContext(Handle<Context> context,
uint32_t id) {
uint32_t parent_context_id = 0; uint32_t parent_context_id = 0;
if (!context->previous().IsNativeContext() && if (!context->previous().IsNativeContext() &&
!context->previous().IsScriptContext()) { !context->previous().IsScriptContext()) {
parent_context_id = GetContextId(context->previous()) + 1; parent_context_id = GetContextId(context->previous());
DCHECK_LT(parent_context_id, id);
++parent_context_id; // 0 is reserved for "no parent context".
} }
// TODO(v8:11525): Use less space for encoding the context type. // TODO(v8:11525): Use less space for encoding the context type.
@ -1662,7 +1673,7 @@ uint32_t WebSnapshotSerializer::GetContextId(Context context) {
bool return_value = context_ids_.Lookup(context, &id); bool return_value = context_ids_.Lookup(context, &id);
DCHECK(return_value); DCHECK(return_value);
USE(return_value); USE(return_value);
return static_cast<uint32_t>(context_ids_.size() - 1 - id); return static_cast<uint32_t>(id);
} }
uint32_t WebSnapshotSerializer::GetArrayId(JSArray array) { uint32_t WebSnapshotSerializer::GetArrayId(JSArray array) {

View File

@ -234,7 +234,7 @@ class V8_EXPORT WebSnapshotSerializer
void SerializeObjectPropertiesWithDictionaryMap(T dict); void SerializeObjectPropertiesWithDictionaryMap(T dict);
void SerializeFunction(Handle<JSFunction> function); void SerializeFunction(Handle<JSFunction> function);
void SerializeClass(Handle<JSFunction> function); void SerializeClass(Handle<JSFunction> function);
void SerializeContext(Handle<Context> context); void SerializeContext(Handle<Context> context, uint32_t id);
void SerializeArray(Handle<JSArray> array); void SerializeArray(Handle<JSArray> array);
void SerializeObject(Handle<JSObject> object); void SerializeObject(Handle<JSObject> object);

View File

@ -123,3 +123,23 @@ d8.file.execute('test/mjsunit/web-snapshot/web-snapshot-helpers.js');
assertSame(newAsyncGeneratorFunction.prototype.__proto__, assertSame(newAsyncGeneratorFunction.prototype.__proto__,
asyncGeneratorFunction.prototype.__proto__); asyncGeneratorFunction.prototype.__proto__);
})(); })();
(function TestContextTree() {
function createObjects() {
(function outer() {
let a = 10;
let b = 20;
(function inner1() {
let c = 5;
globalThis.f1 = function() { return a + b + c; };
})();
(function inner2() {
let d = 10;
globalThis.f2 = function() { return a - b - d; };
})();
})();
}
const {f1, f2} = takeAndUseWebSnapshot(createObjects, ['f1', 'f2']);
assertEquals(35, f1());
assertEquals(-20, f2());
})();