Commit 395350c0 authored by Marja Hölttä's avatar Marja Hölttä Committed by V8 LUCI CQ

[web snap] Fix: allow empty objects to have non-trivial prototypes

Bug: v8:11525
Change-Id: I226ba870cee7df20a7960defb0c03607d64e27b0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3634962Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80445}
parent b086aa70
...@@ -1939,10 +1939,17 @@ void WebSnapshotDeserializer::DeserializeMaps() { ...@@ -1939,10 +1939,17 @@ void WebSnapshotDeserializer::DeserializeMaps() {
} }
if (property_count == 0) { if (property_count == 0) {
DisallowGarbageCollection no_gc; if (prototype_id == 0) {
Map empty_map = DisallowGarbageCollection no_gc;
isolate_->native_context()->object_function().initial_map(); Map empty_map =
maps_.set(i, empty_map); isolate_->native_context()->object_function().initial_map();
maps_.set(i, empty_map);
} else {
Handle<Map> map = factory()->NewMap(
JS_OBJECT_TYPE, JSObject::kHeaderSize, HOLEY_ELEMENTS, 0);
DeserializeObjectPrototype(map, prototype_id);
maps_.set(i, *map);
}
continue; continue;
} }
...@@ -2371,14 +2378,17 @@ void WebSnapshotDeserializer::DeserializeObjectPrototype( ...@@ -2371,14 +2378,17 @@ void WebSnapshotDeserializer::DeserializeObjectPrototype(
Handle<Map> map, uint32_t prototype_id) { Handle<Map> map, uint32_t prototype_id) {
if (prototype_id == 0) { if (prototype_id == 0) {
// Use Object.prototype as the prototype. // Use Object.prototype as the prototype.
map->set_prototype(isolate_->native_context()->initial_object_prototype(), Map::SetPrototype(
UPDATE_WRITE_BARRIER); isolate_, map,
handle(isolate_->native_context()->initial_object_prototype(),
isolate_));
} else { } else {
// TODO(v8::11525): Implement stricter checks, e.g., disallow cycles. // TODO(v8::11525): Implement stricter checks, e.g., disallow cycles.
--prototype_id; --prototype_id;
if (prototype_id < current_object_count_) { if (prototype_id < current_object_count_) {
map->set_prototype(HeapObject::cast(objects_.get(prototype_id)), HeapObject prototype = HeapObject::cast(objects_.get(prototype_id));
UPDATE_WRITE_BARRIER); prototype.map().set_is_prototype_map(true);
Map::SetPrototype(isolate_, map, handle(prototype, isolate_));
} else { } else {
// The object hasn't been deserialized yet. // The object hasn't been deserialized yet.
AddDeferredReference(map, 0, OBJECT_ID, prototype_id); AddDeferredReference(map, 0, OBJECT_ID, prototype_id);
...@@ -2997,8 +3007,14 @@ void WebSnapshotDeserializer::ProcessDeferredReferences() { ...@@ -2997,8 +3007,14 @@ void WebSnapshotDeserializer::ProcessDeferredReferences() {
// The only deferred reference allowed for a Map is the __proto__. // The only deferred reference allowed for a Map is the __proto__.
DCHECK_EQ(index, 0); DCHECK_EQ(index, 0);
DCHECK(target.IsJSReceiver()); DCHECK(target.IsJSReceiver());
Map::cast(container).set_prototype(HeapObject::cast(target), HeapObject prototype = HeapObject::cast(target);
UPDATE_WRITE_BARRIER); prototype.map().set_is_prototype_map(true);
{
AllowGarbageCollection allow_gc;
Map::SetPrototype(isolate_, handle(Map::cast(container), isolate_),
handle(prototype, isolate_));
}
raw_deferred_references = *deferred_references_;
} else { } else {
UNREACHABLE(); UNREACHABLE();
} }
......
...@@ -19,3 +19,25 @@ d8.file.execute('test/mjsunit/web-snapshot/web-snapshot-helpers.js'); ...@@ -19,3 +19,25 @@ d8.file.execute('test/mjsunit/web-snapshot/web-snapshot-helpers.js');
assertTrue(obj1.a === Realm.eval(realm, "Error")); assertTrue(obj1.a === Realm.eval(realm, "Error"));
assertTrue(obj2.b === Realm.eval(realm, "Error.prototype")); assertTrue(obj2.b === Realm.eval(realm, "Error.prototype"));
})(); })();
(function TestObjectPrototype() {
function createObjects() {
globalThis.obj = {a: 1, __proto__: {x: 1}};
}
const realm = Realm.create();
const {obj} = takeAndUseWebSnapshot(createObjects, ['obj'], realm);
assertEquals(1, obj.x);
assertEquals(1, obj.__proto__.x);
assertSame(Realm.eval(realm, 'Object.prototype'), obj.__proto__.__proto__);
})();
(function TestEmptyObjectPrototype() {
function createObjects() {
globalThis.obj = {__proto__: {x: 1}};
}
const realm = Realm.create();
const {obj} = takeAndUseWebSnapshot(createObjects, ['obj'], realm);
assertEquals(1, obj.x);
assertEquals(1, obj.__proto__.x);
assertSame(Realm.eval(realm, 'Object.prototype'), obj.__proto__.__proto__);
})();
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