[vm] Extract reading of parameter covariance attributes
This change extracts code which reads kernel in order to get
covariance attributes of parameters into a separate function.
This removes code duplication and makes it easier to hook up
reading of covariance attributes from bytecode in future.
Change-Id: Ia19caf3edaf45df9e0bb1bdc715fac21d26788dc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/96560
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Auto-Submit: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Samir Jindel <sjindel@google.com>
diff --git a/runtime/vm/kernel.cc b/runtime/vm/kernel.cc
index 2776042..5d67407 100644
--- a/runtime/vm/kernel.cc
+++ b/runtime/vm/kernel.cc
@@ -4,6 +4,7 @@
#include "vm/kernel.h"
+#include "vm/bit_vector.h"
#include "vm/compiler/frontend/constant_evaluator.h"
#include "vm/compiler/frontend/kernel_translation_helper.h"
#include "vm/longjump.h"
@@ -585,89 +586,100 @@
}
}
-bool NeedsDynamicInvocationForwarder(const Function& function) {
+void ReadParameterCovariance(const Function& function,
+ BitVector* is_covariant,
+ BitVector* is_generic_covariant_impl) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
- TranslationHelper helper(thread);
- Script& script = Script::Handle(zone, function.script());
- helper.InitFromScript(script);
+ const intptr_t num_params = function.NumParameters();
+ ASSERT(is_covariant->length() == num_params);
+ ASSERT(is_generic_covariant_impl->length() == num_params);
- // Setup a [ActiveClassScope] and a [ActiveMemberScope] which will be used
- // e.g. for type translation.
-
- const Class& owner_class = Class::Handle(zone, function.Owner());
- Function& outermost_function =
- Function::Handle(zone, function.GetOutermostFunction());
-
- ActiveClass active_class;
- ActiveClassScope active_class_scope(&active_class, &owner_class);
- ActiveMemberScope active_member(&active_class, &outermost_function);
- ActiveTypeParametersScope active_type_params(&active_class, function, zone);
+ const auto& script = Script::Handle(zone, function.script());
+ TranslationHelper translation_helper(thread);
+ translation_helper.InitFromScript(script);
KernelReaderHelper reader_helper(
- zone, &helper, script,
+ zone, &translation_helper, script,
ExternalTypedData::Handle(zone, function.KernelData()),
function.KernelDataProgramOffset());
- TypeTranslator type_translator(&reader_helper, &active_class,
- /* finalize= */ true);
-
reader_helper.SetOffset(function.kernel_offset());
-
- // Handle setters.
- if (reader_helper.PeekTag() == kField) {
- ASSERT(function.IsImplicitSetterFunction());
- const auto& field = Field::Handle(zone, function.accessor_field());
- return !(field.is_covariant() || field.is_generic_covariant_impl());
- }
-
reader_helper.ReadUntilFunctionNode();
FunctionNodeHelper function_node_helper(&reader_helper);
- function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters);
- intptr_t num_type_params = reader_helper.ReadListLength();
-
- for (intptr_t i = 0; i < num_type_params; ++i) {
- TypeParameterHelper helper(&reader_helper);
- helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound);
- AbstractType& bound = type_translator.BuildType(); // read bound
- helper.Finish();
-
- if (!bound.IsTopType() && !helper.IsGenericCovariantImpl()) {
- return true;
- }
- }
- function_node_helper.SetJustRead(FunctionNodeHelper::kTypeParameters);
function_node_helper.ReadUntilExcluding(
FunctionNodeHelper::kPositionalParameters);
// Positional.
const intptr_t num_positional_params = reader_helper.ReadListLength();
- for (intptr_t i = 0; i < num_positional_params; ++i) {
+ intptr_t param_index = function.NumImplicitParameters();
+ for (intptr_t i = 0; i < num_positional_params; ++i, ++param_index) {
VariableDeclarationHelper helper(&reader_helper);
- helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
- AbstractType& type = type_translator.BuildType(); // read type.
- helper.SetJustRead(VariableDeclarationHelper::kType);
helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd);
- if (!type.IsTopType() && !helper.IsGenericCovariantImpl() &&
- !helper.IsCovariant()) {
- return true;
+ if (helper.IsCovariant()) {
+ is_covariant->Add(param_index);
+ }
+ if (helper.IsGenericCovariantImpl()) {
+ is_generic_covariant_impl->Add(param_index);
}
}
// Named.
const intptr_t num_named_params = reader_helper.ReadListLength();
- for (intptr_t i = 0; i < num_named_params; ++i) {
+ for (intptr_t i = 0; i < num_named_params; ++i, ++param_index) {
VariableDeclarationHelper helper(&reader_helper);
- helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
- AbstractType& type = type_translator.BuildType(); // read type.
- helper.SetJustRead(VariableDeclarationHelper::kType);
helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd);
- if (!type.IsTopType() && !helper.IsGenericCovariantImpl() &&
- !helper.IsCovariant()) {
+ if (helper.IsCovariant()) {
+ is_covariant->Add(param_index);
+ }
+ if (helper.IsGenericCovariantImpl()) {
+ is_generic_covariant_impl->Add(param_index);
+ }
+ }
+}
+
+bool NeedsDynamicInvocationForwarder(const Function& function) {
+ Zone* zone = Thread::Current()->zone();
+
+ // Covariant parameters (both explicitly covariant and generic-covariant-impl)
+ // are checked in the body of a function and therefore don't need checks in a
+ // dynamic invocation forwarder. So dynamic invocation forwarder is only
+ // needed if there are non-covariant parameters of non-top type.
+
+ ASSERT(!function.IsImplicitGetterFunction());
+ if (function.IsImplicitSetterFunction()) {
+ const auto& field = Field::Handle(zone, function.accessor_field());
+ return !(field.is_covariant() || field.is_generic_covariant_impl());
+ }
+
+ const auto& type_params =
+ TypeArguments::Handle(zone, function.type_parameters());
+ if (!type_params.IsNull()) {
+ auto& type_param = TypeParameter::Handle(zone);
+ auto& bound = AbstractType::Handle(zone);
+ for (intptr_t i = 0, n = type_params.Length(); i < n; ++i) {
+ type_param ^= type_params.TypeAt(i);
+ bound = type_param.bound();
+ if (!bound.IsTopType() && !type_param.IsGenericCovariantImpl()) {
+ return true;
+ }
+ }
+ }
+
+ const intptr_t num_params = function.NumParameters();
+ BitVector is_covariant(zone, num_params);
+ BitVector is_generic_covariant_impl(zone, num_params);
+ ReadParameterCovariance(function, &is_covariant, &is_generic_covariant_impl);
+
+ auto& type = AbstractType::Handle(zone);
+ for (intptr_t i = function.NumImplicitParameters(); i < num_params; ++i) {
+ type = function.ParameterTypeAt(i);
+ if (!type.IsTopType() && !is_generic_covariant_impl.Contains(i) &&
+ !is_covariant.Contains(i)) {
return true;
}
}
diff --git a/runtime/vm/kernel.h b/runtime/vm/kernel.h
index 34609b8..db52690 100644
--- a/runtime/vm/kernel.h
+++ b/runtime/vm/kernel.h
@@ -32,6 +32,7 @@
#if !defined(DART_PRECOMPILED_RUNTIME)
namespace dart {
+class BitVector;
class Field;
class ParsedFunction;
class Zone;
@@ -194,6 +195,15 @@
bool is_annotations_offset);
RawObject* BuildParameterDescriptor(const Function& function);
+// Fills in [is_covariant] and [is_generic_covariant_impl] vectors
+// according to covariance attributes of [function] parameters.
+//
+// [is_covariant] and [is_generic_covariant_impl] should contain bitvectors
+// of function.NumParameters() length.
+void ReadParameterCovariance(const Function& function,
+ BitVector* is_covariant,
+ BitVector* is_generic_covariant_impl);
+
// Returns true if the given function needs dynamic invocation forwarder:
// that is if any of the arguments require checking on the dynamic
// call-site: if function has no parameters or has only covariant parameters
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 9c9e092..1920a34 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7335,46 +7335,17 @@
// Change covariant parameter types to Object in the implicit closure.
if (!is_static()) {
- const Script& function_script = Script::Handle(zone, script());
- kernel::TranslationHelper translation_helper(thread);
- translation_helper.InitFromScript(function_script);
+ BitVector is_covariant(zone, NumParameters());
+ BitVector is_generic_covariant_impl(zone, NumParameters());
+ kernel::ReadParameterCovariance(*this, &is_covariant,
+ &is_generic_covariant_impl);
- kernel::KernelReaderHelper kernel_reader_helper(
- zone, &translation_helper, function_script,
- ExternalTypedData::Handle(zone, KernelData()),
- KernelDataProgramOffset());
-
- kernel_reader_helper.SetOffset(kernel_offset());
- kernel_reader_helper.ReadUntilFunctionNode();
-
- kernel::FunctionNodeHelper fn_helper(&kernel_reader_helper);
-
- // Check the positional parameters, including the optional positional ones.
- fn_helper.ReadUntilExcluding(
- kernel::FunctionNodeHelper::kPositionalParameters);
- intptr_t num_pos_params = kernel_reader_helper.ReadListLength();
- ASSERT(num_pos_params ==
- num_fixed_params - 1 + (has_opt_pos_params ? num_opt_params : 0));
const Type& object_type = Type::Handle(zone, Type::ObjectType());
- for (intptr_t i = 0; i < num_pos_params; ++i) {
- kernel::VariableDeclarationHelper var_helper(&kernel_reader_helper);
- var_helper.ReadUntilExcluding(kernel::VariableDeclarationHelper::kEnd);
- if (var_helper.IsCovariant() || var_helper.IsGenericCovariantImpl()) {
- closure_function.SetParameterTypeAt(i + 1, object_type);
- }
- }
- fn_helper.SetJustRead(kernel::FunctionNodeHelper::kPositionalParameters);
-
- // Check the optional named parameters.
- fn_helper.ReadUntilExcluding(kernel::FunctionNodeHelper::kNamedParameters);
- intptr_t num_named_params = kernel_reader_helper.ReadListLength();
- ASSERT(num_named_params == (has_opt_pos_params ? 0 : num_opt_params));
- for (intptr_t i = 0; i < num_named_params; ++i) {
- kernel::VariableDeclarationHelper var_helper(&kernel_reader_helper);
- var_helper.ReadUntilExcluding(kernel::VariableDeclarationHelper::kEnd);
- if (var_helper.IsCovariant() || var_helper.IsGenericCovariantImpl()) {
- closure_function.SetParameterTypeAt(num_pos_params + 1 + i,
- object_type);
+ for (intptr_t i = kClosure; i < num_params; ++i) {
+ const intptr_t original_param_index = has_receiver - kClosure + i;
+ if (is_covariant.Contains(original_param_index) ||
+ is_generic_covariant_impl.Contains(original_param_index)) {
+ closure_function.SetParameterTypeAt(i, object_type);
}
}
}