Skip to content

Commit 5559d1e

Browse files
rmacnak-googleCommit Queue
authored andcommitted
[vm] Avoid massive vtables for handles.
Implement type checks for handles using one virtual function and range checks instead of per-type virtual functions, which scale quadratically with the number of handle classes. out/ReleaseX64/exe.stripped/gen_snapshot 6886680 -> 6645512 (-3.5%) Cf. fa75e88 TEST=ci Change-Id: Ic5f78a5843e4c612ae1ad5981d055444f78c178a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/423922 Reviewed-by: Alexander Aprelev <[email protected]> Commit-Queue: Ryan Macnak <[email protected]>
1 parent 2118f18 commit 5559d1e

File tree

2 files changed

+133
-2
lines changed

2 files changed

+133
-2
lines changed

runtime/vm/class_id.h

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ static constexpr intptr_t kClassIdTagMax = (1 << 20) - 1;
5252
V(ContextScope) \
5353
V(Sentinel) \
5454
V(SingleTargetCache) \
55-
V(UnlinkedCall) \
5655
V(MonomorphicSmiableCall) \
5756
V(CallSiteData) \
57+
V(UnlinkedCall) \
5858
V(ICData) \
5959
V(MegamorphicCache) \
6060
V(SubtypeTestCache) \
@@ -210,6 +210,86 @@ static constexpr intptr_t kClassIdTagMax = (1 << 20) - 1;
210210
V(Object) \
211211
CLASS_LIST_NO_OBJECT(V)
212212

213+
#define LEAF_HANDLE_LIST(V) \
214+
V(Class) \
215+
V(PatchClass) \
216+
V(Function) \
217+
V(TypeParameters) \
218+
V(ClosureData) \
219+
V(FfiTrampolineData) \
220+
V(Field) \
221+
V(Script) \
222+
V(Library) \
223+
V(Namespace) \
224+
V(KernelProgramInfo) \
225+
V(WeakSerializationReference) \
226+
V(WeakArray) \
227+
V(Code) \
228+
V(Bytecode) \
229+
V(Instructions) \
230+
V(InstructionsSection) \
231+
V(InstructionsTable) \
232+
V(ObjectPool) \
233+
V(PcDescriptors) \
234+
V(CodeSourceMap) \
235+
V(CompressedStackMaps) \
236+
V(LocalVarDescriptors) \
237+
V(ExceptionHandlers) \
238+
V(Context) \
239+
V(ContextScope) \
240+
V(Sentinel) \
241+
V(SingleTargetCache) \
242+
V(UnlinkedCall) \
243+
V(MonomorphicSmiableCall) \
244+
V(ICData) \
245+
V(MegamorphicCache) \
246+
V(SubtypeTestCache) \
247+
V(LoadingUnit) \
248+
V(ApiError) \
249+
V(LanguageError) \
250+
V(UnhandledException) \
251+
V(UnwindError) \
252+
V(LibraryPrefix) \
253+
V(TypeArguments) \
254+
V(Type) \
255+
V(FunctionType) \
256+
V(RecordType) \
257+
V(TypeParameter) \
258+
V(Finalizer) \
259+
V(NativeFinalizer) \
260+
V(FinalizerEntry) \
261+
V(Closure) \
262+
V(Smi) \
263+
V(Mint) \
264+
V(Double) \
265+
V(Bool) \
266+
V(Float32x4) \
267+
V(Int32x4) \
268+
V(Float64x2) \
269+
V(Record) \
270+
V(TypedData) \
271+
V(ExternalTypedData) \
272+
V(TypedDataView) \
273+
V(Pointer) \
274+
V(DynamicLibrary) \
275+
V(Capability) \
276+
V(ReceivePort) \
277+
V(SendPort) \
278+
V(StackTrace) \
279+
V(SuspendState) \
280+
V(RegExp) \
281+
V(WeakProperty) \
282+
V(WeakReference) \
283+
V(MirrorReference) \
284+
V(FutureOr) \
285+
V(UserTag) \
286+
V(TransferableTypedData) \
287+
V(Map) \
288+
V(Set) \
289+
V(Array) \
290+
V(GrowableObjectArray) \
291+
V(String)
292+
213293
enum ClassId : intptr_t {
214294
// Illegal class id.
215295
kIllegalCid = 0,
@@ -307,6 +387,13 @@ inline bool IsInternalOnlyClassId(intptr_t index) {
307387
return index <= kLastInternalOnlyCid;
308388
}
309389

390+
inline bool IsCallSiteDataClassId(intptr_t index) {
391+
COMPILE_ASSERT(kCallSiteDataCid + 1 == kUnlinkedCallCid &&
392+
kCallSiteDataCid + 2 == kICDataCid &&
393+
kCallSiteDataCid + 3 == kMegamorphicCacheCid);
394+
return (index >= kCallSiteDataCid && index <= kMegamorphicCacheCid);
395+
}
396+
310397
// Make sure this function is updated when new Error types are added.
311398
static const ClassId kFirstErrorCid = kErrorCid;
312399
static const ClassId kLastErrorCid = kUnwindErrorCid;
@@ -323,6 +410,14 @@ inline bool IsErrorClassId(intptr_t index) {
323410
return (index >= kFirstErrorCid && index <= kLastErrorCid);
324411
}
325412

413+
inline bool IsAbstractTypeClassId(intptr_t index) {
414+
COMPILE_ASSERT(kAbstractTypeCid + 1 == kTypeCid &&
415+
kAbstractTypeCid + 2 == kFunctionTypeCid &&
416+
kAbstractTypeCid + 3 == kRecordTypeCid &&
417+
kAbstractTypeCid + 4 == kTypeParameterCid);
418+
return (index >= kAbstractTypeCid && index <= kTypeParameterCid);
419+
}
420+
326421
inline bool IsConcreteTypeClassId(intptr_t index) {
327422
// Make sure to update when new AbstractType subclasses are added.
328423
COMPILE_ASSERT(kFunctionTypeCid == kTypeCid + 1 &&

runtime/vm/object.h

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ class BaseTextBuffer;
119119
object##Ptr ptr() const { \
120120
return static_cast<object##Ptr>(ptr_); \
121121
} \
122+
intptr_t HandleTag() const { \
123+
return k##object##Cid; \
124+
} \
122125
bool Is##object() const { \
123126
return true; \
124127
} \
@@ -356,9 +359,42 @@ class Object {
356359
inline ClassPtr clazz() const;
357360
static intptr_t tags_offset() { return OFFSET_OF(UntaggedObject, tags_); }
358361

362+
virtual intptr_t HandleTag() const { return kObjectCid; }
363+
364+
#define DEFINE_LEAF_CHECK(clazz) \
365+
bool Is##clazz() const { return HandleTag() == k##clazz##Cid; }
366+
LEAF_HANDLE_LIST(DEFINE_LEAF_CHECK)
367+
#undef DEFINE_LEAF_CHECK
368+
bool IsTypedDataBase() const {
369+
switch (HandleTag()) {
370+
case kTypedDataBaseCid:
371+
case kTypedDataCid:
372+
case kExternalTypedDataCid:
373+
case kTypedDataViewCid:
374+
return true;
375+
default:
376+
return false;
377+
}
378+
}
379+
bool IsFinalizerBase() const {
380+
switch (HandleTag()) {
381+
case kFinalizerBaseCid:
382+
case kFinalizerCid:
383+
case kNativeFinalizerCid:
384+
return true;
385+
default:
386+
return false;
387+
}
388+
}
389+
bool IsCallSiteData() const { return IsCallSiteDataClassId(HandleTag()); }
390+
bool IsError() const { return IsErrorClassId(HandleTag()); }
391+
bool IsNumber() const { return IsNumberClassId(HandleTag()); }
392+
bool IsInteger() const { return IsIntegerClassId(HandleTag()); }
393+
bool IsInstance() const { return HandleTag() >= kInstanceCid; }
394+
bool IsAbstractType() const { return IsAbstractTypeClassId(HandleTag()); }
395+
359396
// Class testers.
360397
#define DEFINE_CLASS_TESTER(clazz) \
361-
virtual bool Is##clazz() const { return false; } \
362398
static bool Is##clazz##NoHandle(ObjectPtr ptr) { \
363399
/* Use a stack handle to make RawCast safe in contexts where handles */ \
364400
/* should not be allocated, such as GC or runtime transitions. Not */ \

0 commit comments

Comments
 (0)