Skip to content

Commit 43717d0

Browse files
Samuel GroßV8 LUCI CQ
Samuel Groß
authored and
V8 LUCI CQ
committed
[sandbox][leaptiering] Basic serializer support for dispatch handles
This CL implements basic support for serializing and deserializing JSDispatchHandles. Previously, serializing an object would clear any dispatch handles in the object. However, now that builtin JSFunctions have a dispatch entry, the serializer needs to support them. With this CL, the deserializer will now allocate entries in the JSDispatchTable with the correct parameter count. Serializing the Code object stored in the table entry will be done in a later CL. Bug: 40931165, 42204201 Change-Id: I35b7eb21efc6eab74dc0be305a8b5f5c8c0069ed Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5783522 Commit-Queue: Samuel Groß <saelo@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Cr-Commit-Position: refs/heads/main@{#95685}
1 parent 4f9d5c3 commit 43717d0

File tree

5 files changed

+68
-16
lines changed

5 files changed

+68
-16
lines changed

src/sandbox/isolate-inl.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ TrustedPointerTable::Space* IsolateForSandbox::GetTrustedPointerTableSpace() {
6464
#ifdef V8_ENABLE_LEAPTIERING
6565
JSDispatchTable::Space* IsolateForSandbox::GetJSDispatchTableSpaceFor(
6666
Address owning_slot) {
67-
return isolate_->heap()->js_dispatch_table_space();
67+
return ReadOnlyHeap::Contains(owning_slot)
68+
? isolate_->read_only_heap()->js_dispatch_table_space()
69+
: isolate_->heap()->js_dispatch_table_space();
6870
}
6971
#endif // V8_ENABLE_LEAPTIERING
7072

src/snapshot/deserializer.cc

+37
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "src/objects/slots.h"
2727
#include "src/objects/string.h"
2828
#include "src/roots/roots.h"
29+
#include "src/sandbox/js-dispatch-table-inl.h"
2930
#include "src/snapshot/embedded/embedded-data-inl.h"
3031
#include "src/snapshot/references.h"
3132
#include "src/snapshot/serializer-deserializer.h"
@@ -944,6 +945,8 @@ int Deserializer<IsolateT>::ReadSingleBytecodeData(uint8_t data,
944945
return ReadIndirectPointerPrefix(data, slot_accessor);
945946
case kInitializeSelfIndirectPointer:
946947
return ReadInitializeSelfIndirectPointer(data, slot_accessor);
948+
case kAllocateJSDispatchEntry:
949+
return ReadAllocateJSDispatchEntry(data, slot_accessor);
947950
case kProtectedPointerPrefix:
948951
return ReadProtectedPointerPrefix(data, slot_accessor);
949952
case CASE_RANGE(kRootArrayConstants, 32):
@@ -1282,6 +1285,40 @@ int Deserializer<IsolateT>::ReadInitializeSelfIndirectPointer(
12821285
#endif // V8_ENABLE_SANDBOX
12831286
}
12841287

1288+
template <typename IsolateT>
1289+
template <typename SlotAccessor>
1290+
int Deserializer<IsolateT>::ReadAllocateJSDispatchEntry(
1291+
uint8_t data, SlotAccessor slot_accessor) {
1292+
#ifdef V8_ENABLE_LEAPTIERING
1293+
DCHECK_NE(slot_accessor.object()->address(), kNullAddress);
1294+
JSDispatchTable* jdt = GetProcessWideJSDispatchTable();
1295+
Handle<HeapObject> host = slot_accessor.object();
1296+
1297+
uint32_t entry_id = source_.GetUint30();
1298+
uint32_t parameter_count = source_.GetUint30();
1299+
DCHECK_LE(parameter_count, kMaxUInt16);
1300+
1301+
JSDispatchHandle handle;
1302+
auto it = js_dispatch_entries_map_.find(entry_id);
1303+
if (it != js_dispatch_entries_map_.end()) {
1304+
handle = it->second;
1305+
DCHECK_EQ(parameter_count, jdt->GetParameterCount(handle));
1306+
} else {
1307+
JSDispatchTable::Space* space =
1308+
IsolateForSandbox(isolate()).GetJSDispatchTableSpaceFor(
1309+
host->address());
1310+
handle = jdt->AllocateAndInitializeEntry(space, parameter_count);
1311+
js_dispatch_entries_map_[entry_id] = handle;
1312+
}
1313+
1314+
host->Relaxed_WriteField<JSDispatchHandle>(slot_accessor.offset(), handle);
1315+
1316+
return 1;
1317+
#else
1318+
UNREACHABLE();
1319+
#endif // V8_ENABLE_SANDBOX
1320+
}
1321+
12851322
template <typename IsolateT>
12861323
template <typename SlotAccessor>
12871324
int Deserializer<IsolateT>::ReadProtectedPointerPrefix(

src/snapshot/deserializer.h

+7
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ class Deserializer : public SerializerDeserializer {
225225
int ReadInitializeSelfIndirectPointer(uint8_t data,
226226
SlotAccessor slot_accessor);
227227
template <typename SlotAccessor>
228+
int ReadAllocateJSDispatchEntry(uint8_t data, SlotAccessor slot_accessor);
229+
template <typename SlotAccessor>
228230
int ReadProtectedPointerPrefix(uint8_t data, SlotAccessor slot_accessor);
229231
template <typename SlotAccessor>
230232
int ReadRootArrayConstants(uint8_t data, SlotAccessor slot_accessor);
@@ -284,6 +286,11 @@ class Deserializer : public SerializerDeserializer {
284286
// Vector of allocated objects that can be accessed by a backref, by index.
285287
std::vector<Handle<HeapObject>> back_refs_;
286288

289+
// Map of JSDispatchTable entries. When such an entry is serialized, we also
290+
// serialize an ID of the entry, which then allows the deserializer to
291+
// correctly reconstruct shared table entries.
292+
std::unordered_map<int, JSDispatchHandle> js_dispatch_entries_map_;
293+
287294
// Unresolved forward references (registered with kRegisterPendingForwardRef)
288295
// are collected in order as (object, field offset) pairs. The subsequent
289296
// forward ref resolution (with kResolvePendingForwardRef) accesses this

src/snapshot/serializer-deserializer.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ class SerializerDeserializer : public RootVisitor {
3737

3838
// clang-format off
3939
#define UNUSED_SERIALIZER_BYTE_CODES(V) \
40-
/* Free range 0x20..0x2f */ \
41-
V(0x20) V(0x21) V(0x22) V(0x23) V(0x24) V(0x25) V(0x26) V(0x27) \
40+
/* Free range 0x21..0x2f */ \
41+
V(0x21) V(0x22) V(0x23) V(0x24) V(0x25) V(0x26) V(0x27) \
4242
V(0x28) V(0x29) V(0x2a) V(0x2b) V(0x2c) V(0x2d) V(0x2e) V(0x2f) \
4343
/* Free range 0x30..0x3f */ \
4444
V(0x30) V(0x31) V(0x32) V(0x33) V(0x34) V(0x35) V(0x36) V(0x37) \
@@ -158,6 +158,10 @@ class SerializerDeserializer : public RootVisitor {
158158
// that it will be deserialized before any inner objects, which may require
159159
// the pointer table entry for back reference to the trusted object.
160160
kInitializeSelfIndirectPointer,
161+
// This bytecode instructs the deserializer to allocate an entry in the
162+
// JSDispatchTable for the host object and store the corresponding dispatch
163+
// handle into the current slot.
164+
kAllocateJSDispatchEntry,
161165
// A prefix indicating that the following object is referenced through a
162166
// protected pointer, i.e. a pointer from one trusted object to another.
163167
kProtectedPointerPrefix,

src/snapshot/serializer.cc

+15-13
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "src/objects/slots-inl.h"
2222
#include "src/objects/slots.h"
2323
#include "src/objects/smi.h"
24+
#include "src/sandbox/js-dispatch-table-inl.h"
2425
#include "src/snapshot/embedded/embedded-data.h"
2526
#include "src/snapshot/serializer-deserializer.h"
2627
#include "src/snapshot/serializer-inl.h"
@@ -1261,23 +1262,24 @@ void Serializer::ObjectSerializer::VisitProtectedPointer(
12611262
void Serializer::ObjectSerializer::VisitJSDispatchTableEntry(
12621263
Tagged<HeapObject> host, JSDispatchHandle handle) {
12631264
#ifdef V8_ENABLE_LEAPTIERING
1264-
// New dispatch table entries will be allocated during deserialization if
1265-
// necessary. Here we just serialize an empty handle.
1266-
// TODO(saelo): we could also emit a kInitializeJSDispatchHandle opcode here
1267-
// and then allocate a dispatch entry during deserialization when we
1268-
// encounter that. That way we don't need to hook into object post
1269-
// processing. If the dispatch handle is empty, we would just skip it here
1270-
// (and would then serialize the raw null handle, which is correct).
1265+
// If the slot is empty, we will skip it here and then just serialize the
1266+
// null handle as raw data.
1267+
if (handle == kNullJSDispatchHandle) return;
1268+
12711269
// TODO(saelo): we might want to call OutputRawData here, but for that we
12721270
// first need to pass the slot address to this method (e.g. as part of a
12731271
// JSDispatchHandleSlot struct).
1274-
static_assert(kJSDispatchHandleSize % kTaggedSize == 0);
1275-
sink_->Put(
1276-
FixedRawDataWithSize::Encode(kJSDispatchHandleSize >> kTaggedSizeLog2),
1277-
"FixedRawData");
1278-
sink_->PutRaw(reinterpret_cast<const uint8_t*>(&kNullJSDispatchHandle),
1279-
kJSDispatchHandleSize, "empty js dispatch handle");
1272+
12801273
bytes_processed_so_far_ += kJSDispatchHandleSize;
1274+
1275+
sink_->Put(kAllocateJSDispatchEntry, "AllocateJSDispatchEntry");
1276+
sink_->PutUint30(handle >> kJSDispatchHandleShift, "EntryID");
1277+
sink_->PutUint30(GetProcessWideJSDispatchTable()->GetParameterCount(handle),
1278+
"ParameterCount");
1279+
1280+
// TODO(saelo): in the future, we will probably also need to serialize the
1281+
// Code object here, then decode it in the deserializer and write it into the
1282+
// dispatch table entry.
12811283
#else
12821284
UNREACHABLE();
12831285
#endif // V8_ENABLE_LEAPTIERING

0 commit comments

Comments
 (0)