[vm] Exclude class name from function name in instruction sizes json.

Issue https://github.com/dart-lang/sdk/issues/41249

Cq-Include-Trybots: luci.dart.try:pkg-linux-debug-try,pkg-linux-release-try,pkg-win-release-try,pkg-mac-release-try
Change-Id: Idf2bb9c9d6392c7a95aa09a2cc1f2190adcf782d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/150522
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Vyacheslav Egorov 2020-06-10 10:18:37 +00:00 committed by commit-bot@chromium.org
parent f40875bf1b
commit 45310394a6
7 changed files with 103 additions and 68 deletions

View file

@ -97,11 +97,12 @@ void main(List<String> args) {
reason: 'Sizes file is non-empty');
// Check for duplicated symbols (using both raw and scrubbed names).
final symbolRawNamesByLibrary = Map<String, Set<String>>();
final symbolScrubbedNamesByLibrary = Map<String, Set<String>>();
// Maps below contain mappings library-uri -> class-name -> names.
final symbolRawNames = <String, Map<String, Set<String>>>{};
final symbolScrubbedNames = <String, Map<String, Set<String>>>{};
Set<String> getSetOfNames(
Map<String, Set<String>> map, String libraryUri) {
Set<String> getSetOfNames(Map<String, Map<String, Set<String>>> map,
String libraryUri, String className) {
// For file uris make sure to canonicalize the path. This prevents
// issues with mismatching case on Windows which has case insensitive
// file system.
@ -112,48 +113,60 @@ void main(List<String> args) {
Uri.file(path.canonicalize(uri.toFilePath())).toString();
}
}
return map.putIfAbsent(libraryUri ?? '', () => {});
return map
.putIfAbsent(libraryUri ?? '', () => {})
.putIfAbsent(className ?? '', () => {});
}
for (var sym in symbols) {
expect(
getSetOfNames(symbolRawNamesByLibrary, sym.libraryUri)
getSetOfNames(symbolRawNames, sym.libraryUri, sym.className)
.add(sym.name.raw),
isTrue,
reason:
'All symbols should have unique names (within libraries): ${sym.name.raw}');
expect(
getSetOfNames(symbolScrubbedNamesByLibrary, sym.libraryUri)
getSetOfNames(symbolScrubbedNames, sym.libraryUri, sym.className)
.add(sym.name.scrubbed),
isTrue,
reason: 'Scrubbing the name should not make it non-unique');
}
// Check for expected names which should appear in the output.
final inputDartSymbolNames = symbolScrubbedNamesByLibrary[
final inputDartSymbolNames = symbolScrubbedNames[
Uri.file(path.canonicalize(inputDart)).toString()];
expect(inputDartSymbolNames, isNotNull,
reason: 'Symbols from input.dart are included into sizes output');
expect(inputDartSymbolNames, contains('makeSomeClosures'));
final closures = inputDartSymbolNames.where(
expect(inputDartSymbolNames[''], isNotNull,
reason: 'Should include top-level members from input.dart');
expect(inputDartSymbolNames[''], contains('makeSomeClosures'));
final closures = inputDartSymbolNames[''].where(
(name) => name.startsWith('makeSomeClosures.<anonymous closure'));
expect(closures.length, 3);
expect(inputDartSymbolNames, contains('A.tornOff'));
expect(inputDartSymbolNames, contains('[tear-off] A.tornOff'));
expect(inputDartSymbolNames,
contains('[tear-off-extractor] A.get:tornOff'));
expect(inputDartSymbolNames, contains('B.tornOff'));
expect(inputDartSymbolNames, contains('[tear-off] B.tornOff'));
expect(inputDartSymbolNames,
contains('[tear-off-extractor] B.get:tornOff'));
expect(closures.length, 3,
reason: 'There are three closures inside makeSomeClosure');
expect(inputDartSymbolNames['A'], isNotNull,
reason: 'Should include class A members from input.dart');
expect(inputDartSymbolNames['A'], contains('tornOff'));
expect(inputDartSymbolNames['A'], contains('[tear-off] tornOff'));
expect(inputDartSymbolNames['A'],
contains('[tear-off-extractor] get:tornOff'));
expect(inputDartSymbolNames['B'], isNotNull,
reason: 'Should include class B members from input.dart');
expect(inputDartSymbolNames['B'], contains('tornOff'));
expect(inputDartSymbolNames['B'], contains('[tear-off] tornOff'));
expect(inputDartSymbolNames['B'],
contains('[tear-off-extractor] get:tornOff'));
// Presence of async modifier should not cause tear-off name to end
// with {body}.
expect(inputDartSymbolNames, contains('[tear-off] C.tornOff'));
expect(inputDartSymbolNames['C'], contains('[tear-off] tornOff'));
// Check that output does not contain '[unknown stub]'
expect(symbolRawNamesByLibrary[''], isNot(contains('[unknown stub]')));
expect(symbolRawNames[''][''], isNot(contains('[unknown stub]')),
reason: 'All stubs must be named');
});
});
});

View file

@ -417,10 +417,11 @@ void Disassembler::DisassembleCodeHelper(const char* function_fullname,
} else if (function.IsNull()) {
cls ^= code.owner();
if (cls.IsNull()) {
THR_Print(" 0x%" Px ": %s, (%s)%s\n", base + offset,
code.QualifiedName(Object::kScrubbedName,
Object::NameDisambiguation::kYes),
skind, s_entry_point);
THR_Print(
" 0x%" Px ": %s, (%s)%s\n", base + offset,
code.QualifiedName(NameFormattingParams(
Object::kScrubbedName, Object::NameDisambiguation::kYes)),
skind, s_entry_point);
} else {
THR_Print(" 0x%" Px ": allocation stub for %s, (%s)%s\n",
base + offset, cls.ToCString(), skind, s_entry_point);

View file

@ -337,9 +337,10 @@ void ImageWriter::DumpInstructionsSizes() {
js.PrintPropertyStr("l", url);
js.PrintPropertyStr("c", name);
}
js.PrintProperty(
"n", data.code_->QualifiedName(Object::kInternalName,
Object::NameDisambiguation::kYes));
js.PrintProperty("n",
data.code_->QualifiedName(
NameFormattingParams::DisambiguatedWithoutClassName(
Object::kInternalName)));
js.PrintProperty("s", SizeInSnapshot(data.insns_->raw()));
js.CloseObject();
}

View file

@ -8839,27 +8839,24 @@ StringPtr Function::UserVisibleName() const {
StringPtr Function::QualifiedScrubbedName() const {
Thread* thread = Thread::Current();
ZoneTextBuffer printer(thread->zone());
PrintQualifiedName(kScrubbedName, &printer);
PrintQualifiedName(NameFormattingParams(kScrubbedName), &printer);
return Symbols::New(thread, printer.buffer());
}
StringPtr Function::QualifiedUserVisibleName() const {
Thread* thread = Thread::Current();
ZoneTextBuffer printer(thread->zone());
PrintQualifiedName(kUserVisibleName, &printer);
PrintQualifiedName(NameFormattingParams(kUserVisibleName), &printer);
return Symbols::New(thread, printer.buffer());
}
void Function::PrintQualifiedName(
NameVisibility name_visibility,
ZoneTextBuffer* printer,
NameDisambiguation name_disambiguation /* = NameDisambiguation::kNo */)
const {
void Function::PrintQualifiedName(const NameFormattingParams& params,
ZoneTextBuffer* printer) const {
// If |this| is the generated asynchronous body closure, use the
// name of the parent function.
Function& fun = Function::Handle(raw());
if (name_disambiguation == NameDisambiguation::kYes) {
if (params.disambiguate_names) {
if (fun.IsInvokeFieldDispatcher()) {
printer->AddString("[invoke-field] ");
}
@ -8891,50 +8888,49 @@ void Function::PrintQualifiedName(
// the parent.
parent = parent.parent_function();
}
parent.PrintQualifiedName(name_visibility, printer, name_disambiguation);
parent.PrintQualifiedName(params, printer);
// A function's scrubbed name and its user visible name are identical.
printer->AddString(".");
if (name_disambiguation == NameDisambiguation::kYes &&
if (params.disambiguate_names &&
fun.name() == Symbols::AnonymousClosure().raw()) {
printer->Printf("<anonymous closure @%" Pd ">", fun.token_pos().Pos());
} else {
printer->AddString(fun.NameCString(name_visibility));
printer->AddString(fun.NameCString(params.name_visibility));
}
// If we skipped rewritten async/async*/sync* body then append a suffix
// to the end of the name.
if (fun.raw() != raw() &&
name_disambiguation == NameDisambiguation::kYes) {
if (fun.raw() != raw() && params.disambiguate_names) {
printer->AddString("{body}");
}
return;
}
}
const Class& cls = Class::Handle(Owner());
if (!cls.IsTopLevel()) {
if (fun.kind() == FunctionLayout::kConstructor) {
printer->AddString("new ");
} else {
if (fun.kind() == FunctionLayout::kConstructor) {
printer->AddString("new ");
} else if (params.include_class_name) {
const Class& cls = Class::Handle(Owner());
if (!cls.IsTopLevel()) {
const Class& mixin = Class::Handle(cls.Mixin());
printer->AddString(name_visibility == kUserVisibleName
printer->AddString(params.name_visibility == kUserVisibleName
? mixin.UserVisibleNameCString()
: cls.NameCString(name_visibility));
: cls.NameCString(params.name_visibility));
printer->AddString(".");
}
}
printer->AddString(fun.NameCString(name_visibility));
printer->AddString(fun.NameCString(params.name_visibility));
// If we skipped rewritten async/async*/sync* body then append a suffix
// to the end of the name.
if (fun.raw() != raw() && name_disambiguation == NameDisambiguation::kYes) {
if (fun.raw() != raw() && params.disambiguate_names) {
printer->AddString("{body}");
}
// Field dispatchers are specialized for an argument descriptor so there
// might be multiples of them with the same name but different argument
// descriptors. Add a suffix to disambiguate.
if (name_disambiguation == NameDisambiguation::kYes &&
fun.IsInvokeFieldDispatcher()) {
if (params.disambiguate_names && fun.IsInvokeFieldDispatcher()) {
printer->AddString(" ");
if (NumTypeParameters() != 0) {
printer->Printf("<%" Pd ">", fun.NumTypeParameters());
@ -16229,7 +16225,8 @@ intptr_t Code::GetDeoptIdForOsr(uword pc) const {
const char* Code::ToCString() const {
return OS::SCreate(Thread::Current()->zone(), "Code(%s)",
QualifiedName(kScrubbedName, NameDisambiguation::kYes));
QualifiedName(NameFormattingParams(
kScrubbedName, NameDisambiguation::kYes)));
}
const char* Code::Name() const {
@ -16266,16 +16263,14 @@ const char* Code::Name() const {
}
}
const char* Code::QualifiedName(NameVisibility name_visibility,
NameDisambiguation name_disambiguation) const {
const char* Code::QualifiedName(const NameFormattingParams& params) const {
Zone* zone = Thread::Current()->zone();
const Object& obj =
Object::Handle(zone, WeakSerializationReference::UnwrapIfTarget(owner()));
if (obj.IsFunction()) {
ZoneTextBuffer printer(zone);
printer.AddString(is_optimized() ? "[Optimized] " : "[Unoptimized] ");
Function::Cast(obj).PrintQualifiedName(name_visibility, &printer,
name_disambiguation);
Function::Cast(obj).PrintQualifiedName(params, &printer);
return printer.buffer();
}
return Name();
@ -18745,7 +18740,9 @@ void AbstractType::PrintName(
} else if (param.parameterized_function() != Function::null()) {
const Function& func =
Function::Handle(zone, param.parameterized_function());
func.PrintQualifiedName(name_visibility, printer, name_disambiguation);
func.PrintQualifiedName(
NameFormattingParams(name_visibility, name_disambiguation),
printer);
printer->AddString("::");
}
}

View file

@ -2427,6 +2427,32 @@ enum {
kAllFree = kMaxInt32,
};
// Formatting configuration for Function::PrintQualifiedName.
struct NameFormattingParams {
Object::NameVisibility name_visibility;
bool disambiguate_names;
// By default function name includes the name of the enclosing class if any.
// However in some context this information is redundant and class name
// is already known. In this case setting |include_class_name| to false
// allows you to exclude this information from the formatted name.
bool include_class_name = true;
NameFormattingParams(Object::NameVisibility visibility,
Object::NameDisambiguation name_disambiguation =
Object::NameDisambiguation::kNo)
: name_visibility(visibility),
disambiguate_names(name_disambiguation ==
Object::NameDisambiguation::kYes) {}
static NameFormattingParams DisambiguatedWithoutClassName(
Object::NameVisibility visibility) {
NameFormattingParams params(visibility, Object::NameDisambiguation::kYes);
params.include_class_name = false;
return params;
}
};
class Function : public Object {
public:
StringPtr name() const { return raw_ptr()->name_; }
@ -2435,10 +2461,8 @@ class Function : public Object {
const char* NameCString(NameVisibility name_visibility) const;
void PrintQualifiedName(
NameVisibility name_visibility,
ZoneTextBuffer* printer,
NameDisambiguation name_disambiguation = NameDisambiguation::kNo) const;
void PrintQualifiedName(const NameFormattingParams& params,
ZoneTextBuffer* printer) const;
StringPtr QualifiedScrubbedName() const;
StringPtr QualifiedUserVisibleName() const;
@ -6339,8 +6363,7 @@ class Code : public Object {
intptr_t GetDeoptIdForOsr(uword pc) const;
const char* Name() const;
const char* QualifiedName(NameVisibility name_visibility,
NameDisambiguation name_disambiguation) const;
const char* QualifiedName(const NameFormattingParams& params) const;
int64_t compile_timestamp() const {
#if defined(PRODUCT)

View file

@ -876,8 +876,8 @@ void Code::PrintJSONImpl(JSONStream* stream, bool ref) const {
AddCommonObjectProperties(&jsobj, "Code", ref);
jsobj.AddFixedServiceId("code/%" Px64 "-%" Px "", compile_timestamp(),
PayloadStart());
const char* qualified_name =
QualifiedName(kUserVisibleName, NameDisambiguation::kNo);
const char* qualified_name = QualifiedName(
NameFormattingParams(kUserVisibleName, NameDisambiguation::kNo));
const char* vm_name = Name();
AddNameProperties(&jsobj, qualified_name, vm_name);
const bool is_stub =

View file

@ -499,8 +499,8 @@ class AbstractCode {
const char* QualifiedName() const {
if (code_.IsCode()) {
return Code::Cast(code_).QualifiedName(Object::kUserVisibleName,
Object::NameDisambiguation::kNo);
return Code::Cast(code_).QualifiedName(
NameFormattingParams(Object::kUserVisibleName));
} else if (code_.IsBytecode()) {
return Bytecode::Cast(code_).QualifiedName();
} else {