一,ContextScope
1,ContextScope类可以延迟本地函数的编译,直到调用它。ContextScope实例收集要编译的局部函数引用的局部变量,这些变量属于外部作用域,也就是说,属于包围局部函数的(可能是嵌套的)函数的局部作用域。每个捕获的变量由其在源中的标记位置、名称、类型、上下文中的分配索引及其上下文级别表示。函数嵌套级别和循环嵌套级别不被保留,因为它们仅在分配上下文级别之前使用。此外,ContextScope有一个字段“is_implicit”,如果ContextScop是为隐式闭包创建的,则该字段为true。
参考博客:https://www.cnblogs.com/sxhlf/p/6727486.html
2,struct VariableDesc {
RawSmi* declaration_token_pos;
RawSmi* token_pos;
RawString* name;
RawSmi* flags;
static constexpr intptr_t kIsFinal = 0x1;
static constexpr intptr_t kIsConst = 0x2;
static constexpr intptr_t kIsLate = 0x4;//延迟
RawSmi* late_init_offset;
union {
RawAbstractType* type;
RawInstance* value; // iff is_const is true
};
RawSmi* context_index;
RawSmi* context_level;//参考NumCapturedVariables
};
3,VariableDesc地址空间分配
可变长度数据如下
#define OPEN_ARRAY_START(type, align) \
do { \
const uword result = reinterpret_cast<uword>(this) + sizeof(*this); \
ASSERT(Utils::IsAligned(result, sizeof(align))); \
return reinterpret_cast<type*>(result); \
} while (0)
RawObject* const* data() const { OPEN_ARRAY_START(RawObject*, RawObject*);
const VariableDesc* VariableDescAddr(intptr_t index) const {
ASSERT((index >= 0) && (index < num_variables_ + 1));
// data() )指向第一个描述符的第一个组件
return &(reinterpret_cast<const VariableDesc*>(data())[index]);
}
4,创建一个ContextScope
RawContextScope* ContextScope::New(intptr_t num_variables, bool is_implicit) {
intptr_t size = ContextScope::InstanceSize(num_variables);
ContextScope& result = ContextScope::Handle();
{
RawObject* raw = Object::Allocate(ContextScope::kClassId, size, Heap::kOld);
NoSafepointScope no_safepoint;
result ^= raw;
result.set_num_variables(num_variables);
result.set_is_implicit(is_implicit);
}
return result.raw();
}
5,调用实例:
int LocalScope::NumCapturedVariables() const {
不必遍历父范围,因为我们只对该范围中引用的捕获变量感兴趣。如果此作用域是函数级别1的顶级作用域,并且它(或其子作用域)引用了在函数级别0的父作用域中声明的捕获变量,则它将包含该变量的别名。
因为嵌套函数的代码生成被推迟到第一次调用时,闭包作用域的函数级别只能为1
ASSERT(function_level() == 1);
int num_captured = 0;
for (int i = 0; i < num_variables(); i++) {
LocalVariable* variable = VariableAt(i);
// 统计属于外部范围的捕获变量的别名.
if (variable->owner()->function_level() != 1) {
ASSERT(variable->is_captured());
ASSERT(variable->owner()->function_level() == 0);
num_captured++;
}
}
return num_captured;
}
// 计引用的捕获变量的数量
intptr_t num_captured_vars = NumCapturedVariables();
// 为num_captured_vars描述符创建一个带有空格的ContextScope
const ContextScope& context_scope =
ContextScope::Handle(ContextScope::New(num_captured_vars, false));
6,局部变量LocalVarDescriptors
struct VarInfo {
int32_t index_kind; // 堆栈或上下文中时隙索引的位字段
// /以及VarInfoKind类型的Entry类型
TokenPosition declaration_pos; // T声明的标记位置
TokenPosition begin_pos; // 作用域开始的标记位置
TokenPosition end_pos; // 作用域结束的标记位置.
int16_t scope_id; // 变量所属的范围
VarInfoKind kind() const {
return static_cast<VarInfoKind>(KindBits::decode(index_kind));
}
void set_kind(VarInfoKind kind) {
index_kind = KindBits::update(kind, index_kind);
}
int32_t index() const { return IndexBits::decode(index_kind) - kIndexBias; }
void set_index(int32_t index) {
index_kind = IndexBits::update(index + kIndexBias, index_kind);
}
};
二,CallSiteData//函数调用入口
1,target_name_
2,args_descriptor_
三,class MegamorphicCache : public CallSiteData
1,mask_ 表中的类ID是smi标记的,因此我们使用smi标记掩码和目标类ID来避免在生成的代码中取消标记(在测试循环的每次迭代中)
2,buckets()通过RawObject** slot = &Array::DataOf(buckets())[target_index];可以看出存储多个slot
3,插入
void MegamorphicCache::InsertLocked(const Smi& class_id,
const Object& target) const {
…
const Array& backing_array = Array::Handle(buckets());
intptr_t id_mask = mask();
intptr_t index = (class_id.Value() * kSpreadFactor) & id_mask;
intptr_t i = index;
do {
if (Smi::Value(Smi::RawCast(GetClassId(backing_array, i))) == kIllegalCid) {//
SetEntry(backing_array, i, class_id, target);
set_filled_entry_count(filled_entry_count() + 1);
return;
}
i = (i + 1) & id_mask;
} while (i != index);
}
五,TypeArguments
1,A TypeArguments 是一个 AbstractType数组
1,Number of fields in the raw object is 4:
包括这四位 instantiations_, length_, hash_ and nullability_.
static const int kNumFields = 4;
3,类型参数向量的可为nullability表示其类型元素的可为nullability(最多为最大数量,即kNullabilityMaxTypes)
在某些情况下(由编译器预先确定),它在运行时用于决定是否可以共享实例化器类型参数(instantiator type arguments ITA),而不是执行成本更高的非实例化类型参数(uninstantiated type arguments UTA)实例化
向量可空性存储为位向量(在Smi字段中),每种类型使用2位:
-如果类型为空或legacy(复数*=),则设置高位。
-如果类型为空,则设置低位。
如果向量大于kNullabilityMaxTypes,则Nullability为0。
在运行时评估的决定UTA是否可以共享ITA的条件是
(UTA.nullability&ITA.nullaability)==UTA.nullability
请注意,这允许ITA比UTA更长。
bool TypeArguments::IsDynamicTypes(bool raw_instantiated,
intptr_t from_index,
intptr_t len) const {
AbstractType& type = AbstractType::Handle();
Class& type_class = Class::Handle();
for (intptr_t i = 0; i < len; i++) {
type = TypeAt(from_index + i);
if (type.IsNull()) {
return false;
}
if (!type.HasTypeClass()) {
if (raw_instantiated && type.IsTypeParameter()) {
// /非实例化类型参数等效于动态参数
continue;
}
return false;
}
type_class = type.type_class();
if (!type_class.IsDynamicClass()) {
return false;
}
}
return true;
}
bool TypeArguments::IsSubtypeOf(const TypeArguments& other,
intptr_t from_index,
intptr_t len,
Heap::Space space) const {
AbstractType& type = AbstractType::Handle();
AbstractType& other_type = AbstractType::Handle();
for (intptr_t i = 0; i < len; i++) {
type = TypeAt(from_index + i);
other_type = other.TypeAt(from_index + i);
if (type.IsNull() || other_type.IsNull() ||
!type.IsSubtypeOf(other_type, space)) {
return false;
}
}
return true;
}
六,class AbstractType : public Instance
//AbstractType是一个抽象超类,AbstractType的子类是Type和TypeParameter。
bool IsDynamicType() const { return type_class_id() == kDynamicCid; }
bool IsVoidType() const { return type_class_id() == kVoidCid; }
bool IsNullType() const;
bool IsNeverType() const;
bool IsObjectType() const { return type_class_id() == kInstanceCid; }
bool IsTopType() const;//可以参考FutureOr
//返回此(可能是嵌套的)“FutureOr”类型的类型参数。
//如果此类型不是“FutureOr”类型,则返回未修改的类型。
//多个RawAbstractType,可指定返回一个
RawAbstractType* AbstractType::UnwrapFutureOr() const {
if (!IsFutureOrType()) {
return raw();
}
if (arguments() == TypeArguments::null()) {
return Type::dynamic_type().raw();
}
TypeArguments& type_args = thread->TypeArgumentsHandle();
type_args = arguments();
/*
virtual RawTypeArguments* arguments() const { return raw_ptr()->arguments_; }
virtual void set_arguments(const TypeArguments& value) const;
*/
AbstractType& type_arg = thread->AbstractTypeHandle();
type_arg = type_args.TypeAt(0);
while (type_arg.IsFutureOrType()) {
if (type_arg.arguments() == TypeArguments::null()) {
return Type::dynamic_type().raw();
}
type_args = type_arg.arguments();
type_arg = type_args.TypeAt(0);
}
return type_arg.raw();
}
七,class Type : public AbstractType
Type由一个类组成,可能用类型参数参数化。例如:C<T1,T2>。
警告:“RawType*”表示指向类Type的VM对象的“raw”指针,而“Type”表示指向同一对象的“句柄”RawType”与“raw type”无关,而与“cooked type型”或“rare type”相反
八,class TypeRef : public AbstractType
TypeRef用于中断递归类型表示中的循环。
它唯一的字段是它所引用的递归AbstractType,在完成过程中它可以/暂时为空。请注意,循环始终包含类型参数
九,TypeParameter
表示参数化类的类型参数。它指定其索引(以及用于调试的名称)及其bound。例如,类型参数“V”在类HashMap<K,V>的上下文中指定为索引1。编译时,TypeParameter尚未实例化,即它只是一个占位符。完成后,TypeParameter索引将更改,以反映其作为参数化类的类型参数(而不是类型参数)的位置。如果类型参数声明时没有扩展子句,则其绑定设置为ObjectType
bool IsClassTypeParameter() const {
return parameterized_class_id() != kFunctionCid;
}
bool IsFunctionTypeParameter() const {
return parameterized_function() != Function::null();
}
//为泛型的上界
RawAbstractType* bound() const { return raw_ptr()->bound_; }
void set_bound(const AbstractType& value) const;
某个类型是 A 类型的子类型,也称上界或上限,使用 <: 关键字,语法如下:
[T <: A]或用通配符:[_ <: A]
//例子:判断T0/FutureOr<S0> 是 T1/FutureOr<S1>的子类
// if T1 is FutureOr<S1> then:
// T0 <: T1 iff any of the following hold:
// either T0 <: Future<S1>
// or T0 <: S1
// or T0 is X0 and X0 has bound S0 and S0 <: T1 (checked elsewhere)
if (other_cid == kFutureOrCid) {
const AbstractType& other_type_arg =
AbstractType::Handle(zone, other_type_arguments.TypeAtNullSafe(0));
// Check if S1 is a top type.
if (other_type_arg.IsTopType()) {
return true;
}
// Check T0 <: Future<S1> when T0 is Future<S0>.
if (this_class.IsFutureClass()) {
const AbstractType& type_arg =
AbstractType::Handle(zone, type_arguments.TypeAtNullSafe(0));
// If T0 is Future<S0>, then T0 <: Future<S1>, iff S0 <: S1.
if (type_arg.IsSubtypeOf(other_type_arg, space)) {
if (verified_nullability) {
return true;
}
}
}
// Check T0 <: Future<S1> when T0 is FutureOr<S0> is already done.
// Check T0 <: S1.
if (other_type_arg.HasTypeClass() &&
Class::IsSubtypeOf(this_class, type_arguments, nullability,
other_type_arg, space)) {
return true;
}
}
十,闭包
class Closure : public Instance
RawTypeArguments* function_type_arguments() const {
return raw_ptr()->function_type_arguments_;
}
static intptr_t function_type_arguments_offset() {
return OFFSET_OF(RawClosure, function_type_arguments_);
}
RawTypeArguments* delayed_type_arguments() const {
return raw_ptr()->delayed_type_arguments_;
}
static intptr_t delayed_type_arguments_offset() {
return OFFSET_OF(RawClosure, delayed_type_arguments_);
}
RawFunction* function() const { return raw_ptr()->function_; }
static intptr_t function_offset() { return OFFSET_OF(RawClosure, function_); }
RawContext* context() const { return raw_ptr()->context_; }
static intptr_t context_offset() { return OFFSET_OF(RawClosure, context_); }
十一,栈追踪class StackTrace : public Instance
static const int kPreallocatedStackdepth = 90;
void set_expand_inlined(bool value) const;
RawObject* CodeAtFrame(intptr_t frame_index) const;
RawSmi* PcOffsetAtFrame(intptr_t frame_index) const;
//堆栈和async-link之间的链接是否表示异步函数的同步启动。在这种情况下,我们在连接堆栈时省略了<异步暂停>标 记
RawStackTrace* async_link() const { return raw_ptr()->async_link_; }
void set_async_link(const StackTrace& async_link) const;
//如果异步堆栈跟踪随同步异步调用附加到同步堆栈跟踪,则应从异步堆栈跟踪顶部截断的帧数
//如果不裁剪,边框看起来像:
// <async function>
// ---------------------------
// <asynchronous gap marker>
// <async function>
//因为它实际上不是一个异步调用,所以在连接同步和异步堆栈跟踪时,我们会裁剪最后两个帧。
static constexpr intptr_t kSyncAsyncCroppedFrames=2;//不是特别明白
十二,WeakProperty
RawObject* key_;
RawObject* value_;
//链接列表正在链接所有挂起的弱属性。
//未键入以明确GC不会访问它
uword next_;
static void Clear(RawWeakProperty* raw_weak) {
ASSERT(raw_weak->ptr()->next_ == 0);
// This action is performed by the GC. No barrier.
raw_weak->ptr()->key_ = Object::null();
raw_weak->ptr()->value_ = Object::null();
}
十三,Pointer对象
Pointer& result = Pointer::Handle(zone);
result ^= Object::Allocate(kFfiPointerCid, Pointer::InstanceSize(), space);
result.SetTypeArguments(type_args);
result.SetNativeAddress(native_address);
bool Pointer::IsPointer(const Instance& obj) {
return RawObject::IsFfiPointerClassId(obj.raw()->GetClassId());
}
bool Instance::IsPointer() const {
return Pointer::IsPointer(*this);
}
十四,CompressedStackMaps
在AOT模式下,当vm_service/profiler不存在(PRODUCT/flutter版本构建)并且使用了--dwarf-stack-traces时,几乎不需要代码对象。目前,代码对象占据了快照中对象堆大小的很大一部分,因此删除它们会减少内存使用,也会减少AOT快照大小。
为了删除大多数代码对象,我们需要:
提供另一种查找机制来访问与给定PC对应的CompressedStackMaps。
在--dwarf-stack-traces模式下,从堆栈跟踪中删除代码的使用。
删除的大多数用法ReversePc::Lookup。
十五,PcDescriptors
宏参数V传递了两个参数,即枚举值的原始名称和枚举定义中使用的初始化表达式。初始化表达式中枚举值的使用目前是硬编码的,因此第二个参数在枚举定义之外是无用的,应该由该宏的其他用户删除。
#定义FOR_EACH_RAW_PC_DESCRIPTOR(V)\
/*取消优化继续点*/
V(Deopt, 1) \kDeopt=1
/* IC call. */ \
V(IcCall, kDeopt << 1) \kIcCall=kDeopt<<1
/* 通过存根调用已知目标. */ \
V(UnoptStaticCall, kIcCall << 1) \kUnoptStaticCall=kIcCall<<1
/* Runtime call. */ \
V(RuntimeCall, kUnoptStaticCall << 1) \
/* OSR 入口点 在 unopt. code. */ \
V(OsrEntry, kRuntimeCall << 1) \
/* Call rewind target address. */ \
V(Rewind, kOsrEntry << 1) \
/* Target-word-size 重定位. */ \
V(BSSRelocation, kRewind << 1) \
V(Other, kBSSRelocation << 1) \
V(AnyKind, -1)
//描述符的数量。这只需要是一个int32_t,但我们将其设为uword,以便可变长度数据在64位平台上64位对齐
uword length_;
//可变长度数据如下。
uint8_t* data() { OPEN_ARRAY_START(uint8_t, intptr_t); }
const uint8_t* data() const { OPEN_ARRAY_START(uint8_t, intptr_t); }
//我们将在这里使用VisitPointers函数遍历pc描述符表以访问表中的对象(如果有)。
注意:永远不要返回对RawPcDescriptors::PcDescriptorRec的引用,因为对象可以移动
Iterator,MoveNext,PcOffset