Skip to content

Commit 5d0d9e4

Browse files
alexmarkovCommit Queue
authored andcommitted
[vm,dyn_modules] Fix creation of dynamic invocation forwarders for bytecode functions
TEST=ci Change-Id: Id3e01591565c20fe8fe5f18438fdc66b61ac5e1a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/426521 Commit-Queue: Alexander Markov <[email protected]> Reviewed-by: Slava Egorov <[email protected]>
1 parent 8360666 commit 5d0d9e4

File tree

6 files changed

+106
-101
lines changed

6 files changed

+106
-101
lines changed

runtime/vm/compiler/aot/precompiler.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1821,7 +1821,7 @@ static void AddNamesToFunctionsTable(Zone* zone,
18211821
AddNameToFunctionsTable(zone, table, fname, function);
18221822

18231823
*dyn_function = function.ptr();
1824-
if (kernel::NeedsDynamicInvocationForwarder(function)) {
1824+
if (function.NeedsDynamicInvocationForwarder()) {
18251825
*mangled_name = function.name();
18261826
*mangled_name =
18271827
Function::CreateDynamicInvocationForwarderName(*mangled_name);

runtime/vm/interpreter.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3541,8 +3541,7 @@ ObjectPtr Interpreter::Run(Thread* thread,
35413541
ASSERT(Function::KindOf(function) ==
35423542
UntaggedFunction::kDynamicInvocationForwarder);
35433543

3544-
ArrayPtr checks = Array::RawCast(function->untag()->data());
3545-
FunctionPtr target = Function::RawCast(checks->untag()->element(0));
3544+
FunctionPtr target = Function::RawCast(function->untag()->data());
35463545
ASSERT(Function::KindOf(target) !=
35473546
UntaggedFunction::kDynamicInvocationForwarder);
35483547

runtime/vm/kernel.cc

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -654,89 +654,6 @@ void ReadParameterCovariance(const Function& function,
654654
}
655655
}
656656

657-
bool NeedsDynamicInvocationForwarder(const Function& function) {
658-
Zone* zone = Thread::Current()->zone();
659-
660-
// Right now closures do not need a dyn:* forwarder.
661-
// See https://github.com/dart-lang/sdk/issues/40813
662-
if (function.IsClosureFunction()) return false;
663-
664-
// Method extractors have no parameters to check and return value is a closure
665-
// and therefore not an unboxed primitive type.
666-
if (function.IsMethodExtractor()) {
667-
return false;
668-
}
669-
670-
// Record field getters have no parameters to check and 'dynamic' return type.
671-
if (function.IsRecordFieldGetter()) {
672-
return false;
673-
}
674-
675-
// Invoke field dispatchers are dynamically generated, will invoke a getter to
676-
// obtain the field value and then invoke ".call()" on the result.
677-
// Those dynamically generated dispathers don't have proper kernel metadata
678-
// associated with them - we can therefore not query if there are dynamic
679-
// calls to them or not and are therefore conservative.
680-
if (function.IsInvokeFieldDispatcher()) {
681-
return true;
682-
}
683-
684-
// The dyn:* forwarders perform unboxing of parameters before calling the
685-
// actual target (which accepts unboxed parameters) and boxes return values
686-
// of the return value.
687-
if (function.HasUnboxedParameters() || function.HasUnboxedReturnValue()) {
688-
return true;
689-
}
690-
691-
if (function.MaxNumberOfParametersInRegisters(zone) > 0) {
692-
return true;
693-
}
694-
695-
// There are no parameters to type check for getters and if the return value
696-
// is boxed, then the dyn:* forwarder is not needed.
697-
if (function.IsImplicitGetterFunction()) {
698-
return false;
699-
}
700-
701-
// Covariant parameters (both explicitly covariant and generic-covariant-impl)
702-
// are checked in the body of a function and therefore don't need checks in a
703-
// dynamic invocation forwarder. So dynamic invocation forwarder is only
704-
// needed if there are non-covariant parameters of non-top type.
705-
if (function.IsImplicitSetterFunction()) {
706-
const auto& field = Field::Handle(zone, function.accessor_field());
707-
return !(field.is_covariant() || field.is_generic_covariant_impl());
708-
}
709-
710-
const auto& type_params =
711-
TypeParameters::Handle(zone, function.type_parameters());
712-
if (!type_params.IsNull()) {
713-
auto& bound = AbstractType::Handle(zone);
714-
for (intptr_t i = 0, n = type_params.Length(); i < n; ++i) {
715-
bound = type_params.BoundAt(i);
716-
if (!bound.IsTopTypeForSubtyping() &&
717-
!type_params.IsGenericCovariantImplAt(i)) {
718-
return true;
719-
}
720-
}
721-
}
722-
723-
const intptr_t num_params = function.NumParameters();
724-
BitVector is_covariant(zone, num_params);
725-
BitVector is_generic_covariant_impl(zone, num_params);
726-
ReadParameterCovariance(function, &is_covariant, &is_generic_covariant_impl);
727-
728-
auto& type = AbstractType::Handle(zone);
729-
for (intptr_t i = function.NumImplicitParameters(); i < num_params; ++i) {
730-
type = function.ParameterTypeAt(i);
731-
if (!type.IsTopTypeForSubtyping() &&
732-
!is_generic_covariant_impl.Contains(i) && !is_covariant.Contains(i)) {
733-
return true;
734-
}
735-
}
736-
737-
return false;
738-
}
739-
740657
static ProcedureAttributesMetadata ProcedureAttributesOf(
741658
Zone* zone,
742659
const KernelProgramInfo& kernel_program_info,

runtime/vm/kernel.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,6 @@ void ReadParameterCovariance(const Function& function,
206206
BitVector* is_covariant,
207207
BitVector* is_generic_covariant_impl);
208208

209-
// Returns true if the given function needs dynamic invocation forwarder:
210-
// that is if any of the arguments require checking on the dynamic
211-
// call-site: if function has no parameters or has only covariant parameters
212-
// as such function already checks all of its parameters.
213-
bool NeedsDynamicInvocationForwarder(const Function& function);
214-
215209
ProcedureAttributesMetadata ProcedureAttributesOf(const Function& function,
216210
Zone* zone);
217211

runtime/vm/object.cc

Lines changed: 97 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4387,6 +4387,11 @@ FunctionPtr Function::CreateDynamicInvocationForwarder(
43874387
// blocks inlining and can't take Function-s only Code objects.
43884388
forwarder.set_is_visible(false);
43894389

4390+
#if defined(DART_DYNAMIC_MODULES)
4391+
if (HasBytecode()) {
4392+
forwarder.ClearBytecode();
4393+
}
4394+
#endif
43904395
forwarder.ClearICDataArray();
43914396
forwarder.ClearCode();
43924397
forwarder.set_usage_counter(0);
@@ -4428,13 +4433,7 @@ FunctionPtr Function::GetDynamicInvocationForwarder(
44284433
/*create_if_absent=*/false);
44294434
if (!result.IsNull()) return result.ptr();
44304435

4431-
const bool needs_dyn_forwarder =
4432-
#if defined(DART_DYNAMIC_MODULES) && defined(DART_PRECOMPILED_RUNTIME)
4433-
// TODO(alexmarkov)
4434-
false;
4435-
#else
4436-
kernel::NeedsDynamicInvocationForwarder(*this);
4437-
#endif
4436+
const bool needs_dyn_forwarder = NeedsDynamicInvocationForwarder();
44384437
if (!needs_dyn_forwarder) {
44394438
return ptr();
44404439
}
@@ -4455,6 +4454,90 @@ FunctionPtr Function::GetDynamicInvocationForwarder(
44554454
return result.ptr();
44564455
}
44574456

4457+
bool Function::NeedsDynamicInvocationForwarder() const {
4458+
Zone* zone = Thread::Current()->zone();
4459+
4460+
// Right now closures do not need a dyn:* forwarder.
4461+
// See https://github.com/dart-lang/sdk/issues/40813
4462+
if (IsClosureFunction()) return false;
4463+
4464+
// Method extractors have no parameters to check and return value is a closure
4465+
// and therefore not an unboxed primitive type.
4466+
if (IsMethodExtractor()) {
4467+
return false;
4468+
}
4469+
4470+
// Record field getters have no parameters to check and 'dynamic' return type.
4471+
if (IsRecordFieldGetter()) {
4472+
return false;
4473+
}
4474+
4475+
// Invoke field dispatchers are dynamically generated, will invoke a getter to
4476+
// obtain the field value and then invoke ".call()" on the result.
4477+
// Those dynamically generated dispathers don't have proper kernel metadata
4478+
// associated with them - we can therefore not query if there are dynamic
4479+
// calls to them or not and are therefore conservative.
4480+
if (IsInvokeFieldDispatcher()) {
4481+
return true;
4482+
}
4483+
4484+
#if !defined(DART_PRECOMPILED_RUNTIME)
4485+
// The dyn:* forwarders perform unboxing of parameters before calling the
4486+
// actual target (which accepts unboxed parameters) and boxes return values
4487+
// of the return value.
4488+
if (HasUnboxedParameters() || HasUnboxedReturnValue()) {
4489+
return true;
4490+
}
4491+
4492+
if (MaxNumberOfParametersInRegisters(zone) > 0) {
4493+
return true;
4494+
}
4495+
#endif
4496+
4497+
// There are no parameters to type check for getters and if the return value
4498+
// is boxed, then the dyn:* forwarder is not needed.
4499+
if (IsImplicitGetterFunction()) {
4500+
return false;
4501+
}
4502+
4503+
// Covariant parameters (both explicitly covariant and generic-covariant-impl)
4504+
// are checked in the body of a function and therefore don't need checks in a
4505+
// dynamic invocation forwarder. So dynamic invocation forwarder is only
4506+
// needed if there are non-covariant parameters of non-top type.
4507+
if (IsImplicitSetterFunction()) {
4508+
const auto& field = Field::Handle(zone, accessor_field());
4509+
return !(field.is_covariant() || field.is_generic_covariant_impl());
4510+
}
4511+
4512+
const auto& type_params = TypeParameters::Handle(zone, type_parameters());
4513+
if (!type_params.IsNull()) {
4514+
auto& bound = AbstractType::Handle(zone);
4515+
for (intptr_t i = 0, n = type_params.Length(); i < n; ++i) {
4516+
bound = type_params.BoundAt(i);
4517+
if (!bound.IsTopTypeForSubtyping() &&
4518+
!type_params.IsGenericCovariantImplAt(i)) {
4519+
return true;
4520+
}
4521+
}
4522+
}
4523+
4524+
const intptr_t num_params = NumParameters();
4525+
BitVector is_covariant(zone, num_params);
4526+
BitVector is_generic_covariant_impl(zone, num_params);
4527+
ReadParameterCovariance(&is_covariant, &is_generic_covariant_impl);
4528+
4529+
auto& type = AbstractType::Handle(zone);
4530+
for (intptr_t i = NumImplicitParameters(); i < num_params; ++i) {
4531+
type = ParameterTypeAt(i);
4532+
if (!type.IsTopTypeForSubtyping() &&
4533+
!is_generic_covariant_impl.Contains(i) && !is_covariant.Contains(i)) {
4534+
return true;
4535+
}
4536+
}
4537+
4538+
return false;
4539+
}
4540+
44584541
void Function::ReadParameterCovariance(
44594542
BitVector* is_covariant,
44604543
BitVector* is_generic_covariant_impl) const {
@@ -8393,6 +8476,12 @@ void Function::AttachBytecode(const Bytecode& value) const {
83938476
SetInstructions(StubCode::InterpretCall());
83948477
}
83958478

8479+
void Function::ClearBytecode() const {
8480+
ASSERT(HasBytecode());
8481+
untag()->set_ic_data_array_or_bytecode(Object::null());
8482+
ClearCode();
8483+
}
8484+
83968485
#endif // defined(DART_DYNAMIC_MODULES)
83978486

83988487
bool Function::HasCode(FunctionPtr function) {
@@ -11916,8 +12005,7 @@ bool Function::NeedsMonomorphicCheckedEntry(Zone* zone) const {
1191612005

1191712006
// Only if there are dynamic callers and if we didn't create a dyn:* forwarder
1191812007
// for it do we need the monomorphic checked entry.
11919-
return HasDynamicCallers(zone) &&
11920-
!kernel::NeedsDynamicInvocationForwarder(*this);
12008+
return HasDynamicCallers(zone) && !NeedsDynamicInvocationForwarder();
1192112009
#else
1192212010
UNREACHABLE();
1192312011
return true;

runtime/vm/object.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3271,6 +3271,7 @@ class Function : public Object {
32713271

32723272
#if defined(DART_DYNAMIC_MODULES)
32733273
void AttachBytecode(const Bytecode& bytecode) const;
3274+
void ClearBytecode() const;
32743275
inline BytecodePtr GetBytecode() const;
32753276
static inline BytecodePtr GetBytecode(FunctionPtr function);
32763277
inline bool HasBytecode() const;
@@ -4099,6 +4100,12 @@ class Function : public Object {
40994100

41004101
FunctionPtr GetDynamicInvocationForwarder(const String& mangled_name) const;
41014102

4103+
// Returns true if this function needs dynamic invocation forwarder:
4104+
// that is if any of the arguments require checking on the dynamic
4105+
// call-site: if function has no parameters or has only covariant parameters
4106+
// as such function already checks all of its parameters.
4107+
bool NeedsDynamicInvocationForwarder() const;
4108+
41024109
// Fills in [is_covariant] and [is_generic_covariant_impl] vectors
41034110
// according to covariance attributes of function parameters.
41044111
//

0 commit comments

Comments
 (0)