17f62d3f3a
Before, use of a function in the static calls table of a Code object would cause it to be retained. Now, like dispatch table use, we only retain such functions if there are other uses like dynamic function lookup that needs the function object or if the --retain-function-objects flag is enabled. In most modes, --retain-function-objects is enabled by default. It is only disabled by default in product mode when --dwarf-stack-traces is enabled, since otherwise the removed function objects may be needed for debugging platforms like the Observatory or when creating symbolic stack traces. Changes on flutter gallery in release mode: Default: arm7: isolate: +6.65%, total: +1.30% arm8: isolate: +6.67%, total: +1.28% (The increase is due to changing back to all function objects being retained as the default when using symbolic stack traces.) With --no-retain-function-objects: arm7: isolate: -9.95%, total: -1.73% arm8: isolate: -10.04%, total: -1.77% (This measures how much dropping static call function objects when possible affects the size compared to just dropping function objects for dispatch table entries when possible.) Bug: https://github.com/dart-lang/sdk/issues/41052 Change-Id: I3c834b14b0c58ccfdbaca3f154df536df29c13ef Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-linux-product-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/142146 Commit-Queue: Tess Strickland <sstrickl@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
121 lines
4.4 KiB
C++
121 lines
4.4 KiB
C++
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#ifndef RUNTIME_VM_PROGRAM_VISITOR_H_
|
|
#define RUNTIME_VM_PROGRAM_VISITOR_H_
|
|
|
|
#include "vm/allocation.h"
|
|
|
|
namespace dart {
|
|
|
|
// Currently, we have three types of abstract visitors that can be extended and
|
|
// used for program walking:
|
|
//
|
|
// * ClassVisitor, a visitor for classes in the program.
|
|
// * FunctionVisitor, a visitor for functions in the program.
|
|
// * CodeVisitor, a visitor for code objects in the program.
|
|
//
|
|
// To find the functions in a program, we must traverse the classes in the
|
|
// program, and similarly for code objects and functions. Thus, each
|
|
// FunctionVisitor is also a ClassVisitor, and each CodeVisitor is also a
|
|
// FunctionVisitor (and thus a ClassVisitor).
|
|
//
|
|
// Only the most specific visitor method is abstract. Derived visitors have a
|
|
// default empty implementation for base visitor methods to limit boilerplate
|
|
// needed when extending. For example, subclasses of CodeVisitor that only do
|
|
// per-Code work do not need to add empty implementations for VisitClass and
|
|
// VisitFunction.
|
|
//
|
|
// There are no guarantees for the order in which objects of a given type will
|
|
// be visited, but each object will be visited only once. In addition, each
|
|
// object is visited before any visitable sub-objects it contains. For example,
|
|
// this means a FunctionVisitor with a VisitClass implementation that drops
|
|
// methods from a class will not visit the dropped methods unless they are also
|
|
// found via another source of function objects.
|
|
//
|
|
// Note that WalkProgram only visits objects in the isolate heap. Deduplicating
|
|
// visitors that want to use VM objects as canonical when possible should
|
|
// instead add the appropriate VM objects first in their constructor.
|
|
|
|
class Class;
|
|
class Code;
|
|
class Function;
|
|
|
|
class CodeVisitor;
|
|
class FunctionVisitor;
|
|
|
|
class ClassVisitor : public ValueObject {
|
|
public:
|
|
virtual ~ClassVisitor() {}
|
|
|
|
virtual bool IsFunctionVisitor() const { return false; }
|
|
const FunctionVisitor* AsFunctionVisitor() const {
|
|
return const_cast<FunctionVisitor*>(
|
|
const_cast<ClassVisitor*>(this)->AsFunctionVisitor());
|
|
}
|
|
FunctionVisitor* AsFunctionVisitor() {
|
|
if (!IsFunctionVisitor()) return nullptr;
|
|
return reinterpret_cast<FunctionVisitor*>(this);
|
|
}
|
|
|
|
virtual bool IsCodeVisitor() const { return false; }
|
|
const CodeVisitor* AsCodeVisitor() const {
|
|
return const_cast<CodeVisitor*>(
|
|
const_cast<ClassVisitor*>(this)->AsCodeVisitor());
|
|
}
|
|
CodeVisitor* AsCodeVisitor() {
|
|
if (!IsCodeVisitor()) return nullptr;
|
|
return reinterpret_cast<CodeVisitor*>(this);
|
|
}
|
|
|
|
virtual void VisitClass(const Class& cls) = 0;
|
|
};
|
|
|
|
class FunctionVisitor : public ClassVisitor {
|
|
public:
|
|
bool IsFunctionVisitor() const { return true; }
|
|
virtual void VisitClass(const Class& cls) {}
|
|
virtual void VisitFunction(const Function& function) = 0;
|
|
};
|
|
|
|
class CodeVisitor : public FunctionVisitor {
|
|
public:
|
|
bool IsCodeVisitor() const { return true; }
|
|
virtual void VisitFunction(const Function& function) {}
|
|
virtual void VisitCode(const Code& code) = 0;
|
|
};
|
|
|
|
class Thread;
|
|
class Isolate;
|
|
|
|
class ProgramVisitor : public AllStatic {
|
|
public:
|
|
// Walks all non-null class, function, and code objects in the program as
|
|
// necessary for the given visitor.
|
|
static void WalkProgram(Zone* zone, Isolate* isolate, ClassVisitor* visitor);
|
|
|
|
static void Dedup(Thread* thread);
|
|
|
|
private:
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
static void BindStaticCalls(Zone* zone, Isolate* isolate);
|
|
static void ShareMegamorphicBuckets(Zone* zone, Isolate* isolate);
|
|
static void NormalizeAndDedupCompressedStackMaps(Zone* zone,
|
|
Isolate* isolate);
|
|
static void DedupPcDescriptors(Zone* zone, Isolate* isolate);
|
|
static void DedupDeoptEntries(Zone* zone, Isolate* isolate);
|
|
#if defined(DART_PRECOMPILER)
|
|
static void DedupCatchEntryMovesMaps(Zone* zone, Isolate* isolate);
|
|
static void DedupUnlinkedCalls(Zone* zone, Isolate* isolate);
|
|
#endif
|
|
static void DedupCodeSourceMaps(Zone* zone, Isolate* isolate);
|
|
static void DedupLists(Zone* zone, Isolate* isolate);
|
|
static void DedupInstructions(Zone* zone, Isolate* isolate);
|
|
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_PROGRAM_VISITOR_H_
|