[vm,aot,bytecode] Handle inferred-type metadata when generating bytecode
Change-Id: Ifadb25c782db5c95025e7275daf0676abd73cf49
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/120341
Reviewed-by: RĂ©gis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 0724be1..6b64e85 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -56,6 +56,8 @@
import '../metadata/bytecode.dart';
import '../metadata/direct_call.dart'
show DirectCallMetadata, DirectCallMetadataRepository;
+import '../metadata/inferred_type.dart'
+ show InferredType, InferredTypeMetadataRepository;
import '../metadata/procedure_attributes.dart'
show ProcedureAttributesMetadata, ProcedureAttributesMetadataRepository;
@@ -126,6 +128,8 @@
Map<TreeNode, DirectCallMetadata> directCallMetadata;
ProcedureAttributesMetadataRepository procedureAttributesMetadataRepository;
ProcedureAttributesMetadata procedureAttributesMetadata;
+ Map<TreeNode, InferredType> inferredTypeMetadata;
+ List<Constant> inferredTypesAttribute;
List<ClassDeclaration> classDeclarations;
List<FieldDeclaration> fieldDeclarations;
@@ -182,6 +186,9 @@
procedureAttributesMetadataRepository =
component.metadata[ProcedureAttributesMetadataRepository.repositoryTag];
+
+ inferredTypeMetadata = component
+ .metadata[InferredTypeMetadataRepository.repositoryTag]?.mapping;
}
@override
@@ -410,17 +417,23 @@
}
ObjectHandle getMemberAttributes(Member member) {
- if (procedureAttributesMetadata == null) {
+ if (procedureAttributesMetadata == null && inferredTypesAttribute == null) {
return null;
}
- final procedureAttributes = procedureAttributesMetadataRepository
- .getBytecodeAttribute(procedureAttributesMetadata);
// List of pairs (tag, value).
- final attrs = ListConstant(const DynamicType(), <Constant>[
- StringConstant(ProcedureAttributesMetadataRepository.repositoryTag),
- procedureAttributes,
- ]);
- return objectTable.getHandle(attrs);
+ final attrs = <Constant>[];
+ if (procedureAttributesMetadata != null) {
+ final attribute = procedureAttributesMetadataRepository
+ .getBytecodeAttribute(procedureAttributesMetadata);
+ attrs.add(
+ StringConstant(ProcedureAttributesMetadataRepository.repositoryTag));
+ attrs.add(attribute);
+ }
+ if (inferredTypesAttribute != null) {
+ attrs.add(StringConstant(InferredTypeMetadataRepository.repositoryTag));
+ attrs.add(ListConstant(const DynamicType(), inferredTypesAttribute));
+ }
+ return objectTable.getHandle(ListConstant(const DynamicType(), attrs));
}
// Insert annotations for the function and its parameters into the annotations
@@ -1180,7 +1193,7 @@
bool isSet: false,
bool isDynamicForwarder: false,
bool isUnchecked: false,
- TreeNode context}) {
+ TreeNode node}) {
assert(!isGet || !isSet);
final kind = isGet
? InvocationKind.getter
@@ -1188,7 +1201,10 @@
final cpIndex = cp.addDirectCall(kind, target, argDesc, isDynamicForwarder);
if (totalArgCount >= argumentsLimit) {
- throw new TooManyArgumentsException(context.fileOffset);
+ throw new TooManyArgumentsException(node.fileOffset);
+ }
+ if (inferredTypeMetadata != null && node != null) {
+ _appendInferredType(node, asm.offset);
}
if (isUnchecked) {
asm.emitUncheckedDirectCall(cpIndex, totalArgCount);
@@ -1201,7 +1217,7 @@
{bool hasReceiver: false,
bool isFactory: false,
bool isUnchecked: false,
- TreeNode context}) {
+ TreeNode node}) {
final argDesc = objectTable.getArgDescHandleByArguments(args,
hasReceiver: hasReceiver, isFactory: isFactory);
@@ -1216,7 +1232,7 @@
}
_genDirectCall(target, argDesc, totalArgCount,
- isUnchecked: isUnchecked, context: context);
+ isUnchecked: isUnchecked, node: node);
}
void _genTypeArguments(List<DartType> typeArgs, {Class instantiatingClass}) {
@@ -1553,6 +1569,28 @@
procedureAttributesMetadata = procedureAttributesMetadataRepository != null
? procedureAttributesMetadataRepository.mapping[node]
: null;
+
+ if (inferredTypeMetadata != null) {
+ if (node is Field) {
+ // Field type is at PC = -1.
+ _appendInferredType(node, -1);
+ } else if (enclosingFunction != null && hasCode) {
+ assert(node is Procedure || node is Constructor);
+ // Parameter types are at PC = -N,..,-1 where N - number of declared
+ // (explicit) parameters.
+ int i = -(enclosingFunction.positionalParameters.length +
+ enclosingFunction.namedParameters.length);
+ for (var v in enclosingFunction.positionalParameters) {
+ _appendInferredType(v, i);
+ ++i;
+ }
+ for (var v in enclosingFunction.namedParameters) {
+ _appendInferredType(v, i);
+ ++i;
+ }
+ }
+ }
+
if (!hasCode) {
return;
}
@@ -1596,6 +1634,32 @@
_genEqualsOperatorNullHandling(node);
}
+ void _appendInferredType(TreeNode node, int pc) {
+ final InferredType md = inferredTypeMetadata[node];
+ if (md == null) {
+ return;
+ }
+ inferredTypesAttribute ??= <Constant>[];
+ // List of triplets (PC, concreteClass, flags).
+ // Verify that PCs are monotonically increasing.
+ assert(inferredTypesAttribute.isEmpty ||
+ (inferredTypesAttribute[inferredTypesAttribute.length - 3]
+ as IntConstant)
+ .value <
+ pc);
+ inferredTypesAttribute.add(IntConstant(pc));
+ Class concreteClass = md.concreteClass;
+ // VM uses more specific function type and doesn't expect to
+ // see inferred _Closure class.
+ if (concreteClass != null && concreteClass != closureClass) {
+ inferredTypesAttribute
+ .add(TypeLiteralConstant(coreTypes.legacyRawType(concreteClass)));
+ } else {
+ inferredTypesAttribute.add(NullConstant());
+ }
+ inferredTypesAttribute.add(IntConstant(md.flags));
+ }
+
// Generate additional code for 'operator ==' to handle nulls.
void _genEqualsOperatorNullHandling(Member member) {
if (member.name.name != '==' ||
@@ -1693,6 +1757,8 @@
savedAssemblers = null;
hasErrors = false;
procedureAttributesMetadata = null;
+ inferredTypeMetadata = null;
+ inferredTypesAttribute = null;
}
SourcePositions finalizeSourcePositions() {
@@ -2767,7 +2833,7 @@
new Arguments(node.arguments.positional, named: node.arguments.named)
..parent = node;
_genArguments(null, args);
- _genDirectCallWithArgs(node.target, args, hasReceiver: true, context: node);
+ _genDirectCallWithArgs(node.target, args, hasReceiver: true, node: node);
asm.emitDrop1();
}
@@ -2777,7 +2843,7 @@
_genArguments(node.receiver, args);
final target = node.target;
if (target is Procedure && !target.isGetter && !target.isSetter) {
- _genDirectCallWithArgs(target, args, hasReceiver: true, context: node);
+ _genDirectCallWithArgs(target, args, hasReceiver: true, node: node);
} else {
throw new UnsupportedOperationError(
'Unsupported DirectMethodInvocation with target ${target.runtimeType} $target');
@@ -2789,7 +2855,8 @@
_generateNode(node.receiver);
final target = node.target;
if (target is Field || (target is Procedure && target.isGetter)) {
- _genDirectCall(target, objectTable.getArgDescHandle(1), 1, isGet: true);
+ _genDirectCall(target, objectTable.getArgDescHandle(1), 1,
+ isGet: true, node: node);
} else {
throw new UnsupportedOperationError(
'Unsupported DirectPropertyGet with ${target.runtimeType} $target');
@@ -2810,7 +2877,8 @@
final target = node.target;
assert(target is Field || (target is Procedure && target.isSetter));
- _genDirectCall(target, objectTable.getArgDescHandle(2), 2, isSet: true);
+ _genDirectCall(target, objectTable.getArgDescHandle(2), 2,
+ isSet: true, node: node);
asm.emitDrop1();
if (hasResult) {
@@ -3031,7 +3099,14 @@
asm.emitSpecializedBytecode(opcode);
}
+ bool _isUncheckedCall(
+ Node node, Member interfaceTarget, Expression receiver) =>
+ isUncheckedCall(interfaceTarget, receiver, typeEnvironment) ||
+ (inferredTypeMetadata != null &&
+ inferredTypeMetadata[node]?.skipCheck == true);
+
void _genInstanceCall(
+ Node node,
InvocationKind invocationKind,
Member interfaceTarget,
Name targetName,
@@ -3040,7 +3115,11 @@
ObjectHandle argDesc) {
final isDynamic = interfaceTarget == null;
final isUnchecked = invocationKind != InvocationKind.getter &&
- isUncheckedCall(interfaceTarget, receiver, typeEnvironment);
+ _isUncheckedCall(node, interfaceTarget, receiver);
+
+ if (inferredTypeMetadata != null) {
+ _appendInferredType(node, asm.offset);
+ }
if (invocationKind != InvocationKind.getter && !isDynamic && !isUnchecked) {
final staticReceiverType = getStaticType(receiver, typeEnvironment);
@@ -3118,11 +3197,13 @@
if (directCall != null) {
final isDynamicForwarder = (interfaceTarget == null);
final isUnchecked =
- isUncheckedCall(interfaceTarget, node.receiver, typeEnvironment);
+ _isUncheckedCall(node, interfaceTarget, node.receiver);
_genDirectCall(directCall.target, argDesc, totalArgCount,
- isDynamicForwarder: isDynamicForwarder, isUnchecked: isUnchecked);
+ isDynamicForwarder: isDynamicForwarder,
+ isUnchecked: isUnchecked,
+ node: node);
} else {
- _genInstanceCall(InvocationKind.method, interfaceTarget, node.name,
+ _genInstanceCall(node, InvocationKind.method, interfaceTarget, node.name,
node.receiver, totalArgCount, argDesc);
}
}
@@ -3142,10 +3223,10 @@
asm.emitCheckReceiverForNull(
cp.addSelectorName(node.name, InvocationKind.getter));
}
- _genDirectCall(directCall.target, argDesc, 1, isGet: true);
+ _genDirectCall(directCall.target, argDesc, 1, isGet: true, node: node);
} else {
- _genInstanceCall(InvocationKind.getter, node.interfaceTarget, node.name,
- node.receiver, 1, argDesc);
+ _genInstanceCall(node, InvocationKind.getter, node.interfaceTarget,
+ node.name, node.receiver, 1, argDesc);
}
}
@@ -3178,14 +3259,15 @@
if (directCall != null) {
final isDynamicForwarder = (node.interfaceTarget == null);
final isUnchecked =
- isUncheckedCall(node.interfaceTarget, node.receiver, typeEnvironment);
+ _isUncheckedCall(node, node.interfaceTarget, node.receiver);
_genDirectCall(directCall.target, argDesc, numArguments,
isSet: true,
isDynamicForwarder: isDynamicForwarder,
- isUnchecked: isUnchecked);
+ isUnchecked: isUnchecked,
+ node: node);
} else {
- _genInstanceCall(InvocationKind.setter, node.interfaceTarget, node.name,
- node.receiver, numArguments, argDesc);
+ _genInstanceCall(node, InvocationKind.setter, node.interfaceTarget,
+ node.name, node.receiver, numArguments, argDesc);
}
asm.emitDrop1();
@@ -3214,7 +3296,7 @@
}
_genArguments(new ThisExpression(), args);
_genDirectCallWithArgs(target, args,
- hasReceiver: true, isUnchecked: true, context: node);
+ hasReceiver: true, isUnchecked: true, node: node);
}
@override
@@ -3228,7 +3310,8 @@
return;
}
_genPushReceiver();
- _genDirectCall(target, objectTable.getArgDescHandle(1), 1, isGet: true);
+ _genDirectCall(target, objectTable.getArgDescHandle(1), 1,
+ isGet: true, node: node);
}
@override
@@ -3252,7 +3335,7 @@
assert(target is Field || (target is Procedure && target.isSetter));
_genDirectCall(target, objectTable.getArgDescHandle(2), 2,
- isSet: true, isUnchecked: true);
+ isSet: true, isUnchecked: true, node: node);
}
asm.emitDrop1();
@@ -3321,11 +3404,13 @@
} else if (_hasTrivialInitializer(target)) {
asm.emitLoadStatic(cp.addStaticField(target));
} else {
- _genDirectCall(target, objectTable.getArgDescHandle(0), 0, isGet: true);
+ _genDirectCall(target, objectTable.getArgDescHandle(0), 0,
+ isGet: true, node: node);
}
} else if (target is Procedure) {
if (target.isGetter) {
- _genDirectCall(target, objectTable.getArgDescHandle(0), 0, isGet: true);
+ _genDirectCall(target, objectTable.getArgDescHandle(0), 0,
+ isGet: true, node: node);
} else if (target.isFactory || target.isRedirectingFactoryConstructor) {
throw 'Unexpected target for StaticGet: factory $target';
} else {
@@ -3367,7 +3452,7 @@
}
_genArguments(null, args);
_genDirectCallWithArgs(target, args,
- isFactory: target.isFactory, context: node);
+ isFactory: target.isFactory, node: node);
}
@override
@@ -3389,7 +3474,8 @@
int cpIndex = cp.addStaticField(target);
asm.emitStoreStaticTOS(cpIndex);
} else {
- _genDirectCall(target, objectTable.getArgDescHandle(1), 1, isSet: true);
+ _genDirectCall(target, objectTable.getArgDescHandle(1), 1,
+ isSet: true, node: node);
asm.emitDrop1();
}
}
@@ -4242,7 +4328,7 @@
final args = node.arguments;
assert(args.types.isEmpty);
_genArguments(new ThisExpression(), args);
- _genDirectCallWithArgs(node.target, args, hasReceiver: true, context: node);
+ _genDirectCallWithArgs(node.target, args, hasReceiver: true, node: node);
asm.emitDrop1();
}
@@ -4260,7 +4346,7 @@
}
}
assert(target != null);
- _genDirectCallWithArgs(target, args, hasReceiver: true, context: node);
+ _genDirectCallWithArgs(target, args, hasReceiver: true, node: node);
asm.emitDrop1();
}
diff --git a/pkg/vm/lib/metadata/inferred_type.dart b/pkg/vm/lib/metadata/inferred_type.dart
index c22b155..432f693 100644
--- a/pkg/vm/lib/metadata/inferred_type.dart
+++ b/pkg/vm/lib/metadata/inferred_type.dart
@@ -47,6 +47,8 @@
bool get isInt => (_flags & flagInt) != 0;
bool get skipCheck => (_flags & flagSkipCheck) != 0;
+ int get flags => _flags;
+
@override
String toString() {
final base =
@@ -65,8 +67,10 @@
/// Repository for [InferredType].
class InferredTypeMetadataRepository extends MetadataRepository<InferredType> {
+ static const String repositoryTag = 'vm.inferred-type.metadata';
+
@override
- final String tag = 'vm.inferred-type.metadata';
+ String get tag => repositoryTag;
@override
final Map<TreeNode, InferredType> mapping = <TreeNode, InferredType>{};
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
index be09321..6edaba1 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
@@ -153,9 +153,6 @@
if (is_generating_interpreter()) {
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
} else {
- // TODO(alexmarkov): Make table of local variables in bytecode and
- // propagate type, name and positions.
-
ASSERT(local_vars_.is_empty());
const intptr_t num_bytecode_locals = frame_size.value();
@@ -230,8 +227,23 @@
const AbstractType& type =
AbstractType::ZoneHandle(Z, function().ParameterTypeAt(param_index));
- LocalVariable* param_var = new (Z) LocalVariable(
- TokenPosition::kNoSource, TokenPosition::kNoSource, name, type);
+ CompileType* param_type = nullptr;
+ if (!inferred_types_attribute_.IsNull()) {
+ // Parameter types are assigned to synthetic PCs = -N,..,-1
+ // where N is number of parameters.
+ const intptr_t pc = -function().NumParameters() + param_index;
+ // Search from the beginning as parameters may be declared in arbitrary
+ // order.
+ inferred_types_index_ = 0;
+ const InferredTypeMetadata inferred_type = GetInferredType(pc);
+ if (!inferred_type.IsTrivial()) {
+ param_type = new (Z) CompileType(inferred_type.ToCompileType(Z));
+ }
+ }
+
+ LocalVariable* param_var =
+ new (Z) LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
+ name, type, param_type);
param_var->set_index(var_index);
if (!function().IsNonImplicitClosureFunction() &&
@@ -448,6 +460,31 @@
return arguments;
}
+InferredTypeMetadata BytecodeFlowGraphBuilder::GetInferredType(intptr_t pc) {
+ ASSERT(!inferred_types_attribute_.IsNull());
+ intptr_t i = inferred_types_index_;
+ const intptr_t len = inferred_types_attribute_.Length();
+ for (; i < len; i += InferredTypeBytecodeAttribute::kNumElements) {
+ ASSERT(i + InferredTypeBytecodeAttribute::kNumElements <= len);
+ const intptr_t attr_pc =
+ InferredTypeBytecodeAttribute::GetPCAt(inferred_types_attribute_, i);
+ if (attr_pc == pc) {
+ const InferredTypeMetadata result =
+ InferredTypeBytecodeAttribute::GetInferredTypeAt(
+ Z, inferred_types_attribute_, i);
+ // Found. Next time, continue search at the next entry.
+ inferred_types_index_ = i + InferredTypeBytecodeAttribute::kNumElements;
+ return result;
+ }
+ if (attr_pc > pc) {
+ break;
+ }
+ }
+ // Not found. Next time, continue search at the last inspected entry.
+ inferred_types_index_ = i;
+ return InferredTypeMetadata(kDynamicCid, InferredTypeMetadata::kFlagNullable);
+}
+
void BytecodeFlowGraphBuilder::PropagateStackState(intptr_t target_pc) {
if (is_generating_interpreter() || IsStackEmpty()) {
return;
@@ -861,7 +898,14 @@
call->set_entry_kind(Code::EntryKind::kUnchecked);
}
- call->InitResultType(Z);
+ if (!call->InitResultType(Z)) {
+ if (!inferred_types_attribute_.IsNull()) {
+ const InferredTypeMetadata result_type = GetInferredType(pc_);
+ if (!result_type.IsTrivial()) {
+ call->SetResultType(Z, result_type.ToCompileType(Z));
+ }
+ }
+ }
code_ <<= call;
B->Push(call);
@@ -928,7 +972,12 @@
Array::ZoneHandle(Z, arg_desc.GetArgumentNames()), checked_argument_count,
*ic_data_array_, B->GetNextDeoptId(), interface_target);
- // TODO(alexmarkov): add type info - call->SetResultType()
+ if (!inferred_types_attribute_.IsNull()) {
+ const InferredTypeMetadata result_type = GetInferredType(pc_);
+ if (!result_type.IsTrivial()) {
+ call->SetResultType(Z, result_type.ToCompileType(Z));
+ }
+ }
if (is_unchecked_call) {
call->set_entry_kind(Code::EntryKind::kUnchecked);
@@ -991,6 +1040,14 @@
Array::ZoneHandle(Z, arg_desc.GetArgumentNames()), position_,
B->GetNextDeoptId(), Code::EntryKind::kUnchecked);
+ // TODO(alexmarkov): use inferred result type for ClosureCallInstr
+ // if (!inferred_types_attribute_.IsNull()) {
+ // const InferredTypeMetadata result_type = GetInferredType(pc_);
+ // if (!result_type.IsTrivial()) {
+ // call->SetResultType(Z, result_type.ToCompileType(Z));
+ // }
+ // }
+
code_ <<= call;
B->Push(call);
}
@@ -1025,7 +1082,12 @@
Array::ZoneHandle(Z, arg_desc.GetArgumentNames()), checked_argument_count,
*ic_data_array_, B->GetNextDeoptId(), interface_target);
- // TODO(alexmarkov): add type info - call->SetResultType()
+ if (!inferred_types_attribute_.IsNull()) {
+ const InferredTypeMetadata result_type = GetInferredType(pc_);
+ if (!result_type.IsTrivial()) {
+ call->SetResultType(Z, result_type.ToCompileType(Z));
+ }
+ }
code_ <<= call;
B->Push(call);
@@ -2171,6 +2233,9 @@
CollectControlFlow(descriptors, handlers, graph_entry_);
+ inferred_types_attribute_ ^= BytecodeReader::GetBytecodeAttribute(
+ function(), Symbols::vm_inferred_type_metadata());
+
kernel::BytecodeSourcePositionsIterator source_pos_iter(Z, bytecode);
bool update_position = source_pos_iter.MoveNext();
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
index 814b8df..6b1ea18 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
@@ -7,6 +7,7 @@
#include "vm/compiler/backend/il.h"
#include "vm/compiler/frontend/base_flow_graph_builder.h"
+#include "vm/compiler/frontend/kernel_translation_helper.h" // For InferredTypeMetadata
#include "vm/constants_kbc.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -42,7 +43,8 @@
stacktrace_var_(nullptr),
scratch_var_(nullptr),
prologue_info_(-1, -1),
- throw_no_such_method_(nullptr) {}
+ throw_no_such_method_(nullptr),
+ inferred_types_attribute_(Array::Handle(zone_)) {}
FlowGraph* BuildGraph();
@@ -158,6 +160,7 @@
intptr_t GetStackDepth() const;
bool IsStackEmpty() const;
ArgumentArray GetArguments(int count);
+ InferredTypeMetadata GetInferredType(intptr_t pc);
void PropagateStackState(intptr_t target_pc);
void DropUnusedValuesFromStack();
void BuildJumpIfStrictCompare(Token::Kind cmp_kind);
@@ -236,6 +239,8 @@
bool build_debug_step_checks_ = false;
bool seen_parameters_scope_ = false;
BytecodeScope* current_scope_ = nullptr;
+ Array& inferred_types_attribute_;
+ intptr_t inferred_types_index_ = 0;
};
} // namespace kernel
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
index 7d5970b..a888b26 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.cc
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -1885,6 +1885,26 @@
bool present = map.UpdateOrInsert(key, value);
ASSERT(!present);
I->object_store()->set_bytecode_attributes(map.Release());
+
+ if (key.IsField()) {
+ const Field& field = Field::Cast(key);
+ const auto& inferred_type_attr =
+ Array::CheckedHandle(Z, BytecodeReader::GetBytecodeAttribute(
+ key, Symbols::vm_inferred_type_metadata()));
+
+ if (!inferred_type_attr.IsNull() &&
+ (InferredTypeBytecodeAttribute::GetPCAt(inferred_type_attr, 0) ==
+ InferredTypeBytecodeAttribute::kFieldTypePC)) {
+ const InferredTypeMetadata type =
+ InferredTypeBytecodeAttribute::GetInferredTypeAt(
+ Z, inferred_type_attr, 0);
+ if (!type.IsTrivial()) {
+ field.set_guarded_cid(type.cid);
+ field.set_is_nullable(type.IsNullable());
+ field.set_guarded_list_length(Field::kNoFixedLength);
+ }
+ }
+ }
}
void BytecodeReaderHelper::ReadMembers(const Class& cls, bool discard_fields) {
@@ -3499,6 +3519,21 @@
return Object::null();
}
+InferredTypeMetadata InferredTypeBytecodeAttribute::GetInferredTypeAt(
+ Zone* zone,
+ const Array& attr,
+ intptr_t index) {
+ ASSERT(index + kNumElements <= attr.Length());
+ const auto& type = AbstractType::CheckedHandle(zone, attr.At(index + 1));
+ const intptr_t flags = Smi::Value(Smi::RawCast(attr.At(index + 2)));
+ if (!type.IsNull()) {
+ intptr_t cid = Type::Cast(type).type_class_id();
+ return InferredTypeMetadata(cid, flags);
+ } else {
+ return InferredTypeMetadata(kDynamicCid, flags);
+ }
+}
+
#if !defined(PRODUCT)
RawLocalVarDescriptors* BytecodeReader::ComputeLocalVarDescriptors(
Zone* zone,
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.h b/runtime/vm/compiler/frontend/bytecode_reader.h
index d5ad36d..418d021 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.h
+++ b/runtime/vm/compiler/frontend/bytecode_reader.h
@@ -370,6 +370,26 @@
#endif
};
+class InferredTypeBytecodeAttribute : public AllStatic {
+ public:
+ // Number of array elements per entry in InferredType bytecode
+ // attribute (PC, type, flags).
+ static constexpr intptr_t kNumElements = 3;
+
+ // Field type is the first entry with PC = -1.
+ static constexpr intptr_t kFieldTypePC = -1;
+
+ // Returns PC at given index.
+ static intptr_t GetPCAt(const Array& attr, intptr_t index) {
+ return Smi::Value(Smi::RawCast(attr.At(index)));
+ }
+
+ // Returns InferredType metadata at given index.
+ static InferredTypeMetadata GetInferredTypeAt(Zone* zone,
+ const Array& attr,
+ intptr_t index);
+};
+
class BytecodeSourcePositionsIterator : ValueObject {
public:
// These constants should match corresponding constants in class
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 9d06f55..c95b589 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -462,6 +462,7 @@
V(vm_prefer_inline, "vm:prefer-inline") \
V(vm_entry_point, "vm:entry-point") \
V(vm_exact_result_type, "vm:exact-result-type") \
+ V(vm_inferred_type_metadata, "vm.inferred-type.metadata") \
V(vm_never_inline, "vm:never-inline") \
V(vm_non_nullable_result_type, "vm:non-nullable-result-type") \
V(vm_trace_entrypoints, "vm:testing.unsafe.trace-entrypoints-fn") \