f98a2138b7
When uploading CLs, the presubmit checks verify that the lines in the diff are formatted correctly according to `git cl format runtime`. However, when `buildtools/<os>-<arch>/clang/bin/clang-format` is updated, it does not force reformatting of files that would be reformatted. This leads to two issues: * Inconsistent style within the code base and within a single file. * Spurious reformatting in CLs when (1) clang-format is used on the whole file, or (2) the diff lines overlap. `clang-format` doesn't change that frequently, so in general this is not a large issue, but I've seen a bit too many "spurious formatting, please revert" comments on CLs recently. This CL formats the runtime to be in line with the current pinned `clang-format`: ``` $ find runtime/ -iname *.h -o -iname *.cc | xargs buildtools/mac-arm64/clang/bin/clang-format -i ``` `git cl format` (which only formats changed lines, and does so with `clang-format`) seems to not agree with itself, or clang-format, or cpplint in a handful of places. This CL adds `// clang-format off` for these. (See previous patchsets for the specific instances.) TEST=A variety of bots including GCC, MacOS and Windows. Change-Id: I470892e898971899fda14bb3b8f2c8efefd67686 Cq-Include-Trybots: luci.dart.try:vm-gcc-linux-try,vm-ffi-qemu-linux-release-riscv64-try,vm-ffi-qemu-linux-release-arm-try,vm-aot-win-debug-x64-try,vm-win-debug-x64c-try,vm-mac-debug-x64-try,vm-mac-debug-arm64-try,vm-aot-linux-debug-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/362780 Reviewed-by: Ryan Macnak <rmacnak@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com>
641 lines
31 KiB
C++
641 lines
31 KiB
C++
// Copyright (c) 2018, 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.
|
|
|
|
// Slot is an abstraction that describes an readable (and possibly writeable)
|
|
// location within an object.
|
|
//
|
|
// In general slots follow the memory model for normal Dart fields - but can
|
|
// also be used to describe locations that don't have corresponding Field
|
|
// object, i.e. fields within native objects like arrays or contexts.
|
|
//
|
|
// Slot objects created by the compiler have an identity. If two slots F and G
|
|
// are different then compiler assumes that store into F can't alias a load
|
|
// from G and vice versa.
|
|
//
|
|
// All slots can be split into 4 categories:
|
|
//
|
|
// - slots for fields of native classes (Array, Closure, etc);
|
|
// - slots for type arguments;
|
|
// - slots for captured variable;
|
|
// - slots for normal Dart fields (e.g. those that Field object).
|
|
//
|
|
|
|
#ifndef RUNTIME_VM_COMPILER_BACKEND_SLOT_H_
|
|
#define RUNTIME_VM_COMPILER_BACKEND_SLOT_H_
|
|
|
|
#if defined(DART_PRECOMPILED_RUNTIME)
|
|
#error "AOT runtime should not use compiler sources (including header files)"
|
|
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
#include "vm/compiler/backend/compile_type.h"
|
|
#include "vm/compiler/backend/locations.h"
|
|
#include "vm/thread.h"
|
|
|
|
namespace dart {
|
|
|
|
class LocalScope;
|
|
class LocalVariable;
|
|
class ParsedFunction;
|
|
|
|
// The list of slots that correspond to nullable boxed fields of native
|
|
// Dart objects in the following format:
|
|
//
|
|
// V(class_name, underlying_type, field_name, exact_type, FINAL|VAR)
|
|
//
|
|
// - class_name and field_name specify the name of the host class and the name
|
|
// of the field respectively;
|
|
// - underlying_type: the Raw class which holds the field;
|
|
// - exact_type specifies exact type of the field (any load from this field
|
|
// would only yield instances of this type);
|
|
// - the last component specifies whether field behaves like a final field
|
|
// (i.e. initialized once at construction time and does not change after
|
|
// that) or like a non-final field.
|
|
#define NULLABLE_TAGGED_NATIVE_DART_SLOTS_LIST(V) \
|
|
V(Array, UntaggedArray, type_arguments, TypeArguments, FINAL) \
|
|
V(Finalizer, UntaggedFinalizer, type_arguments, TypeArguments, FINAL) \
|
|
V(FinalizerBase, UntaggedFinalizerBase, all_entries, Set, VAR) \
|
|
V(FinalizerBase, UntaggedFinalizerBase, detachments, Dynamic, VAR) \
|
|
V(FinalizerBase, UntaggedFinalizer, entries_collected, FinalizerEntry, VAR) \
|
|
V(FinalizerEntry, UntaggedFinalizerEntry, value, Dynamic, VAR) \
|
|
V(FinalizerEntry, UntaggedFinalizerEntry, detach, Dynamic, VAR) \
|
|
V(FinalizerEntry, UntaggedFinalizerEntry, token, Dynamic, VAR) \
|
|
V(FinalizerEntry, UntaggedFinalizerEntry, finalizer, FinalizerBase, VAR) \
|
|
V(FinalizerEntry, UntaggedFinalizerEntry, next, FinalizerEntry, VAR) \
|
|
V(Function, UntaggedFunction, signature, FunctionType, FINAL) \
|
|
V(Context, UntaggedContext, parent, Context, FINAL) \
|
|
V(Closure, UntaggedClosure, instantiator_type_arguments, TypeArguments, \
|
|
FINAL) \
|
|
V(Closure, UntaggedClosure, delayed_type_arguments, TypeArguments, FINAL) \
|
|
V(Closure, UntaggedClosure, function_type_arguments, TypeArguments, FINAL) \
|
|
V(FunctionType, UntaggedFunctionType, type_parameters, TypeParameters, \
|
|
FINAL) \
|
|
V(ReceivePort, UntaggedReceivePort, send_port, SendPort, FINAL) \
|
|
V(ReceivePort, UntaggedReceivePort, handler, Closure, VAR) \
|
|
V(ImmutableLinkedHashBase, UntaggedLinkedHashBase, index, \
|
|
TypedDataUint32Array, VAR) \
|
|
V(Instance, UntaggedInstance, native_fields_array, Dynamic, VAR) \
|
|
V(SuspendState, UntaggedSuspendState, function_data, Dynamic, VAR) \
|
|
V(SuspendState, UntaggedSuspendState, then_callback, Closure, VAR) \
|
|
V(SuspendState, UntaggedSuspendState, error_callback, Closure, VAR) \
|
|
V(TypeParameters, UntaggedTypeParameters, flags, Array, FINAL) \
|
|
V(TypeParameters, UntaggedTypeParameters, bounds, TypeArguments, FINAL) \
|
|
V(TypeParameters, UntaggedTypeParameters, defaults, TypeArguments, FINAL) \
|
|
V(WeakProperty, UntaggedWeakProperty, key, Dynamic, VAR) \
|
|
V(WeakProperty, UntaggedWeakProperty, value, Dynamic, VAR) \
|
|
V(WeakReference, UntaggedWeakReference, target, Dynamic, VAR) \
|
|
V(WeakReference, UntaggedWeakReference, type_arguments, TypeArguments, FINAL)
|
|
|
|
// The list of slots that correspond to non-nullable boxed fields of native
|
|
// Dart objects that contain integers in the following format:
|
|
//
|
|
// V(class_name, underlying_type, field_name, exact_type, FINAL|VAR)
|
|
//
|
|
// - class_name and field_name specify the name of the host class and the name
|
|
// of the field respectively;
|
|
// - underlying_type: the Raw class which holds the field;
|
|
// - exact_type specifies exact type of the field (any load from this field
|
|
// would only yield instances of this type);
|
|
// - the last component specifies whether field behaves like a final field
|
|
// (i.e. initialized once at construction time and does not change after
|
|
// that) or like a non-final field.
|
|
#define NONNULLABLE_INT_TAGGED_NATIVE_DART_SLOTS_LIST(V) \
|
|
V(Array, UntaggedArray, length, Smi, FINAL) \
|
|
V(Closure, UntaggedClosure, hash, Smi, VAR) \
|
|
V(GrowableObjectArray, UntaggedGrowableObjectArray, length, Smi, VAR) \
|
|
V(TypedDataBase, UntaggedTypedDataBase, length, Smi, FINAL) \
|
|
V(TypedDataView, UntaggedTypedDataView, offset_in_bytes, Smi, FINAL) \
|
|
V(String, UntaggedString, length, Smi, FINAL) \
|
|
V(LinkedHashBase, UntaggedLinkedHashBase, hash_mask, Smi, VAR) \
|
|
V(LinkedHashBase, UntaggedLinkedHashBase, used_data, Smi, VAR) \
|
|
V(LinkedHashBase, UntaggedLinkedHashBase, deleted_keys, Smi, VAR) \
|
|
V(ArgumentsDescriptor, UntaggedArray, type_args_len, Smi, FINAL) \
|
|
V(ArgumentsDescriptor, UntaggedArray, positional_count, Smi, FINAL) \
|
|
V(ArgumentsDescriptor, UntaggedArray, count, Smi, FINAL) \
|
|
V(ArgumentsDescriptor, UntaggedArray, size, Smi, FINAL) \
|
|
V(Record, UntaggedRecord, shape, Smi, FINAL) \
|
|
V(TypeArguments, UntaggedTypeArguments, hash, Smi, VAR) \
|
|
V(TypeArguments, UntaggedTypeArguments, length, Smi, FINAL) \
|
|
V(AbstractType, UntaggedTypeArguments, hash, Smi, VAR)
|
|
|
|
// The list of slots that correspond to non-nullable boxed fields of native
|
|
// Dart objects that do not contain integers in the following format:
|
|
//
|
|
// V(class_name, underlying_type, field_name, exact_type, FINAL|VAR)
|
|
//
|
|
// - class_name and field_name specify the name of the host class and the name
|
|
// of the field respectively;
|
|
// - underlying_type: the Raw class which holds the field;
|
|
// - exact_type specifies exact type of the field (any load from this field
|
|
// would only yield instances of this type);
|
|
// - the last component specifies whether field behaves like a final field
|
|
// (i.e. initialized once at construction time and does not change after
|
|
// that) or like a non-final field.
|
|
#define NONNULLABLE_NONINT_TAGGED_NATIVE_DART_SLOTS_LIST(V) \
|
|
V(Closure, UntaggedClosure, function, Function, FINAL) \
|
|
V(Closure, UntaggedClosure, context, Dynamic, FINAL) \
|
|
V(Finalizer, UntaggedFinalizer, callback, Closure, FINAL) \
|
|
V(NativeFinalizer, UntaggedFinalizer, callback, Pointer, FINAL) \
|
|
V(Function, UntaggedFunction, data, Dynamic, FINAL) \
|
|
V(FunctionType, UntaggedFunctionType, named_parameter_names, Array, FINAL) \
|
|
V(FunctionType, UntaggedFunctionType, parameter_types, Array, FINAL) \
|
|
V(GrowableObjectArray, UntaggedGrowableObjectArray, data, Array, VAR) \
|
|
V(TypedDataView, UntaggedTypedDataView, typed_data, Dynamic, FINAL) \
|
|
V(LinkedHashBase, UntaggedLinkedHashBase, index, TypedDataUint32Array, VAR) \
|
|
V(LinkedHashBase, UntaggedLinkedHashBase, data, Array, VAR) \
|
|
V(ImmutableLinkedHashBase, UntaggedLinkedHashBase, data, ImmutableArray, \
|
|
FINAL) \
|
|
V(TypeParameters, UntaggedTypeParameters, names, Array, FINAL) \
|
|
V(UnhandledException, UntaggedUnhandledException, exception, Dynamic, FINAL) \
|
|
V(UnhandledException, UntaggedUnhandledException, stacktrace, Dynamic, FINAL)
|
|
|
|
// List of slots that correspond to fields of native objects that contain
|
|
// unboxed values in the following format:
|
|
//
|
|
// V(class_name, underlying_type, field_name, representation, FINAL|VAR)
|
|
//
|
|
// - class_name and field_name specify the name of the host class and the name
|
|
// of the field respectively;
|
|
// - underlying_type: the Raw class which holds the field;
|
|
// - representation specifies the representation of the bits stored within
|
|
// the unboxed field (minus the kUnboxed prefix);
|
|
// - the last component specifies whether field behaves like a final field
|
|
// (i.e. initialized once at construction time and does not change after
|
|
// that) or like a non-final field.
|
|
//
|
|
// Note: As the underlying field is unboxed, these slots cannot be nullable.
|
|
//
|
|
// Note: Currently LoadFieldInstr::IsImmutableLengthLoad() assumes that no
|
|
// unboxed slots represent length loads.
|
|
#define UNBOXED_NATIVE_DART_SLOTS_LIST(V) \
|
|
V(AbstractType, UntaggedAbstractType, flags, Uint32, FINAL) \
|
|
V(ClosureData, UntaggedClosureData, packed_fields, Uint32, FINAL) \
|
|
V(FinalizerEntry, UntaggedFinalizerEntry, external_size, IntPtr, VAR) \
|
|
V(Function, UntaggedFunction, kind_tag, Uint32, FINAL) \
|
|
V(FunctionType, UntaggedFunctionType, packed_parameter_counts, Uint32, \
|
|
FINAL) \
|
|
V(FunctionType, UntaggedFunctionType, packed_type_parameter_counts, Uint16, \
|
|
FINAL) \
|
|
V(SubtypeTestCache, UntaggedSubtypeTestCache, num_inputs, Uint32, FINAL)
|
|
|
|
// Native slots containing untagged addresses that do not exist in JIT mode.
|
|
// See UNTAGGED_NATIVE_DART_SLOTS_LIST for the format.
|
|
#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
|
|
#define AOT_ONLY_UNTAGGED_NATIVE_DART_SLOTS_LIST(V) \
|
|
V(Closure, UntaggedClosure, entry_point, false, FINAL)
|
|
#else
|
|
#define AOT_ONLY_UNTAGGED_NATIVE_DART_SLOTS_LIST(V)
|
|
#endif
|
|
|
|
// List of slots that correspond to fields of native Dart objects containing
|
|
// untagged addresses in the following format:
|
|
//
|
|
// V(class_name, underlying_type, field_name, gc_may_move, FINAL|VAR)
|
|
//
|
|
// - class_name and field_name specify the name of the host class and the name
|
|
// of the field respectively;
|
|
// - underlying_type: the Raw class which holds the field;
|
|
// - gc_may_move: whether the untagged address contained in this field is a
|
|
// pointer to memory that may be moved by the GC, which means a value loaded
|
|
// from this field is invalidated by any instruction that can cause GC;
|
|
// - the last component specifies whether field behaves like a final field
|
|
// (i.e. initialized once at construction time and does not change after
|
|
// that) or like a non-final field.
|
|
//
|
|
// Note: As the underlying field is untagged, these slots cannot be nullable.
|
|
//
|
|
// Note: All slots for fields that contain untagged addresses are given
|
|
// the kUntagged representation.
|
|
#define UNTAGGED_NATIVE_DART_SLOTS_LIST(V) \
|
|
AOT_ONLY_UNTAGGED_NATIVE_DART_SLOTS_LIST(V) \
|
|
V(Function, UntaggedFunction, entry_point, false, FINAL) \
|
|
V(FinalizerBase, UntaggedFinalizerBase, isolate, false, VAR) \
|
|
V(PointerBase, UntaggedPointerBase, data, true, VAR)
|
|
|
|
// List of slots that correspond to fields of non-Dart objects containing
|
|
// tagged addresses of Dart objects in the following format:
|
|
//
|
|
// V(class_name, _, field_name, exact_type, FINAL|VAR)
|
|
//
|
|
// - class_name and field_name specify the name of the host class and the name
|
|
// of the field respectively;
|
|
// - exact_type specifies exact type of the field (any load from this field
|
|
// would only yield instances of this type);
|
|
// - the last component specifies whether field behaves like a final field
|
|
// (i.e. initialized once at construction time and does not change after
|
|
// that) or like a non-final field.
|
|
//
|
|
// Note: Currently LoadFieldInstr::IsImmutableLengthLoad() assumes that no
|
|
// slots of non-Dart values represent length loads.
|
|
#define NULLABLE_TAGGED_NATIVE_NONDART_SLOTS_LIST(V) \
|
|
V(Isolate, _, finalizers, GrowableObjectArray, VAR) \
|
|
V(LocalHandle, _, ptr, Dynamic, VAR) \
|
|
V(ObjectStore, _, record_field_names, Array, VAR) \
|
|
V(PersistentHandle, _, ptr, Dynamic, VAR)
|
|
|
|
// List of slots that correspond to fields of non-Dart objects containing
|
|
// unboxed values in the following format:
|
|
//
|
|
// V(class_name, _, field_name, representation, FINAL|VAR)
|
|
//
|
|
// - class_name and field_name specify the name of the host class and the name
|
|
// of the field respectively;
|
|
// - representation specifies the representation of the bits stored within
|
|
// the unboxed field (minus the kUnboxed prefix);
|
|
// - the last component specifies whether field behaves like a final field
|
|
// (i.e. initialized once at construction time and does not change after
|
|
// that) or like a non-final field.
|
|
//
|
|
// Note: As the underlying field is unboxed, these slots cannot be nullable.
|
|
//
|
|
// Note: Currently LoadFieldInstr::IsImmutableLengthLoad() assumes that no
|
|
// slots of non-Dart values represent length loads.
|
|
#define UNBOXED_NATIVE_NONDART_SLOTS_LIST(V) \
|
|
V(StreamInfo, _, enabled, IntPtr, VAR)
|
|
|
|
// List of slots that correspond to fields of non-Dart objects containing
|
|
// untagged addresses in the following format:
|
|
//
|
|
// V(class_name, _, field_name, gc_may_move, FINAL|VAR)
|
|
//
|
|
// - class_name and field_name specify the name of the host class and the name
|
|
// of the field respectively;
|
|
// - gc_may_move: whether the untagged address contained in this field is a
|
|
// pointer to memory that may be moved by the GC, which means a value loaded
|
|
// from this field is invalidated by any instruction that can cause GC;
|
|
// - the last component specifies whether field behaves like a final field
|
|
// (i.e. initialized once at construction time and does not change after
|
|
// that) or like a non-final field.
|
|
//
|
|
// Note: As the underlying field is untagged, these slots cannot be nullable.
|
|
//
|
|
// Note: All slots for fields that contain untagged addresses are given
|
|
// the kUntagged representation.
|
|
//
|
|
// Note: while Thread::isolate_ and IsolateGroup::object_store_ aren't const
|
|
// fields, they should never change during a given execution of the code
|
|
// generated for a function and the compiler only does intra-procedural
|
|
// load optimizations.
|
|
#define UNTAGGED_NATIVE_NONDART_SLOTS_LIST(V) \
|
|
V(IsolateGroup, _, object_store, false, FINAL) \
|
|
V(Thread, _, api_top_scope, false, VAR) \
|
|
V(Thread, _, isolate, false, FINAL) \
|
|
V(Thread, _, isolate_group, false, FINAL) \
|
|
V(Thread, _, service_extension_stream, false, FINAL)
|
|
|
|
// No untagged slot on a non-Dart object should contain a GC-movable address.
|
|
// The gc_may_move field is only there so that any code that operates on
|
|
// UNTAGGED_NATIVE_SLOTS_LIST can use that field as desired.
|
|
#define CHECK_NATIVE_NONDART_SLOT(__, ___, ____, gc_may_move, _____) \
|
|
static_assert(!gc_may_move);
|
|
UNTAGGED_NATIVE_NONDART_SLOTS_LIST(CHECK_NATIVE_NONDART_SLOT)
|
|
#undef CHECK_NATIVE_NONDART_SLOT
|
|
|
|
// For uses that need any native slot that contain an unboxed integer. Such uses
|
|
// can only use the following arguments for each entry:
|
|
// V(class_name, _, field_name, rep, FINAL|VAR)
|
|
#define UNBOXED_NATIVE_SLOTS_LIST(V) \
|
|
UNBOXED_NATIVE_DART_SLOTS_LIST(V) \
|
|
UNBOXED_NATIVE_NONDART_SLOTS_LIST(V)
|
|
|
|
// For uses that need any native slot that contain an untagged address. Such
|
|
// uses can only use the following arguments for each entry:
|
|
// V(class_name, _, field_name, gc_may_move, FINAL|VAR)
|
|
#define UNTAGGED_NATIVE_SLOTS_LIST(V) \
|
|
UNTAGGED_NATIVE_DART_SLOTS_LIST(V) \
|
|
UNTAGGED_NATIVE_NONDART_SLOTS_LIST(V)
|
|
|
|
// For uses that need any native slot that does not contain a Dart object. Such
|
|
// uses can only use the following arguments for each entry:
|
|
// V(class_name, _, field_name, _, FINAL|VAR)
|
|
#define NOT_TAGGED_NATIVE_SLOTS_LIST(V) \
|
|
UNBOXED_NATIVE_SLOTS_LIST(V) \
|
|
UNTAGGED_NATIVE_SLOTS_LIST(V)
|
|
|
|
// For uses that need any native slot that is guaranteed to contain a tagged
|
|
// integer. Such uses can only use the following arguments for each entry:
|
|
// V(class_name, _, field_name, exact_type, FINAL|VAR)
|
|
#define TAGGED_INT_NATIVE_SLOTS_LIST(V) \
|
|
NONNULLABLE_INT_TAGGED_NATIVE_DART_SLOTS_LIST(V)
|
|
|
|
// For uses that need any native slot that contains a tagged object which is not
|
|
// guaranteed to be a integer. This includes nullable integer slots, since
|
|
// those slots may return a non-integer value (null). Such uses can
|
|
// only use the following arguments for each entry:
|
|
// V(class_name, _, field_name, exact_type, FINAL|VAR)
|
|
#define TAGGED_NONINT_NATIVE_SLOTS_LIST(V) \
|
|
NULLABLE_TAGGED_NATIVE_DART_SLOTS_LIST(V) \
|
|
NONNULLABLE_NONINT_TAGGED_NATIVE_DART_SLOTS_LIST(V) \
|
|
NULLABLE_TAGGED_NATIVE_NONDART_SLOTS_LIST(V)
|
|
|
|
// For uses that need any native slot that is not guaranteed to contain an
|
|
// integer, whether a Dart object or unboxed. Such uses can only use the
|
|
// following arguments for each entry:
|
|
// V(class_name, _, field_name, _, FINAL|VAR)
|
|
#define NOT_INT_NATIVE_SLOTS_LIST(V) \
|
|
TAGGED_NONINT_NATIVE_SLOTS_LIST(V) \
|
|
UNTAGGED_NATIVE_SLOTS_LIST(V)
|
|
|
|
// For uses that need any native slot on Dart objects that contains a Dart
|
|
// object (e.g., for write barrier purposes). Such uses can use the following
|
|
// arguments for each entry:
|
|
// V(class_name, underlying_class, field_name, exact_type, FINAL|VAR)
|
|
#define TAGGED_NATIVE_DART_SLOTS_LIST(V) \
|
|
NULLABLE_TAGGED_NATIVE_DART_SLOTS_LIST(V) \
|
|
NONNULLABLE_INT_TAGGED_NATIVE_DART_SLOTS_LIST(V) \
|
|
NONNULLABLE_NONINT_TAGGED_NATIVE_DART_SLOTS_LIST(V)
|
|
|
|
// For uses that need any native slot that is not on a Dart object or does
|
|
// not contain a Dart object (e.g., for write barrier purposes). Such uses
|
|
// can only use the following arguments for each entry:
|
|
// V(class_name, _, field_name, _, FINAL|VAR)
|
|
#define NOT_TAGGED_NATIVE_DART_SLOTS_LIST(V) \
|
|
NULLABLE_TAGGED_NATIVE_NONDART_SLOTS_LIST(V) \
|
|
NOT_TAGGED_NATIVE_SLOTS_LIST(V)
|
|
|
|
// For uses that need any native slot that contains a Dart object. Such uses can
|
|
// only use the following arguments for each entry:
|
|
// V(class_name, _, field_name, exact_type, FINAL|VAR)
|
|
#define TAGGED_NATIVE_SLOTS_LIST(V) \
|
|
TAGGED_INT_NATIVE_SLOTS_LIST(V) \
|
|
TAGGED_NONINT_NATIVE_SLOTS_LIST(V)
|
|
|
|
// For uses that need all native slots. Such uses can only use the following
|
|
// arguments for each entry:
|
|
// V(class_name, _, field_name, _, FINAL|VAR)
|
|
#define NATIVE_SLOTS_LIST(V) \
|
|
TAGGED_NATIVE_SLOTS_LIST(V) \
|
|
NOT_TAGGED_NATIVE_SLOTS_LIST(V)
|
|
|
|
// For tagged slots, the cid should either be Dynamic or the precise cid
|
|
// of the values stored in the corresponding field. That means the cid should
|
|
// not be the cid of an abstract superclass, because then the code will assume
|
|
// the cid of retrieved values is always the given cid.
|
|
//
|
|
// Note: If we ever need native slots with CompileTypes created from an
|
|
// AbstractType instead, then a new base category should be created for those,
|
|
// possibly replacing the cid field with the name of the abstract type.
|
|
#define CHECK_TAGGED_NATIVE_SLOT(__, ___, ____, field_type, _____) \
|
|
static_assert(k##field_type##Cid != kObjectCid); \
|
|
static_assert(k##field_type##Cid != kInstanceCid); \
|
|
static_assert(k##field_type##Cid != kIntegerCid); \
|
|
static_assert(k##field_type##Cid != kStringCid); \
|
|
static_assert(k##field_type##Cid != kAbstractTypeCid);
|
|
TAGGED_NATIVE_SLOTS_LIST(CHECK_TAGGED_NATIVE_SLOT)
|
|
#undef CHECK_NULLABLE_TAGGED_NATIVE_SLOT
|
|
|
|
// Currently we only create slots with CompileTypes created from a precise cid,
|
|
// so integer slots listed here must only contain Smis (or Mints, but no slot
|
|
// currently does has only Mints, adjust this check if one is added).
|
|
//
|
|
// Note: If we ever add a category of native slots with AbstractType-based
|
|
// CompileTypes that always contain integers, then add additional checks that
|
|
// the AbstractTypes of those slots are subtypes of Integer.
|
|
#define CHECK_INT_NATIVE_SLOT(__, ___, ____, field_type, _____) \
|
|
static_assert(k##field_type##Cid == kSmiCid);
|
|
TAGGED_INT_NATIVE_SLOTS_LIST(CHECK_INT_NATIVE_SLOT)
|
|
#undef CHECK_INT_NATIVE_SLOT
|
|
|
|
// Any slot with an integer type should go into the correct category.
|
|
//
|
|
// Note: If we ever add native slots with AbstractType-based CompileTypes, then
|
|
// add appropriate checks that the AbstractType is not a subtype of Integer.
|
|
#define CHECK_NONINT_NATIVE_SLOT(__, ___, ____, field_type, _____) \
|
|
static_assert(k##field_type##Cid != kSmiCid); \
|
|
static_assert(k##field_type##Cid != kMintCid);
|
|
TAGGED_NONINT_NATIVE_SLOTS_LIST(CHECK_NONINT_NATIVE_SLOT)
|
|
#undef CHECK_NONINT_NATIVE_SLOT
|
|
|
|
class FieldGuardState {
|
|
public:
|
|
FieldGuardState() : state_(0) {}
|
|
explicit FieldGuardState(const Field& field);
|
|
|
|
intptr_t guarded_cid() const { return GuardedCidBits::decode(state_); }
|
|
bool is_nullable() const { return IsNullableBit::decode(state_); }
|
|
|
|
private:
|
|
using GuardedCidBits = BitField<int32_t, ClassIdTagType, 0, 20>;
|
|
using IsNullableBit = BitField<int32_t, bool, GuardedCidBits::kNextBit, 1>;
|
|
|
|
const int32_t state_;
|
|
};
|
|
|
|
// Slot is an abstraction that describes an readable (and possibly writeable)
|
|
// location within an object.
|
|
//
|
|
// Slot objects returned by Slot::Get* methods have identity and can be
|
|
// compared by pointer. If two slots are different they must not alias.
|
|
// If two slots can alias - they must be represented by identical
|
|
// slot object.
|
|
class Slot : public ZoneAllocated {
|
|
public:
|
|
// clang-format off
|
|
enum class Kind : uint8_t {
|
|
// Native slots are identified by their kind - each native slot has its own.
|
|
#define DECLARE_KIND(ClassName, __, FieldName, ___, ____) \
|
|
k##ClassName##_##FieldName,
|
|
NATIVE_SLOTS_LIST(DECLARE_KIND)
|
|
#undef DECLARE_KIND
|
|
|
|
// A slot used to store type arguments.
|
|
kTypeArguments,
|
|
|
|
// A slot at a specific [index] in a [UntaggedTypeArgument] vector.
|
|
kTypeArgumentsIndex,
|
|
|
|
// A slot corresponding to an array element at given offset.
|
|
// Only used during allocation sinking and in MaterializeObjectInstr.
|
|
kArrayElement,
|
|
|
|
// A slot corresponding to a record field at the given offset.
|
|
kRecordField,
|
|
|
|
// A slot within a Context object that contains a value of a captured
|
|
// local variable.
|
|
kCapturedVariable,
|
|
|
|
// A slot that corresponds to a Dart field (has corresponding Field object).
|
|
kDartField,
|
|
};
|
|
// clang-format on
|
|
|
|
// Returns a slot that represents length field for the given [array_cid].
|
|
static const Slot& GetLengthFieldForArrayCid(intptr_t array_cid);
|
|
|
|
// Return a slot that represents type arguments field for the given class.
|
|
//
|
|
// We do not distinguish type argument fields within disjoint
|
|
// class hierarchies: type argument fields at the same offset would be
|
|
// represented by the same Slot object. Type argument slots are final
|
|
// so disambiguating type arguments fields does not improve alias analysis.
|
|
static const Slot& GetTypeArgumentsSlotFor(Thread* thread, const Class& cls);
|
|
|
|
// Returns a slot at a specific [index] in a [UntaggedTypeArgument] vector.
|
|
static const Slot& GetTypeArgumentsIndexSlot(Thread* thread, intptr_t index);
|
|
|
|
// Returns a slot corresponding to an array element at [offset_in_bytes].
|
|
static const Slot& GetArrayElementSlot(Thread* thread,
|
|
intptr_t offset_in_bytes);
|
|
|
|
// Returns a slot corresponding to a record field at [offset_in_bytes].
|
|
static const Slot& GetRecordFieldSlot(Thread* thread,
|
|
intptr_t offset_in_bytes);
|
|
|
|
// Returns a slot that represents the given captured local variable.
|
|
static const Slot& GetContextVariableSlotFor(Thread* thread,
|
|
const LocalVariable& var);
|
|
|
|
// Returns a slot that represents the given Dart field.
|
|
static const Slot& Get(const Field& field,
|
|
const ParsedFunction* parsed_function);
|
|
|
|
// Convenience getters for native slots.
|
|
#define DEFINE_GETTER(ClassName, __, FieldName, ___, ____) \
|
|
static const Slot& ClassName##_##FieldName() { \
|
|
return GetNativeSlot(Kind::k##ClassName##_##FieldName); \
|
|
}
|
|
|
|
NATIVE_SLOTS_LIST(DEFINE_GETTER)
|
|
#undef DEFINE_GETTER
|
|
|
|
Kind kind() const { return kind_; }
|
|
bool IsDartField() const { return kind() == Kind::kDartField; }
|
|
bool IsLocalVariable() const { return kind() == Kind::kCapturedVariable; }
|
|
bool IsTypeArguments() const { return kind() == Kind::kTypeArguments; }
|
|
bool IsArgumentOfType() const { return kind() == Kind::kTypeArgumentsIndex; }
|
|
bool IsArrayElement() const { return kind() == Kind::kArrayElement; }
|
|
bool IsRecordField() const { return kind() == Kind::kRecordField; }
|
|
bool IsImmutableLengthSlot() const;
|
|
|
|
const char* Name() const;
|
|
|
|
intptr_t offset_in_bytes() const { return offset_in_bytes_; }
|
|
|
|
// Currently returns the representation of unboxed native fields and kTagged
|
|
// for most other types of fields. One special case: fields marked as
|
|
// containing non-nullable ints in AOT kernel, which have the kUnboxedInt64
|
|
// representation.
|
|
Representation representation() const { return representation_; }
|
|
|
|
bool is_immutable() const { return IsImmutableBit::decode(flags_); }
|
|
|
|
// Returns true if properties of this slot were based on the guarded state
|
|
// of the corresponding Dart field.
|
|
bool is_guarded_field() const { return IsGuardedBit::decode(flags_); }
|
|
|
|
bool is_compressed() const { return IsCompressedBit::decode(flags_); }
|
|
|
|
// Returns true if the field is an unboxed native field that may contain an
|
|
// inner pointer to a GC-movable object.
|
|
bool may_contain_inner_pointer() const {
|
|
return MayContainInnerPointerBit::decode(flags_);
|
|
}
|
|
|
|
// Type information about values that can be read from this slot.
|
|
CompileType type() const { return type_; }
|
|
|
|
const Field& field() const {
|
|
ASSERT(IsDartField());
|
|
ASSERT(data_ != nullptr);
|
|
return *DataAs<const Field>();
|
|
}
|
|
|
|
bool Equals(const Slot& other) const;
|
|
uword Hash() const;
|
|
|
|
bool IsIdentical(const Slot& other) const { return this == &other; }
|
|
|
|
bool IsContextSlot() const {
|
|
return kind() == Kind::kCapturedVariable || kind() == Kind::kContext_parent;
|
|
}
|
|
|
|
bool is_tagged() const { return !IsNonTaggedBit::decode(flags_); }
|
|
bool has_untagged_instance() const {
|
|
return HasUntaggedInstanceBit::decode(flags_);
|
|
}
|
|
|
|
void Write(FlowGraphSerializer* s) const;
|
|
static const Slot& Read(FlowGraphDeserializer* d);
|
|
|
|
private:
|
|
Slot(Kind kind,
|
|
int8_t flags,
|
|
intptr_t offset_in_bytes,
|
|
const void* data,
|
|
CompileType type,
|
|
Representation representation,
|
|
const FieldGuardState& field_guard_state = FieldGuardState())
|
|
: kind_(kind),
|
|
flags_(flags),
|
|
offset_in_bytes_(offset_in_bytes),
|
|
representation_(representation),
|
|
field_guard_state_(field_guard_state),
|
|
data_(data),
|
|
type_(type) {}
|
|
|
|
Slot(const Slot& other)
|
|
: Slot(other.kind_,
|
|
other.flags_,
|
|
other.offset_in_bytes_,
|
|
other.data_,
|
|
other.type_,
|
|
other.representation_,
|
|
other.field_guard_state_) {}
|
|
|
|
template <typename T>
|
|
const T* DataAs() const {
|
|
return static_cast<const T*>(data_);
|
|
}
|
|
|
|
static const Slot& GetCanonicalSlot(
|
|
Thread* thread,
|
|
Kind kind,
|
|
int8_t flags,
|
|
intptr_t offset_in_bytes,
|
|
const void* data,
|
|
CompileType type,
|
|
Representation representation,
|
|
const FieldGuardState& field_guard_state = FieldGuardState());
|
|
|
|
static const Slot& GetNativeSlot(Kind kind);
|
|
|
|
const FieldGuardState& field_guard_state() const {
|
|
return field_guard_state_;
|
|
}
|
|
|
|
const Kind kind_;
|
|
const int8_t flags_;
|
|
const intptr_t offset_in_bytes_;
|
|
const Representation representation_;
|
|
|
|
const FieldGuardState field_guard_state_;
|
|
|
|
// Kind dependent data:
|
|
// - name as a Dart String object for local variables;
|
|
// - name as a C string for native slots;
|
|
// - Field object for Dart fields;
|
|
const void* data_;
|
|
|
|
CompileType type_;
|
|
|
|
using IsImmutableBit = BitField<decltype(flags_), bool, 0, 1>;
|
|
using IsGuardedBit =
|
|
BitField<decltype(flags_), bool, IsImmutableBit::kNextBit, 1>;
|
|
using IsCompressedBit =
|
|
BitField<decltype(flags_), bool, IsGuardedBit::kNextBit, 1>;
|
|
// Stores whether a field isn't tagged so that tagged is the default value
|
|
using IsNonTaggedBit =
|
|
BitField<decltype(flags_), bool, IsCompressedBit::kNextBit, 1>;
|
|
using MayContainInnerPointerBit =
|
|
BitField<decltype(flags_), bool, IsNonTaggedBit::kNextBit, 1>;
|
|
using HasUntaggedInstanceBit =
|
|
BitField<decltype(flags_), bool, MayContainInnerPointerBit::kNextBit, 1>;
|
|
|
|
friend class SlotCache;
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_COMPILER_BACKEND_SLOT_H_
|