dart-sdk/runtime/vm/class_id.h
Tess Strickland 0d3ade255b [vm/compiler] Limit exposure of untagged pointers to managed memory.
After https://dart-review.googlesource.com/c/sdk/+/330600, there were
more chances for the optimizing compiler to introduce or move
GC-triggering instructions like allocations or boxings between the
retrieval of an untagged pointer to GC-moveable memory and its use.

To limit the chance of this happening, this CL removes the explicit
loading of the untagged payload address when building the initial
flow graph in most cases when the array is not known to be an external
array (an external string, an external typed data object, or an FFI
Pointer).

The remaining case is during view allocation, which extracts the
payload address of the base typed data object underlying the view
(which may be GC-movable) to calculate the payload address that should
be stored in the data field of the view object. See
https://github.com/dart-lang/sdk/issues/54884.

During canonicalization of LoadIndexed, StoreIndexed, and MemoryCopy
instructions, if the cid of an array input is an external array
(external string, external typed data object, or Pointer), then a
LoadField instruction that extracts the untagged payload address
is inserted before the instruction and the corresponding input is
rebound to that LoadField instruction.

Once all compiler passes that involve code motion have been performed,
a new pass looks for LoadIndexed, StoreIndexed, or MemoryCopy where
the cid stored in the instruction for the array is a typed data cid.
In these cases, if the array is not an internal typed data object,
then the payload address is extracted. Waiting until this point ensures
that no GC-triggering instructions are inserted between the extraction
of the payload address and the use. (Internal typed data objects are
left as-is because the payload address is inside the object itself
and doesn't require indirection through the data field of the object).

This CL also replaces code conditional on the array cid with code
that is instead conditional on the array element representation in
cases where it makes sense to do so, since this is a less brittle
check than checking the array cid (e.g., checking for kUnboxedInt8
to load, store, or copy an signed byte from an array instead of
listing all possible array cids that store signed bytes).

This CL also fixes an issue with the ARM64 assembler where calling
LoadFromOffset with an Address that has a non-Offset type would
silently generate bad code instead of triggering the ASSERT in
PrepareLargeOffset.

TEST=vm/dart/typed_list_index_checkbound_il_test

Issue: https://github.com/dart-lang/sdk/issues/54710
Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-release-ia32-try
Change-Id: I25b5f314943e9254d3d28986d720a5d47f12feeb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/352363
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2024-03-22 10:12:39 +00:00

565 lines
27 KiB
C++

// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_VM_CLASS_ID_H_
#define RUNTIME_VM_CLASS_ID_H_
// This header defines the list of VM implementation classes and their ids.
//
// Note: we assume that all builds of Dart VM use exactly the same class ids
// for these classes.
#include "platform/assert.h"
#include "vm/globals.h"
namespace dart {
// Large enough to contain the class-id part of the object header. See
// UntaggedObject. Signed to be comparable to intptr_t.
typedef int32_t ClassIdTagType;
static constexpr intptr_t kClassIdTagMax = (1 << 20) - 1;
// Classes that are not subclasses of Instance and only handled by the VM,
// but do not require any special handling other than being a predefined class.
#define CLASS_LIST_INTERNAL_ONLY(V) \
V(Class) \
V(PatchClass) \
V(Function) \
V(TypeParameters) \
V(ClosureData) \
V(FfiTrampolineData) \
V(Field) \
V(Script) \
V(Library) \
V(Namespace) \
V(KernelProgramInfo) \
V(WeakSerializationReference) \
V(WeakArray) \
V(Code) \
V(Instructions) \
V(InstructionsSection) \
V(InstructionsTable) \
V(ObjectPool) \
V(PcDescriptors) \
V(CodeSourceMap) \
V(CompressedStackMaps) \
V(LocalVarDescriptors) \
V(ExceptionHandlers) \
V(Context) \
V(ContextScope) \
V(Sentinel) \
V(SingleTargetCache) \
V(UnlinkedCall) \
V(MonomorphicSmiableCall) \
V(CallSiteData) \
V(ICData) \
V(MegamorphicCache) \
V(SubtypeTestCache) \
V(LoadingUnit) \
V(Error) \
V(ApiError) \
V(LanguageError) \
V(UnhandledException) \
V(UnwindError)
// Classes that are subclasses of Instance and neither part of a specific cid
// grouping like strings, arrays, etc. nor require special handling outside of
// being a predefined class.
#define CLASS_LIST_INSTANCE_SINGLETONS(V) \
V(Instance) \
V(LibraryPrefix) \
V(TypeArguments) \
V(AbstractType) \
V(Type) \
V(FunctionType) \
V(RecordType) \
V(TypeParameter) \
V(FinalizerBase) \
V(Finalizer) \
V(NativeFinalizer) \
V(FinalizerEntry) \
V(Closure) \
V(Number) \
V(Integer) \
V(Smi) \
V(Mint) \
V(Double) \
V(Bool) \
V(Float32x4) \
V(Int32x4) \
V(Float64x2) \
V(Record) \
V(TypedDataBase) \
V(TypedData) \
V(ExternalTypedData) \
V(TypedDataView) \
V(Pointer) \
V(DynamicLibrary) \
V(Capability) \
V(ReceivePort) \
V(SendPort) \
V(StackTrace) \
V(SuspendState) \
V(RegExp) \
V(WeakProperty) \
V(WeakReference) \
V(MirrorReference) \
V(FutureOr) \
V(UserTag) \
V(TransferableTypedData)
#define CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY_NOR_MAP(V) \
CLASS_LIST_INTERNAL_ONLY(V) CLASS_LIST_INSTANCE_SINGLETONS(V)
#define CLASS_LIST_MAPS(V) \
V(Map) \
V(ConstMap)
#define CLASS_LIST_SETS(V) \
V(Set) \
V(ConstSet)
#define CLASS_LIST_FIXED_LENGTH_ARRAYS(V) \
V(Array) \
V(ImmutableArray)
#define CLASS_LIST_ARRAYS(V) \
CLASS_LIST_FIXED_LENGTH_ARRAYS(V) \
V(GrowableObjectArray)
#define CLASS_LIST_STRINGS(V) \
V(String) \
V(OneByteString) \
V(TwoByteString)
#define CLASS_LIST_TYPED_DATA(V) \
V(Int8Array) \
V(Uint8Array) \
V(Uint8ClampedArray) \
V(Int16Array) \
V(Uint16Array) \
V(Int32Array) \
V(Uint32Array) \
V(Int64Array) \
V(Uint64Array) \
V(Float32Array) \
V(Float64Array) \
V(Float32x4Array) \
V(Int32x4Array) \
V(Float64x2Array)
#define CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(V) \
V(Int8) \
V(Int16) \
V(Int32) \
V(Int64) \
V(Uint8) \
V(Uint16) \
V(Uint32) \
V(Uint64) \
V(Float) \
V(Double)
#define CLASS_LIST_FFI_TYPE_MARKER(V) \
CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(V) \
V(Void) \
V(Handle) \
V(Bool)
#define CLASS_LIST_FFI(V) \
V(NativeFunction) \
CLASS_LIST_FFI_TYPE_MARKER(V) \
V(NativeType) \
V(Struct)
#define DART_CLASS_LIST_TYPED_DATA(V) \
V(Int8) \
V(Uint8) \
V(Uint8Clamped) \
V(Int16) \
V(Uint16) \
V(Int32) \
V(Uint32) \
V(Int64) \
V(Uint64) \
V(Float32) \
V(Float64) \
V(Float32x4) \
V(Int32x4) \
V(Float64x2)
#define CLASS_LIST_FOR_HANDLES(V) \
CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY_NOR_MAP(V) \
V(Map) \
V(Set) \
V(Array) \
V(GrowableObjectArray) \
V(String)
#define CLASS_LIST_NO_OBJECT(V) \
CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY_NOR_MAP(V) \
CLASS_LIST_MAPS(V) \
CLASS_LIST_SETS(V) \
CLASS_LIST_ARRAYS(V) \
CLASS_LIST_STRINGS(V)
#define CLASS_LIST(V) \
V(Object) \
CLASS_LIST_NO_OBJECT(V)
enum ClassId : intptr_t {
// Illegal class id.
kIllegalCid = 0,
// Pseudo class id for native pointers, the heap should never see an
// object with this class id.
kNativePointer,
// The following entries describes classes for pseudo-objects in the heap
// that should never be reachable from live objects. Free list elements
// maintain the free list for old space, and forwarding corpses are used to
// implement one-way become.
kFreeListElement,
kForwardingCorpse,
// List of Ids for predefined classes.
#define DEFINE_OBJECT_KIND(clazz) k##clazz##Cid,
CLASS_LIST(DEFINE_OBJECT_KIND)
#undef DEFINE_OBJECT_KIND
// clang-format off
#define DEFINE_OBJECT_KIND(clazz) kFfi##clazz##Cid,
CLASS_LIST_FFI(DEFINE_OBJECT_KIND)
#undef DEFINE_OBJECT_KIND
#define DEFINE_OBJECT_KIND(clazz) \
kTypedData##clazz##Cid, \
kTypedData##clazz##ViewCid, \
kExternalTypedData##clazz##Cid, \
kUnmodifiableTypedData##clazz##ViewCid,
CLASS_LIST_TYPED_DATA(DEFINE_OBJECT_KIND)
#undef DEFINE_OBJECT_KIND
kByteDataViewCid,
kUnmodifiableByteDataViewCid,
kByteBufferCid,
// clang-format on
// The following entries do not describe a predefined class, but instead
// are class indexes for pre-allocated instances (Null, dynamic, void, Never).
kNullCid,
kDynamicCid,
kVoidCid,
kNeverCid,
kNumPredefinedCids,
};
// Keep these in sync with the cid numbering above.
const int kTypedDataCidRemainderInternal = 0;
const int kTypedDataCidRemainderView = 1;
const int kTypedDataCidRemainderExternal = 2;
const int kTypedDataCidRemainderUnmodifiable = 3;
const int kNumTypedDataCidRemainders = kTypedDataCidRemainderUnmodifiable + 1;
// Class Id predicates.
bool IsInternalOnlyClassId(intptr_t index);
bool IsErrorClassId(intptr_t index);
bool IsNumberClassId(intptr_t index);
bool IsIntegerClassId(intptr_t index);
bool IsStringClassId(intptr_t index);
bool IsOneByteStringClassId(intptr_t index);
bool IsBuiltinListClassId(intptr_t index);
bool IsTypeClassId(intptr_t index);
bool IsTypedDataBaseClassId(intptr_t index);
bool IsTypedDataClassId(intptr_t index);
bool IsTypedDataViewClassId(intptr_t index);
bool IsExternalTypedDataClassId(intptr_t index);
bool IsFfiPointerClassId(intptr_t index);
bool IsFfiTypeClassId(intptr_t index);
bool IsFfiDynamicLibraryClassId(intptr_t index);
bool IsInternalVMdefinedClassId(intptr_t index);
bool IsImplicitFieldClassId(intptr_t index);
// Should be used for looping over non-Object internal-only cids.
constexpr intptr_t kFirstInternalOnlyCid = kClassCid;
constexpr intptr_t kLastInternalOnlyCid = kUnwindErrorCid;
// Use the currently surrounding cids to check that no new classes have been
// added to the beginning or end of CLASS_LIST_INTERNAL_ONLY without adjusting
// the above definitions.
COMPILE_ASSERT(kFirstInternalOnlyCid == kObjectCid + 1);
COMPILE_ASSERT(kInstanceCid == kLastInternalOnlyCid + 1);
// Returns true for any class id that either does not correspond to a real
// class, like kIllegalCid or kForwardingCorpse, or that is internal to the VM
// and should not be exposed directly to user code.
inline bool IsInternalOnlyClassId(intptr_t index) {
// Fix the condition below if these become non-contiguous.
COMPILE_ASSERT(kIllegalCid + 1 == kNativePointer &&
kIllegalCid + 2 == kFreeListElement &&
kIllegalCid + 3 == kForwardingCorpse &&
kIllegalCid + 4 == kObjectCid &&
kIllegalCid + 5 == kFirstInternalOnlyCid);
return index <= kLastInternalOnlyCid;
}
// Make sure this function is updated when new Error types are added.
static const ClassId kFirstErrorCid = kErrorCid;
static const ClassId kLastErrorCid = kUnwindErrorCid;
COMPILE_ASSERT(kFirstErrorCid == kErrorCid &&
kApiErrorCid == kFirstErrorCid + 1 &&
kLanguageErrorCid == kFirstErrorCid + 2 &&
kUnhandledExceptionCid == kFirstErrorCid + 3 &&
kUnwindErrorCid == kFirstErrorCid + 4 &&
kLastErrorCid == kUnwindErrorCid &&
// Change if needed for detecting a new error added at the end.
kLastInternalOnlyCid == kLastErrorCid);
inline bool IsErrorClassId(intptr_t index) {
return (index >= kFirstErrorCid && index <= kLastErrorCid);
}
inline bool IsConcreteTypeClassId(intptr_t index) {
// Make sure to update when new AbstractType subclasses are added.
COMPILE_ASSERT(kFunctionTypeCid == kTypeCid + 1 &&
kRecordTypeCid == kTypeCid + 2 &&
kTypeParameterCid == kTypeCid + 3);
return (index >= kTypeCid && index <= kTypeParameterCid);
}
inline bool IsNumberClassId(intptr_t index) {
// Make sure this function is updated when new Number types are added.
COMPILE_ASSERT(kIntegerCid == kNumberCid + 1 && kSmiCid == kNumberCid + 2 &&
kMintCid == kNumberCid + 3 && kDoubleCid == kNumberCid + 4);
return (index >= kNumberCid && index <= kDoubleCid);
}
inline bool IsIntegerClassId(intptr_t index) {
// Make sure this function is updated when new Integer types are added.
COMPILE_ASSERT(kSmiCid == kIntegerCid + 1 && kMintCid == kIntegerCid + 2);
return (index >= kIntegerCid && index <= kMintCid);
}
// Make sure this check is updated when new StringCid types are added.
COMPILE_ASSERT(kOneByteStringCid == kStringCid + 1 &&
kTwoByteStringCid == kStringCid + 2);
inline bool IsStringClassId(intptr_t index) {
return (index >= kStringCid && index <= kTwoByteStringCid);
}
inline bool IsOneByteStringClassId(intptr_t index) {
return (index == kOneByteStringCid);
}
inline bool IsArrayClassId(intptr_t index) {
COMPILE_ASSERT(kImmutableArrayCid == kArrayCid + 1);
COMPILE_ASSERT(kGrowableObjectArrayCid == kArrayCid + 2);
return (index >= kArrayCid && index <= kGrowableObjectArrayCid);
}
inline bool IsBuiltinListClassId(intptr_t index) {
// Make sure this function is updated when new builtin List types are added.
return (IsArrayClassId(index) || IsTypedDataBaseClassId(index) ||
(index == kByteBufferCid));
}
inline bool IsTypeClassId(intptr_t index) {
// Only Type, FunctionType and RecordType can be encountered as instance
// types at runtime.
return index == kTypeCid || index == kFunctionTypeCid ||
index == kRecordTypeCid;
}
static const ClassId kFirstTypedDataCid = kTypedDataInt8ArrayCid;
static const ClassId kLastTypedDataCid =
kUnmodifiableTypedDataFloat64x2ArrayViewCid;
// Make sure the following checks are updated when adding new TypedData types.
// The following asserts assume this.
COMPILE_ASSERT(kTypedDataCidRemainderInternal == 0);
// Ensure that each typed data type comes in internal/view/external variants
// next to each other.
COMPILE_ASSERT(kTypedDataInt8ArrayCid + kTypedDataCidRemainderView ==
kTypedDataInt8ArrayViewCid);
COMPILE_ASSERT(kTypedDataInt8ArrayCid + kTypedDataCidRemainderExternal ==
kExternalTypedDataInt8ArrayCid);
COMPILE_ASSERT(kTypedDataInt8ArrayCid + kTypedDataCidRemainderUnmodifiable ==
kUnmodifiableTypedDataInt8ArrayViewCid);
// Ensure the order of the typed data members in 3-step.
COMPILE_ASSERT(kFirstTypedDataCid == kTypedDataInt8ArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 1 * kNumTypedDataCidRemainders ==
kTypedDataUint8ArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 2 * kNumTypedDataCidRemainders ==
kTypedDataUint8ClampedArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 3 * kNumTypedDataCidRemainders ==
kTypedDataInt16ArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 4 * kNumTypedDataCidRemainders ==
kTypedDataUint16ArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 5 * kNumTypedDataCidRemainders ==
kTypedDataInt32ArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 6 * kNumTypedDataCidRemainders ==
kTypedDataUint32ArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 7 * kNumTypedDataCidRemainders ==
kTypedDataInt64ArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 8 * kNumTypedDataCidRemainders ==
kTypedDataUint64ArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 9 * kNumTypedDataCidRemainders ==
kTypedDataFloat32ArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 10 * kNumTypedDataCidRemainders ==
kTypedDataFloat64ArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 11 * kNumTypedDataCidRemainders ==
kTypedDataFloat32x4ArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 12 * kNumTypedDataCidRemainders ==
kTypedDataInt32x4ArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 13 * kNumTypedDataCidRemainders ==
kTypedDataFloat64x2ArrayCid);
COMPILE_ASSERT(kFirstTypedDataCid + 13 * kNumTypedDataCidRemainders +
kTypedDataCidRemainderUnmodifiable ==
kLastTypedDataCid);
// Checks for possible new typed data entries added before or after the current
// entries.
COMPILE_ASSERT(kFfiStructCid + 1 == kFirstTypedDataCid);
COMPILE_ASSERT(kLastTypedDataCid + 1 == kByteDataViewCid);
inline bool IsTypedDataBaseClassId(intptr_t index) {
return index >= kFirstTypedDataCid && index <= kLastTypedDataCid;
}
inline bool IsTypedDataClassId(intptr_t index) {
return IsTypedDataBaseClassId(index) &&
((index - kFirstTypedDataCid) % kNumTypedDataCidRemainders) ==
kTypedDataCidRemainderInternal;
}
inline bool IsTypedDataViewClassId(intptr_t index) {
const bool is_byte_data_view = index == kByteDataViewCid;
return is_byte_data_view ||
(IsTypedDataBaseClassId(index) &&
((index - kFirstTypedDataCid) % kNumTypedDataCidRemainders) ==
kTypedDataCidRemainderView);
}
inline bool IsExternalTypedDataClassId(intptr_t index) {
return IsTypedDataBaseClassId(index) &&
((index - kFirstTypedDataCid) % kNumTypedDataCidRemainders) ==
kTypedDataCidRemainderExternal;
}
inline bool IsUnmodifiableTypedDataViewClassId(intptr_t index) {
const bool is_byte_data_view = index == kUnmodifiableByteDataViewCid;
return is_byte_data_view ||
(IsTypedDataBaseClassId(index) &&
((index - kFirstTypedDataCid) % kNumTypedDataCidRemainders) ==
kTypedDataCidRemainderUnmodifiable);
}
inline bool IsClampedTypedDataBaseClassId(intptr_t index) {
if (!IsTypedDataBaseClassId(index)) return false;
const intptr_t internal_cid =
index - ((index - kFirstTypedDataCid) % kNumTypedDataCidRemainders) +
kTypedDataCidRemainderInternal;
// Currently, the only clamped typed data arrays are Uint8.
return internal_cid == kTypedDataUint8ClampedArrayCid;
}
// Whether the given cid is an external array cid, that is, an array where
// the payload is not in GC-managed memory.
inline bool IsExternalPayloadClassId(classid_t cid) {
return cid == kPointerCid || IsExternalTypedDataClassId(cid);
}
// For predefined cids only. Refer to Class::is_deeply_immutable for
// instances of non-predefined classes.
//
// Having the `@pragma('vm:deeply-immutable')`, which means statically proven
// deeply immutable, implies true for this function. The other way around is not
// guaranteed, predefined classes can be marked deeply immutable in the VM while
// not having their subtypes or super type being deeply immutable.
//
// Keep consistent with runtime/docs/deeply_immutable.md.
inline bool IsDeeplyImmutableCid(intptr_t predefined_cid) {
ASSERT(predefined_cid < kNumPredefinedCids);
return IsStringClassId(predefined_cid) || predefined_cid == kNumberCid ||
predefined_cid == kIntegerCid || predefined_cid == kSmiCid ||
predefined_cid == kMintCid || predefined_cid == kNeverCid ||
predefined_cid == kSentinelCid || predefined_cid == kStackTraceCid ||
predefined_cid == kDoubleCid || predefined_cid == kFloat32x4Cid ||
predefined_cid == kFloat64x2Cid || predefined_cid == kInt32x4Cid ||
predefined_cid == kSendPortCid || predefined_cid == kCapabilityCid ||
predefined_cid == kRegExpCid || predefined_cid == kBoolCid ||
predefined_cid == kNullCid || predefined_cid == kPointerCid ||
predefined_cid == kTypeCid || predefined_cid == kRecordTypeCid ||
predefined_cid == kFunctionTypeCid;
}
inline bool IsShallowlyImmutableCid(intptr_t predefined_cid) {
ASSERT(predefined_cid < kNumPredefinedCids);
// TODO(https://dartbug.com/55136): Mark kClosureCid as shallowly imutable.
return IsUnmodifiableTypedDataViewClassId(predefined_cid);
}
// See documentation on ImmutableBit in raw_object.h
inline bool ShouldHaveImmutabilityBitSetCid(intptr_t predefined_cid) {
ASSERT(predefined_cid < kNumPredefinedCids);
return IsDeeplyImmutableCid(predefined_cid) ||
IsShallowlyImmutableCid(predefined_cid);
}
inline bool IsFfiTypeClassId(intptr_t index) {
switch (index) {
case kPointerCid:
case kFfiNativeFunctionCid:
#define CASE_FFI_CID(name) case kFfi##name##Cid:
CLASS_LIST_FFI_TYPE_MARKER(CASE_FFI_CID)
#undef CASE_FFI_CID
return true;
default:
return false;
}
UNREACHABLE();
}
inline bool IsFfiPredefinedClassId(classid_t class_id) {
switch (class_id) {
case kPointerCid:
case kDynamicLibraryCid:
#define CASE_FFI_CID(name) case kFfi##name##Cid:
CLASS_LIST_FFI(CASE_FFI_CID)
#undef CASE_FFI_CID
return true;
default:
return false;
}
UNREACHABLE();
}
inline bool IsFfiPointerClassId(intptr_t index) {
return index == kPointerCid;
}
inline bool IsFfiDynamicLibraryClassId(intptr_t index) {
return index == kDynamicLibraryCid;
}
inline bool IsInternalVMdefinedClassId(intptr_t index) {
return ((index < kNumPredefinedCids) && !IsImplicitFieldClassId(index));
}
// This is a set of classes that are not Dart classes whose representation
// is defined by the VM but are used in the VM code by computing the
// implicit field offsets of the various fields in the dart object.
inline bool IsImplicitFieldClassId(intptr_t index) {
return index == kByteBufferCid;
}
COMPILE_ASSERT(kByteBufferCid + 1 == kNullCid);
} // namespace dart
#endif // RUNTIME_VM_CLASS_ID_H_