Skip to content

Commit 24b158a

Browse files
alexmarkovCommit Queue
authored andcommitted
[vm,compiler] Avoid slow LookupFunctionAllowPrivate when reading kernel
When reading kernel function names are already mangled using private key, so slower *AllowPrivate lookups are not needed. Also cleaned up unused functions related to *AllowPrivate lookups. TEST=runtime/tests/vm/dart/many_functions_test.dart Fixes #61196 Change-Id: I8dd0b8b907ecea79314480dbc39e0edda8a243d0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/443151 Reviewed-by: Ryan Macnak <[email protected]> Commit-Queue: Alexander Markov <[email protected]>
1 parent 97a23cf commit 24b158a

File tree

12 files changed

+137
-142
lines changed

12 files changed

+137
-142
lines changed

DEPS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,12 @@ hooks = [
701701
'pattern': '.',
702702
'action': ['python3', Var("dart_root") + '/tools/generate_sdk_version_file.py'],
703703
},
704+
{
705+
# Generate large tests.
706+
'name': 'Generate large tests',
707+
'pattern': '.',
708+
'action': ['python3', Var("dart_root") + '/tools/generate_large_tests.py'],
709+
},
704710
{
705711
'name': 'buildtools',
706712
'pattern': '.',

runtime/tests/vm/dart/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Auto-generated tests
2+
many_functions_test.dart
3+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// Generates 'runtime/tests/vm/dart/many_functions_test.dart'.
6+
// This auto-generated test verifies that compiler and VM are capable of
7+
// handling many functions.
8+
9+
void main(List<String> args) {
10+
final count = 10000;
11+
final buffer = StringBuffer();
12+
buffer.write('''
13+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
14+
// for details. All rights reserved. Use of this source code is governed by a
15+
// BSD-style license that can be found in the LICENSE file.
16+
17+
// THIS FILE IS GENERATED. DO NOT EDIT.
18+
19+
''');
20+
for (var i = 0; i < count; i++) {
21+
buffer.write(generateFunction(i));
22+
}
23+
24+
buffer.write('''
25+
void main() {
26+
final array = [];
27+
''');
28+
for (var i = 0; i < count; i++) {
29+
buffer.write('array.add(f$i());\n');
30+
}
31+
buffer.write('''
32+
print('ran \${array.length} functions');
33+
}
34+
''');
35+
36+
print(buffer.toString());
37+
}
38+
39+
String generateFunction(int index) {
40+
return '''
41+
@pragma('vm:never-inline')
42+
String f$index() { return 'function$index'; }
43+
''';
44+
}

runtime/tests/vm/vm.status

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ cc/VerifyImplicit_Crash: Crash # Negative tests of VerifiedMemory should crash i
138138
dart/appjit_cha_deopt_test: Pass, Slow # Quite slow in debug mode, uses --optimization-counter-threshold=100
139139
dart/b162922506_test: SkipSlow # Generates very large input file
140140
dart/hash_map_probes_limit_test: SkipSlow # Test includes large program compilation.
141+
dart/many_functions_test: SkipSlow # Too slow in debug mode.
141142
dart/minimal_kernel_test: SkipSlow # gen_kernel is too slow in debug mode
142143
dart/regress47472_test: Pass, Slow # Slow due to throwing 1 million exceptions.
143144
dart/spawn_shutdown_test: Pass, Slow # VM Shutdown test, It can take some time for all the isolates to shutdown in a Debug build.

runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,9 +1484,8 @@ Function& StreamingFlowGraphBuilder::FindMatchingFunction(
14841484
ArgumentsDescriptor args_desc(
14851485
Array::Handle(Z, ArgumentsDescriptor::NewBoxed(
14861486
type_args_len, argument_count, argument_names)));
1487-
return Function::Handle(
1488-
Z, Resolver::ResolveDynamicForReceiverClassAllowPrivate(klass, name,
1489-
args_desc));
1487+
return Function::Handle(Z, Resolver::ResolveDynamicForReceiverClass(
1488+
klass, name, args_desc, /*allow_add=*/false));
14901489
}
14911490

14921491
bool StreamingFlowGraphBuilder::NeedsDebugStepCheck(const Function& function,

runtime/vm/compiler/frontend/kernel_translation_helper.cc

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -561,8 +561,7 @@ ClassPtr TranslationHelper::LookupClassByKernelClass(NameIndex kernel_class,
561561
}
562562
return Class::null();
563563
}
564-
const Class& klass =
565-
Class::Handle(Z, library.LookupClassAllowPrivate(class_name));
564+
const Class& klass = Class::Handle(Z, library.LookupClass(class_name));
566565
if (klass.IsNull()) {
567566
if (required) {
568567
LookupFailed(kernel_class);
@@ -602,9 +601,8 @@ FieldPtr TranslationHelper::LookupFieldByKernelField(NameIndex kernel_field,
602601
}
603602
return Field::null();
604603
}
605-
Field& field = Field::Handle(
606-
Z, klass.LookupFieldAllowPrivate(
607-
DartSymbolObfuscate(CanonicalNameString(kernel_field))));
604+
Field& field =
605+
Field::Handle(Z, klass.LookupField(DartFieldName(kernel_field)));
608606
if (field.IsNull() && required) {
609607
LookupFailed(kernel_field);
610608
}
@@ -625,9 +623,8 @@ FieldPtr TranslationHelper::LookupFieldByKernelGetterOrSetter(
625623
}
626624
return Field::null();
627625
}
628-
const Field& field = Field::Handle(
629-
Z, klass.LookupFieldAllowPrivate(
630-
DartSymbolObfuscate(CanonicalNameString(kernel_field))));
626+
const Field& field =
627+
Field::Handle(Z, klass.LookupField(DartFieldName(kernel_field)));
631628
if (field.IsNull() && required) {
632629
LookupFailed(kernel_field);
633630
}
@@ -654,7 +651,7 @@ FunctionPtr TranslationHelper::LookupStaticMethodByKernelProcedure(
654651
const auto& error = klass.EnsureIsFinalized(thread_);
655652
ASSERT(error == Error::null());
656653
Function& function =
657-
Function::Handle(Z, klass.LookupFunctionAllowPrivate(procedure_name));
654+
Function::Handle(Z, klass.LookupFunction(procedure_name));
658655
if (function.IsNull() && required) {
659656
LookupFailed(procedure);
660657
}
@@ -687,7 +684,7 @@ FunctionPtr TranslationHelper::LookupConstructorByKernelConstructor(
687684
const auto& error = owner.EnsureIsFinalized(thread_);
688685
ASSERT(error == Error::null());
689686
Function& function = Function::Handle(
690-
Z, owner.LookupConstructorAllowPrivate(DartConstructorName(constructor)));
687+
Z, owner.LookupConstructor(DartConstructorName(constructor)));
691688
if (function.IsNull() && required) {
692689
LookupFailed(constructor);
693690
}
@@ -708,7 +705,7 @@ FunctionPtr TranslationHelper::LookupConstructorByKernelConstructor(
708705
String::ZoneHandle(Z, Symbols::FromConcatAll(thread_, pieces));
709706
const auto& error = owner.EnsureIsFinalized(thread_);
710707
ASSERT(error == Error::null());
711-
FunctionPtr function = owner.LookupConstructorAllowPrivate(new_name);
708+
FunctionPtr function = owner.LookupConstructor(new_name);
712709
if (function == Object::null() && required) {
713710
LookupFailed(constructor_name);
714711
}
@@ -723,7 +720,7 @@ FunctionPtr TranslationHelper::LookupMethodByMember(NameIndex target,
723720
Z, LookupClassByKernelClass(kernel_class, /*required=*/false));
724721
Function& function = Function::Handle(Z);
725722
if (!klass.IsNull() && klass.EnsureIsFinalized(thread_) == Error::null()) {
726-
function = klass.LookupFunctionAllowPrivate(method_name);
723+
function = klass.LookupFunction(method_name);
727724
}
728725
if (function.IsNull() && required) {
729726
LookupFailed(target);
@@ -746,36 +743,20 @@ ObjectPtr TranslationHelper::LookupMemberByMember(NameIndex kernel_name,
746743

747744
Object& member = Object::Handle(Z);
748745
if (IsField(kernel_name)) {
749-
member = klass.LookupFieldAllowPrivate(
750-
DartSymbolObfuscate(CanonicalNameString(kernel_name)));
746+
member = klass.LookupField(DartFieldName(kernel_name));
751747
} else {
752748
const String& procedure_name = DartProcedureName(kernel_name);
753749

754750
const auto& error = klass.EnsureIsFinalized(thread_);
755751
ASSERT(error == Error::null());
756-
member = klass.LookupFunctionAllowPrivate(procedure_name);
752+
member = klass.LookupFunction(procedure_name);
757753
}
758754
if (member.IsNull() && required) {
759755
LookupFailed(kernel_name);
760756
}
761757
return member.ptr();
762758
}
763759

764-
FunctionPtr TranslationHelper::LookupDynamicFunction(const Class& klass,
765-
const String& name) {
766-
// Search the superclass chain for the selector.
767-
Class& iterate_klass = Class::Handle(Z, klass.ptr());
768-
while (!iterate_klass.IsNull()) {
769-
FunctionPtr function =
770-
iterate_klass.LookupDynamicFunctionAllowPrivate(name);
771-
if (function != Object::null()) {
772-
return function;
773-
}
774-
iterate_klass = iterate_klass.SuperClass();
775-
}
776-
return Function::null();
777-
}
778-
779760
Type& TranslationHelper::GetDeclarationType(const Class& klass) {
780761
ASSERT(!klass.IsNull());
781762
// Forward expression evaluation class to a real class when

runtime/vm/compiler/frontend/kernel_translation_helper.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ class TranslationHelper {
176176
const String& method_name,
177177
bool required = true);
178178
ObjectPtr LookupMemberByMember(NameIndex kernel_name, bool required = true);
179-
FunctionPtr LookupDynamicFunction(const Class& klass, const String& name);
180179

181180
Type& GetDeclarationType(const Class& klass);
182181

runtime/vm/object.cc

Lines changed: 6 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -233,27 +233,6 @@ PRECOMPILER_WSR_FIELD_DEFINITION(Function, FunctionType, signature)
233233
}
234234
#endif
235235

236-
// Remove private keys, but retain getter/setter/constructor/mixin manglings.
237-
StringPtr String::RemovePrivateKey(const String& name) {
238-
ASSERT(name.IsOneByteString());
239-
GrowableArray<uint8_t> without_key(name.Length());
240-
intptr_t i = 0;
241-
while (i < name.Length()) {
242-
while (i < name.Length()) {
243-
uint8_t c = name.CharAt(i++);
244-
if (c == '@') break;
245-
without_key.Add(c);
246-
}
247-
while (i < name.Length()) {
248-
uint8_t c = name.CharAt(i);
249-
if ((c < '0') || (c > '9')) break;
250-
i++;
251-
}
252-
}
253-
254-
return String::FromLatin1(without_key.data(), without_key.length());
255-
}
256-
257236
// Takes a vm internal name and makes it suitable for external user.
258237
//
259238
// Examples:
@@ -6670,10 +6649,6 @@ FunctionPtr Class::LookupDynamicFunctionUnsafe(const String& name) const {
66706649
return LookupFunctionReadLocked(name, kInstance);
66716650
}
66726651

6673-
FunctionPtr Class::LookupDynamicFunctionAllowPrivate(const String& name) const {
6674-
return LookupFunctionAllowPrivate(name, kInstance);
6675-
}
6676-
66776652
FunctionPtr Class::LookupStaticFunction(const String& name) const {
66786653
Thread* thread = Thread::Current();
66796654
SafepointReadRwLocker ml(thread, thread->isolate_group()->program_lock());
@@ -6708,32 +6683,14 @@ FunctionPtr Class::LookupFunctionAllowPrivate(const String& name) const {
67086683
return LookupFunctionAllowPrivate(name, kAny);
67096684
}
67106685

6711-
FunctionPtr Class::LookupFunctionReadLocked(const String& name) const {
6712-
return LookupFunctionReadLocked(name, kAny);
6686+
FunctionPtr Class::LookupFunction(const String& name) const {
6687+
Thread* thread = Thread::Current();
6688+
SafepointReadRwLocker ml(thread, thread->isolate_group()->program_lock());
6689+
return LookupFunctionReadLocked(name);
67136690
}
67146691

6715-
// Returns true if 'prefix' and 'accessor_name' match 'name'.
6716-
static bool MatchesAccessorName(const String& name,
6717-
const char* prefix,
6718-
intptr_t prefix_length,
6719-
const String& accessor_name) {
6720-
intptr_t name_len = name.Length();
6721-
intptr_t accessor_name_len = accessor_name.Length();
6722-
6723-
if (name_len != (accessor_name_len + prefix_length)) {
6724-
return false;
6725-
}
6726-
for (intptr_t i = 0; i < prefix_length; i++) {
6727-
if (name.CharAt(i) != prefix[i]) {
6728-
return false;
6729-
}
6730-
}
6731-
for (intptr_t i = 0, j = prefix_length; i < accessor_name_len; i++, j++) {
6732-
if (name.CharAt(j) != accessor_name.CharAt(i)) {
6733-
return false;
6734-
}
6735-
}
6736-
return true;
6692+
FunctionPtr Class::LookupFunctionReadLocked(const String& name) const {
6693+
return LookupFunctionReadLocked(name, kAny);
67376694
}
67386695

67396696
FunctionPtr Class::CheckFunctionType(const Function& func, MemberKind kind) {
@@ -6845,42 +6802,6 @@ FunctionPtr Class::LookupFunctionAllowPrivate(const String& name,
68456802
return Function::null();
68466803
}
68476804

6848-
FunctionPtr Class::LookupGetterFunction(const String& name) const {
6849-
return LookupAccessorFunction(kGetterPrefix, kGetterPrefixLength, name);
6850-
}
6851-
6852-
FunctionPtr Class::LookupSetterFunction(const String& name) const {
6853-
return LookupAccessorFunction(kSetterPrefix, kSetterPrefixLength, name);
6854-
}
6855-
6856-
FunctionPtr Class::LookupAccessorFunction(const char* prefix,
6857-
intptr_t prefix_length,
6858-
const String& name) const {
6859-
ASSERT(!IsNull());
6860-
Thread* thread = Thread::Current();
6861-
if (EnsureIsFinalized(thread) != Error::null()) {
6862-
return Function::null();
6863-
}
6864-
REUSABLE_ARRAY_HANDLESCOPE(thread);
6865-
REUSABLE_FUNCTION_HANDLESCOPE(thread);
6866-
REUSABLE_STRING_HANDLESCOPE(thread);
6867-
Array& funcs = thread->ArrayHandle();
6868-
funcs = current_functions();
6869-
intptr_t len = funcs.Length();
6870-
Function& function = thread->FunctionHandle();
6871-
String& function_name = thread->StringHandle();
6872-
for (intptr_t i = 0; i < len; i++) {
6873-
function ^= funcs.At(i);
6874-
function_name = function.name();
6875-
if (MatchesAccessorName(function_name, prefix, prefix_length, name)) {
6876-
return function.ptr();
6877-
}
6878-
}
6879-
6880-
// No function found.
6881-
return Function::null();
6882-
}
6883-
68846805
FieldPtr Class::LookupInstanceField(const String& name) const {
68856806
return LookupField(name, kInstance);
68866807
}

runtime/vm/object.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,19 +1717,17 @@ class Class : public Object {
17171717
intptr_t FindImplicitClosureFunctionIndex(const Function& needle) const;
17181718
FunctionPtr ImplicitClosureFunctionFromIndex(intptr_t idx) const;
17191719

1720+
FunctionPtr LookupFunction(const String& name) const;
17201721
FunctionPtr LookupFunctionReadLocked(const String& name) const;
17211722
FunctionPtr LookupDynamicFunctionUnsafe(const String& name) const;
17221723

1723-
FunctionPtr LookupDynamicFunctionAllowPrivate(const String& name) const;
17241724
FunctionPtr LookupStaticFunction(const String& name) const;
17251725
FunctionPtr LookupStaticFunctionAllowPrivate(const String& name) const;
17261726
FunctionPtr LookupConstructor(const String& name) const;
17271727
FunctionPtr LookupConstructorAllowPrivate(const String& name) const;
17281728
FunctionPtr LookupFactory(const String& name) const;
17291729
FunctionPtr LookupFactoryAllowPrivate(const String& name) const;
17301730
FunctionPtr LookupFunctionAllowPrivate(const String& name) const;
1731-
FunctionPtr LookupGetterFunction(const String& name) const;
1732-
FunctionPtr LookupSetterFunction(const String& name) const;
17331731
FieldPtr LookupInstanceField(const String& name) const;
17341732
FieldPtr LookupStaticField(const String& name) const;
17351733
FieldPtr LookupField(const String& name) const;
@@ -2248,10 +2246,6 @@ class Class : public Object {
22482246
MemberKind kind) const;
22492247
FieldPtr LookupField(const String& name, MemberKind kind) const;
22502248

2251-
FunctionPtr LookupAccessorFunction(const char* prefix,
2252-
intptr_t prefix_length,
2253-
const String& name) const;
2254-
22552249
// Allocate an instance class which has a VM implementation.
22562250
template <class FakeInstance, class TargetFakeInstance>
22572251
static ClassPtr New(intptr_t id,
@@ -10599,8 +10593,6 @@ class String : public Instance {
1059910593
static StringPtr ToLowerCase(const String& str,
1060010594
Heap::Space space = Heap::kNew);
1060110595

10602-
static StringPtr RemovePrivateKey(const String& name);
10603-
1060410596
static const char* ScrubName(const String& name, bool is_extension = false);
1060510597
static StringPtr ScrubNameRetainPrivate(const String& name,
1060610598
bool is_extension = false);

runtime/vm/resolver.cc

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -157,15 +157,6 @@ FunctionPtr Resolver::ResolveDynamicForReceiverClass(
157157
std::mem_fn(&Class::LookupDynamicFunctionUnsafe));
158158
}
159159

160-
FunctionPtr Resolver::ResolveDynamicForReceiverClassAllowPrivate(
161-
const Class& receiver_class,
162-
const String& function_name,
163-
const ArgumentsDescriptor& args_desc) {
164-
return ResolveDynamicForReceiverClassWithCustomLookup(
165-
receiver_class, function_name, args_desc, /*allow_add=*/false,
166-
std::mem_fn(&Class::LookupDynamicFunctionAllowPrivate));
167-
}
168-
169160
FunctionPtr Resolver::ResolveFunction(Zone* zone,
170161
const Class& receiver_class,
171162
const String& function_name) {

0 commit comments

Comments
 (0)