dart-sdk/runtime/vm/dart_entry.h
Alexander Markov 5129cff930 [vm/aot] Discard Code objects from the heap
While deserializing AOT snapshot, Code objects which do not contain
valuable information besides entry point and stack maps are discarded
and not allocated on the heap (they are replaced with
StubCode::UnknownDartCode()).

PC -> Code/CompressedStackMaps lookup is implemented using a separate
table (InstructionsTable).

Flutter gallery in release-sizeopt mode:
Heap size of snapshot objects: arm -26.89%, arm64 -27.68%

Large Flutter application in release mode with --dwarf-stack-traces:
Heap size of snapshot objects: -24.3%.
Discarded Code objects: 72.5% of all Code objects.

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

TEST=existing tests; "--dwarf_stack_traces --no-retain_function_objects
--no-retain_code_objects" mode is enabled for a few tests.

Change-Id: I5fe3e283630c8e8f4442319d5dcae38d174dd0d8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/189560
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2021-04-13 02:36:16 +00:00

305 lines
12 KiB
C++

// Copyright (c) 2011, 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_DART_ENTRY_H_
#define RUNTIME_VM_DART_ENTRY_H_
#include "vm/allocation.h"
#include "vm/growable_array.h"
#include "vm/object.h"
#include "vm/raw_object.h"
namespace dart {
// Forward declarations.
class Array;
class Closure;
class Function;
class Instance;
class Integer;
class Library;
class Object;
class String;
// An arguments descriptor array consists of the type argument vector length (0
// if none); total argument count (not counting type argument vector); total
// arguments size (not counting type argument vector); the positional argument
// count; a sequence of (name, position) pairs, sorted by name, for each named
// optional argument; and a terminating null to simplify iterating in generated
// code.
class ArgumentsDescriptor : public ValueObject {
public:
explicit ArgumentsDescriptor(const Array& array);
// Accessors.
intptr_t TypeArgsLen() const; // 0 if no type argument vector is passed.
intptr_t FirstArgIndex() const { return TypeArgsLen() > 0 ? 1 : 0; }
intptr_t CountWithTypeArgs() const { return FirstArgIndex() + Count(); }
intptr_t Count() const; // Excluding type arguments vector.
intptr_t Size() const; // Excluding type arguments vector.
intptr_t SizeWithTypeArgs() const { return FirstArgIndex() + Size(); }
intptr_t PositionalCount() const; // Excluding type arguments vector.
intptr_t NamedCount() const { return Count() - PositionalCount(); }
StringPtr NameAt(intptr_t i) const;
intptr_t PositionAt(intptr_t i) const;
bool MatchesNameAt(intptr_t i, const String& other) const;
// Returns array of argument names in the arguments order.
ArrayPtr GetArgumentNames() const;
void PrintTo(BaseTextBuffer* buffer, bool show_named_positions = false) const;
const char* ToCString() const;
// Generated code support.
static intptr_t type_args_len_offset() {
return Array::element_offset(kTypeArgsLenIndex);
}
static intptr_t count_offset() { return Array::element_offset(kCountIndex); }
static intptr_t size_offset() { return Array::element_offset(kSizeIndex); }
static intptr_t positional_count_offset() {
return Array::element_offset(kPositionalCountIndex);
}
static intptr_t first_named_entry_offset() {
return Array::element_offset(kFirstNamedEntryIndex);
}
static intptr_t name_offset() { return kNameOffset * kWordSize; }
static intptr_t position_offset() { return kPositionOffset * kWordSize; }
static intptr_t named_entry_size() { return kNamedEntrySize * kWordSize; }
// Constructs an argument descriptor where all arguments are boxed and
// therefore number of parameters equals parameter size.
//
// Right now this is for example the case for all closure functions.
// Functions marked as entry-points may also be created by NewUnboxed because
// we rely that TFA will mark the arguments as nullable for such cases.
static ArrayPtr NewBoxed(intptr_t type_args_len,
intptr_t num_arguments,
const Array& optional_arguments_names,
Heap::Space space = Heap::kOld) {
return New(type_args_len, num_arguments, num_arguments,
optional_arguments_names, space);
}
// Allocate and return an arguments descriptor. The first
// (num_arguments - optional_arguments_names.Length()) arguments are
// positional and the remaining ones are named optional arguments.
// The presence of a type argument vector as first argument (not counted in
// num_arguments) is indicated by a non-zero type_args_len.
static ArrayPtr New(intptr_t type_args_len,
intptr_t num_arguments,
intptr_t size_arguments,
const Array& optional_arguments_names,
Heap::Space space = Heap::kOld);
// Constructs an argument descriptor where all arguments are boxed and
// therefore number of parameters equals parameter size.
//
// Right now this is for example the case for all closure functions.
static ArrayPtr NewBoxed(intptr_t type_args_len,
intptr_t num_arguments,
Heap::Space space = Heap::kOld) {
return New(type_args_len, num_arguments, num_arguments, space);
}
// Allocate and return an arguments descriptor that has no optional
// arguments. All arguments are positional. The presence of a type argument
// vector as first argument (not counted in num_arguments) is indicated
// by a non-zero type_args_len.
static ArrayPtr New(intptr_t type_args_len,
intptr_t num_arguments,
intptr_t size_arguments,
Heap::Space space = Heap::kOld);
// Initialize the preallocated fixed length arguments descriptors cache.
static void Init();
// Clear the preallocated fixed length arguments descriptors cache.
static void Cleanup();
enum { kCachedDescriptorCount = 32 };
private:
// Absolute indices into the array.
// Keep these in sync with the constants in invocation_mirror_patch.dart.
enum {
kTypeArgsLenIndex,
kCountIndex,
kSizeIndex,
kPositionalCountIndex,
kFirstNamedEntryIndex,
};
private:
// Relative indexes into each named argument entry.
enum {
kNameOffset,
// The least significant bit of the entry in 'kPositionOffset' (second
// least-significant after Smi-encoding) holds the strong-mode checking bit
// for the named argument.
kPositionOffset,
kNamedEntrySize,
};
public:
static intptr_t LengthFor(intptr_t num_named_arguments) {
// Add 1 for the terminating null.
return kFirstNamedEntryIndex + (kNamedEntrySize * num_named_arguments) + 1;
}
static ArrayPtr NewNonCached(intptr_t type_args_len,
intptr_t num_arguments,
intptr_t size_arguments,
bool canonicalize,
Heap::Space space);
// Used by Simulator to parse argument descriptors.
static intptr_t name_index(intptr_t index) {
return kFirstNamedEntryIndex + (index * kNamedEntrySize) + kNameOffset;
}
static intptr_t position_index(intptr_t index) {
return kFirstNamedEntryIndex + (index * kNamedEntrySize) + kPositionOffset;
}
const Array& array_;
// A cache of VM heap allocated arguments descriptors.
static ArrayPtr cached_args_descriptors_[kCachedDescriptorCount];
friend class SnapshotReader;
friend class SnapshotWriter;
friend class Serializer;
friend class Deserializer;
friend class Simulator;
friend class SimulatorHelpers;
DISALLOW_COPY_AND_ASSIGN(ArgumentsDescriptor);
};
// DartEntry abstracts functionality needed to resolve dart functions
// and invoke them from C++.
class DartEntry : public AllStatic {
public:
// Invokes the specified instance function or static function.
// The first argument of an instance function is the receiver.
// On success, returns an InstancePtr. On failure, an ErrorPtr.
// This is used when there is no type argument vector and
// no named arguments in the call.
static ObjectPtr InvokeFunction(const Function& function,
const Array& arguments);
// Invokes the specified code as if it was a Dart function.
// On success, returns an InstancePtr. On failure, an ErrorPtr.
static ObjectPtr InvokeCode(const Code& code,
uword entry_point,
const Array& arguments_descriptor,
const Array& arguments,
Thread* thread);
// Invokes the specified instance, static, or closure function.
// On success, returns an InstancePtr. On failure, an ErrorPtr.
static ObjectPtr InvokeFunction(
const Function& function,
const Array& arguments,
const Array& arguments_descriptor,
uword current_sp = OSThread::GetCurrentStackPointer());
// Invokes the first argument in the provided arguments array as a callable
// object, performing any needed dynamic checks if the callable cannot receive
// dynamic invocation.
//
// On success, returns an InstancePtr. On failure, an ErrorPtr.
//
// Used when an ArgumentsDescriptor is not required, that is, when there
// are no type arguments or named arguments.
static ObjectPtr InvokeClosure(Thread* thread, const Array& arguments);
// Invokes the first argument in the provided arguments array as a callable
// object, performing any needed dynamic checks if the callable cannot receive
// dynamic invocation.
//
// On success, returns an InstancePtr. On failure, an ErrorPtr.
static ObjectPtr InvokeClosure(Thread* thread,
const Array& arguments,
const Array& arguments_descriptor);
// Invokes the noSuchMethod instance function on the receiver.
// On success, returns an InstancePtr. On failure, an ErrorPtr.
static ObjectPtr InvokeNoSuchMethod(Thread* thread,
const Instance& receiver,
const String& target_name,
const Array& arguments,
const Array& arguments_descriptor);
private:
// Resolves the first argument in the provided arguments array to a callable
// compatible with the arguments. Helper method used within InvokeClosure.
//
// If no errors occur, the first argument is changed to be either the resolved
// callable or, if Function::null() is returned, an appropriate target for
// invoking noSuchMethod.
//
// On success, returns a FunctionPtr. On failure, an ErrorPtr.
static ObjectPtr ResolveCallable(Thread* thread,
const Array& arguments,
const Array& arguments_descriptor);
// Invokes a function returned by ResolveCallable, performing any dynamic
// checks needed if the function cannot receive dynamic invocation. Helper
// method used within InvokeClosure.
//
// On success, returns an InstancePtr. On failure, an ErrorPtr.
static ObjectPtr InvokeCallable(Thread* thread,
const Function& callable_function,
const Array& arguments,
const Array& arguments_descriptor);
};
// Utility functions to call from VM into Dart bootstrap libraries.
// Each may return an exception object.
class DartLibraryCalls : public AllStatic {
public:
// On success, returns an InstancePtr. On failure, an ErrorPtr.
static ObjectPtr InstanceCreate(const Library& library,
const String& exception_name,
const String& constructor_name,
const Array& arguments);
// On success, returns an InstancePtr. On failure, an ErrorPtr.
static ObjectPtr ToString(const Instance& receiver);
// On success, returns an InstancePtr. On failure, an ErrorPtr.
static ObjectPtr HashCode(const Instance& receiver);
// On success, returns an InstancePtr. On failure, an ErrorPtr.
static ObjectPtr Equals(const Instance& left, const Instance& right);
// On success, returns an InstancePtr. On failure, an ErrorPtr.
static ObjectPtr IdentityHashCode(const Instance& object);
// Returns the handler if one has been registered for this port id.
static ObjectPtr LookupHandler(Dart_Port port_id);
// Returns a list of open ReceivePorts.
static ObjectPtr LookupOpenPorts();
// Returns null on success, an ErrorPtr on failure.
static ObjectPtr HandleMessage(const Object& handler,
const Instance& dart_message);
// Returns null on success, an ErrorPtr on failure.
static ObjectPtr DrainMicrotaskQueue();
// Ensures that the isolate's _pendingImmediateCallback is set to
// _startMicrotaskLoop from dart:async.
// Returns null on success, an ErrorPtr on failure.
static ObjectPtr EnsureScheduleImmediate();
};
} // namespace dart
#endif // RUNTIME_VM_DART_ENTRY_H_