Skip to content

Commit 7a6287b

Browse files
sstricklcommit-bot@chromium.org
authored andcommitted
[vm] Perform non-covariant checks when dynamically invoking callables.
The VM only does this when the callable function does not expect dynamic invocations. Otherwise, performing the checks would be redundant, as the function body already contains the appropriate non-covariant checks. Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-release-x64-try,vm-dartkb-linux-release-x64-try Bug: #40813 Change-Id: I27b5f4067247c6b1b76ba57951a1d91455c2eeb5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/154463 Commit-Queue: Tess Strickland <[email protected]> Reviewed-by: Martin Kustermann <[email protected]>
1 parent 9de49b5 commit 7a6287b

File tree

2 files changed

+111
-48
lines changed

2 files changed

+111
-48
lines changed

runtime/vm/object.cc

Lines changed: 105 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4089,6 +4089,69 @@ ObjectPtr Class::InvokeSetter(const String& setter_name,
40894089
return value.raw();
40904090
}
40914091

4092+
// Creates a new array of boxed arguments suitable for invoking the callable
4093+
// from the original boxed arguments for a static call. Also sets the contents
4094+
// of the handle pointed to by [callable_args_desc_array_out] to an appropriate
4095+
// arguments descriptor array for the new arguments.
4096+
//
4097+
// Assumes [arg_names] are consistent with [static_args_descriptor].
4098+
static ArrayPtr CreateCallableArgumentsFromStatic(
4099+
Zone* zone,
4100+
const Instance& receiver,
4101+
const Array& static_args,
4102+
const Array& arg_names,
4103+
const ArgumentsDescriptor& static_args_descriptor) {
4104+
const intptr_t num_static_type_args = static_args_descriptor.TypeArgsLen();
4105+
const intptr_t num_static_args = static_args_descriptor.Count();
4106+
// Double check that the static args descriptor expects boxed arguments
4107+
// and the static args descriptor is consistent with the static arguments.
4108+
ASSERT_EQUAL(static_args_descriptor.Size(), num_static_args);
4109+
ASSERT_EQUAL(static_args.Length(),
4110+
num_static_args + (num_static_type_args > 0 ? 1 : 0));
4111+
// Add an additional slot to store the callable as the receiver.
4112+
const auto& callable_args =
4113+
Array::Handle(zone, Array::New(static_args.Length() + 1));
4114+
const intptr_t first_arg_index = static_args_descriptor.FirstArgIndex();
4115+
auto& temp = Object::Handle(zone);
4116+
// Copy the static args into the corresponding slots of the callable args.
4117+
if (num_static_type_args > 0) {
4118+
temp = static_args.At(0);
4119+
callable_args.SetAt(0, temp);
4120+
}
4121+
for (intptr_t i = first_arg_index; i < static_args.Length(); i++) {
4122+
temp = static_args.At(i);
4123+
callable_args.SetAt(i + 1, temp);
4124+
}
4125+
// Set the receiver slot in the callable args.
4126+
callable_args.SetAt(first_arg_index, receiver);
4127+
return callable_args.raw();
4128+
}
4129+
4130+
// Return the result of invoking the callable contained in the arguments.
4131+
// Performs non-covariant type checks when the callable function does not
4132+
// expect to be called dynamically.
4133+
static ObjectPtr InvokeCallableWithChecks(Zone* zone,
4134+
const Array& args,
4135+
const Array& args_descriptor_array) {
4136+
auto& result = Object::Handle(
4137+
zone, DartEntry::ResolveCallable(args, args_descriptor_array));
4138+
if (result.IsError()) {
4139+
return result.raw();
4140+
}
4141+
const auto& function =
4142+
Function::Handle(zone, Function::RawCast(result.raw()));
4143+
if (!function.IsNull() && !function.CanReceiveDynamicInvocation()) {
4144+
// Let DoArgumentTypesMatch extract the appropriate instantiator
4145+
// and function tavs from the arguments (including the callable).
4146+
ArgumentsDescriptor call_args_descriptor(args_descriptor_array);
4147+
result = function.DoArgumentTypesMatch(args, call_args_descriptor);
4148+
if (result.IsError()) {
4149+
return result.raw();
4150+
}
4151+
}
4152+
return DartEntry::InvokeCallable(function, args, args_descriptor_array);
4153+
}
4154+
40924155
ObjectPtr Class::Invoke(const String& function_name,
40934156
const Array& args,
40944157
const Array& arg_names,
@@ -4101,6 +4164,10 @@ ObjectPtr Class::Invoke(const String& function_name,
41014164
// We don't pass any explicit type arguments, which will be understood as
41024165
// using dynamic for any function type arguments by lower layers.
41034166
const int kTypeArgsLen = 0;
4167+
const Array& args_descriptor_array = Array::Handle(
4168+
zone, ArgumentsDescriptor::NewBoxed(kTypeArgsLen, args.Length(),
4169+
arg_names, Heap::kNew));
4170+
ArgumentsDescriptor args_descriptor(args_descriptor_array);
41044171

41054172
Function& function =
41064173
Function::Handle(zone, LookupStaticFunction(function_name));
@@ -4118,26 +4185,19 @@ ObjectPtr Class::Invoke(const String& function_name,
41184185
if (check_is_entrypoint) {
41194186
CHECK_ERROR(EntryPointFieldInvocationError(function_name));
41204187
}
4121-
// Make room for the closure (receiver) in the argument list.
4122-
const intptr_t num_args = args.Length();
4123-
const Array& call_args = Array::Handle(zone, Array::New(num_args + 1));
4124-
Object& temp = Object::Handle(zone);
4125-
for (int i = 0; i < num_args; i++) {
4126-
temp = args.At(i);
4127-
call_args.SetAt(i + 1, temp);
4128-
}
4129-
call_args.SetAt(0, getter_result);
4130-
const Array& call_args_descriptor_array = Array::Handle(
4131-
zone, ArgumentsDescriptor::NewBoxed(kTypeArgsLen, call_args.Length(),
4188+
const auto& call_args_descriptor_array = Array::Handle(
4189+
zone, ArgumentsDescriptor::NewBoxed(args_descriptor.TypeArgsLen(),
4190+
args_descriptor.Count() + 1,
41324191
arg_names, Heap::kNew));
4133-
// Call the closure.
4134-
return DartEntry::InvokeClosure(call_args, call_args_descriptor_array);
4192+
const auto& call_args = Array::Handle(
4193+
zone,
4194+
CreateCallableArgumentsFromStatic(zone, Instance::Cast(getter_result),
4195+
args, arg_names, args_descriptor));
4196+
return InvokeCallableWithChecks(zone, call_args,
4197+
call_args_descriptor_array);
41354198
}
41364199
}
4137-
const Array& args_descriptor_array = Array::Handle(
4138-
zone, ArgumentsDescriptor::NewBoxed(kTypeArgsLen, args.Length(),
4139-
arg_names, Heap::kNew));
4140-
ArgumentsDescriptor args_descriptor(args_descriptor_array);
4200+
41414201
if (function.IsNull() || !function.AreValidArguments(args_descriptor, NULL) ||
41424202
(respect_reflectable && !function.is_reflectable())) {
41434203
return ThrowNoSuchMethod(
@@ -12778,14 +12838,22 @@ ObjectPtr Library::Invoke(const String& function_name,
1277812838
const Array& arg_names,
1277912839
bool respect_reflectable,
1278012840
bool check_is_entrypoint) const {
12841+
Thread* thread = Thread::Current();
12842+
Zone* zone = thread->zone();
12843+
1278112844
// We don't pass any explicit type arguments, which will be understood as
1278212845
// using dynamic for any function type arguments by lower layers.
1278312846
const int kTypeArgsLen = 0;
12847+
const Array& args_descriptor_array = Array::Handle(
12848+
zone, ArgumentsDescriptor::NewBoxed(kTypeArgsLen, args.Length(),
12849+
arg_names, Heap::kNew));
12850+
ArgumentsDescriptor args_descriptor(args_descriptor_array);
1278412851

12785-
Function& function = Function::Handle();
12786-
Object& obj = Object::Handle(LookupLocalOrReExportObject(function_name));
12787-
if (obj.IsFunction()) {
12788-
function ^= obj.raw();
12852+
auto& function = Function::Handle(zone);
12853+
auto& result =
12854+
Object::Handle(zone, LookupLocalOrReExportObject(function_name));
12855+
if (result.IsFunction()) {
12856+
function ^= result.raw();
1278912857
}
1279012858

1279112859
if (!function.IsNull() && check_is_entrypoint) {
@@ -12794,37 +12862,31 @@ ObjectPtr Library::Invoke(const String& function_name,
1279412862

1279512863
if (function.IsNull()) {
1279612864
// Didn't find a method: try to find a getter and invoke call on its result.
12797-
const Object& getter_result = Object::Handle(InvokeGetter(
12798-
function_name, false, respect_reflectable, check_is_entrypoint));
12865+
const Object& getter_result = Object::Handle(
12866+
zone, InvokeGetter(function_name, false, respect_reflectable,
12867+
check_is_entrypoint));
1279912868
if (getter_result.raw() != Object::sentinel().raw()) {
1280012869
if (check_is_entrypoint) {
1280112870
CHECK_ERROR(EntryPointFieldInvocationError(function_name));
1280212871
}
12803-
// Make room for the closure (receiver) in arguments.
12804-
intptr_t numArgs = args.Length();
12805-
const Array& call_args = Array::Handle(Array::New(numArgs + 1));
12806-
Object& temp = Object::Handle();
12807-
for (int i = 0; i < numArgs; i++) {
12808-
temp = args.At(i);
12809-
call_args.SetAt(i + 1, temp);
12810-
}
12811-
call_args.SetAt(0, getter_result);
12812-
const Array& call_args_descriptor_array =
12813-
Array::Handle(ArgumentsDescriptor::NewBoxed(
12814-
kTypeArgsLen, call_args.Length(), arg_names, Heap::kNew));
12815-
// Call closure.
12816-
return DartEntry::InvokeClosure(call_args, call_args_descriptor_array);
12872+
const auto& call_args_descriptor_array = Array::Handle(
12873+
zone, ArgumentsDescriptor::NewBoxed(args_descriptor.TypeArgsLen(),
12874+
args_descriptor.Count() + 1,
12875+
arg_names, Heap::kNew));
12876+
const auto& call_args = Array::Handle(
12877+
zone,
12878+
CreateCallableArgumentsFromStatic(zone, Instance::Cast(getter_result),
12879+
args, arg_names, args_descriptor));
12880+
return InvokeCallableWithChecks(zone, call_args,
12881+
call_args_descriptor_array);
1281712882
}
1281812883
}
1281912884

12820-
const Array& args_descriptor_array =
12821-
Array::Handle(ArgumentsDescriptor::NewBoxed(kTypeArgsLen, args.Length(),
12822-
arg_names, Heap::kNew));
12823-
ArgumentsDescriptor args_descriptor(args_descriptor_array);
1282412885
if (function.IsNull() || !function.AreValidArguments(args_descriptor, NULL) ||
1282512886
(respect_reflectable && !function.is_reflectable())) {
1282612887
return ThrowNoSuchMethod(
12827-
AbstractType::Handle(Class::Handle(toplevel_class()).RareType()),
12888+
AbstractType::Handle(zone,
12889+
Class::Handle(zone, toplevel_class()).RareType()),
1282812890
function_name, args, arg_names, InvocationMirror::kTopLevel,
1282912891
InvocationMirror::kMethod);
1283012892
}
@@ -17949,8 +18011,7 @@ ObjectPtr Instance::Invoke(const String& function_name,
1794918011
}
1795018012
// Replace the closure as the receiver in the arguments list.
1795118013
args.SetAt(0, getter_result);
17952-
// Call the closure.
17953-
return DartEntry::InvokeClosure(args, args_descriptor);
18014+
return InvokeCallableWithChecks(zone, args, args_descriptor);
1795418015
}
1795518016
}
1795618017

runtime/vm/object.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2831,11 +2831,14 @@ class Function : public Object {
28312831
return (kind() == FunctionLayout::kConstructor) && is_static();
28322832
}
28332833

2834+
static bool ClosureBodiesContainNonCovariantChecks() {
2835+
return FLAG_precompiled_mode || FLAG_lazy_dispatchers;
2836+
}
2837+
28342838
// Whether this function can receive an invocation where the number and names
28352839
// of arguments have not been checked.
28362840
bool CanReceiveDynamicInvocation() const {
2837-
return (IsClosureFunction() &&
2838-
(FLAG_lazy_dispatchers || FLAG_precompiled_mode)) ||
2841+
return (IsClosureFunction() && ClosureBodiesContainNonCovariantChecks()) ||
28392842
IsFfiTrampoline();
28402843
}
28412844

@@ -2903,8 +2906,7 @@ class Function : public Object {
29032906
bool IsInFactoryScope() const;
29042907

29052908
bool NeedsArgumentTypeChecks() const {
2906-
return (IsClosureFunction() &&
2907-
(FLAG_lazy_dispatchers || FLAG_precompiled_mode)) ||
2909+
return (IsClosureFunction() && ClosureBodiesContainNonCovariantChecks()) ||
29082910
!(is_static() || (kind() == FunctionLayout::kConstructor));
29092911
}
29102912

0 commit comments

Comments
 (0)