flutter_flutter/runtime/dart_snapshot.h
Chinmay Garde 5bd7260a1e
Enable loading snapshots with sound null safety enabled. (#21820)
Snapshots compiled with sound null-safety enabled require changes to the way in
which isolates are launched. Specifically, the `Dart_IsolateFlags::null_safety`
field needs to be known upfront. The value of this field can only be determined
once the kernel snapshot is available. This poses a problem in the engine
because the engine used to launch the isolate at shell initialization and only
need the kernel mappings later at isolate launch (when transitioning the root
isolate to the `DartIsolate::Phase::Running` phase). This patch delays launch of
the isolate on the UI task runner till a kernel mapping is available. The side
effects of this delay (callers no longer having access to the non-running
isolate handle) have been addressed in this patch. The DartIsolate API has also
been amended to hide the method that could return a non-running isolate to the
caller.  Instead, it has been replaced with a method that requires a valid
isolate configuration that returns a running root isolate. The isolate will be
launched by asking the isolate configuration for its null-safety
characteristics.

A side effect of enabling null-safety is that Dart APIs that work with legacy
types will now terminate the process if used with an isolate that has sound
null-safety enabled. These APIs may no longer be used in the engine. This
primarily affects the Dart Convertors in Tonic that convert certain C++ objects
into the Dart counterparts. All known Dart Converters have been updated to
convert C++ objects to non-nullable Dart types inferred using type traits of the
corresponding C++ object. The few spots in the engine that used the old Dart
APIs directly have been manually updated. To ensure that no usage of the legacy
APIs remain in the engine (as these would cause runtime process terminations),
the legacy APIs were prefixed with the `DART_LEGACY_API` macro and the macro
defined to `[[deprecated]]` in all engine translation units. While the engine
now primarily works with non-nullable Dart types, callers can still use
`Dart_TypeToNonNullableType` to acquire nullable types for use directly or with
Tonic. One use case that is not addressed with the Tonic Dart Convertors is the
creation of non-nullable lists of nullable types. This hasn’t come up so far in
the engine.

A minor related change is reworking tonic to define a single library target.
This allows the various tonic subsystems to depend on one another. Primarily,
this is used to make the Dart convertors use the logging utilities. This now
allows errors to be more descriptive as the presence of error handles is caught
(and logged) earlier.

Fixes https://github.com/flutter/flutter/issues/59879
2020-10-16 14:53:26 -07:00

162 lines
7.1 KiB
C++

// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_RUNTIME_DART_SNAPSHOT_H_
#define FLUTTER_RUNTIME_DART_SNAPSHOT_H_
#include <memory>
#include <string>
#include "flutter/common/settings.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/ref_counted.h"
namespace flutter {
//------------------------------------------------------------------------------
/// @brief A read-only Dart heap snapshot, or, read-executable mapping of
/// AOT compiled Dart code.
///
/// To make Dart code startup more performant, the Flutter tools on
/// the host snapshot the state of the Dart heap at specific points
/// and package the same with the Flutter application. When the Dart
/// VM on the target is configured to run AOT compiled Dart code,
/// the tools also compile the developer's Flutter application code
/// to target specific machine code (instructions). This class deals
/// with the mapping of both these buffers at runtime on the target.
///
/// A Flutter application typically needs two instances of this
/// class at runtime to run Dart code. One instance is for the VM
/// and is called the "core snapshot". The other is the isolate
/// and called the "isolate snapshot". Different root isolates can
/// be launched with different isolate snapshots.
///
/// These snapshots are typically memory-mapped at runtime, or,
/// referenced directly as symbols present in Mach or ELF binaries.
///
/// In the case of the core snapshot, the snapshot is collected when
/// the VM shuts down. The isolate snapshot is collected when the
/// isolate group shuts down.
///
class DartSnapshot : public fml::RefCountedThreadSafe<DartSnapshot> {
public:
//----------------------------------------------------------------------------
/// The symbol name of the heap data of the core snapshot in a dynamic library
/// or currently loaded process.
///
static const char* kVMDataSymbol;
//----------------------------------------------------------------------------
/// The symbol name of the instructions data of the core snapshot in a dynamic
/// library or currently loaded process.
///
static const char* kVMInstructionsSymbol;
//----------------------------------------------------------------------------
/// The symbol name of the heap data of the isolate snapshot in a dynamic
/// library or currently loaded process.
///
static const char* kIsolateDataSymbol;
//----------------------------------------------------------------------------
/// The symbol name of the instructions data of the isolate snapshot in a
/// dynamic library or currently loaded process.
///
static const char* kIsolateInstructionsSymbol;
//----------------------------------------------------------------------------
/// @brief From the fields present in the given settings object, infer
/// the core snapshot.
///
/// @attention Depending on the runtime mode of the Flutter application and
/// the target that Flutter is running on, a complex fallback
/// mechanism is in place to infer the locations of each snapshot
/// buffer. If the caller wants to explicitly specify the buffers
/// of the core snapshot, the `Settings::vm_snapshot_data` and
/// `Settings::vm_snapshots_instr` mapping fields may be used.
/// This specification takes precedence over all fallback search
/// paths.
///
/// @param[in] settings The settings to infer the core snapshot from.
///
/// @return A valid core snapshot or nullptr.
///
static fml::RefPtr<DartSnapshot> VMSnapshotFromSettings(
const Settings& settings);
//----------------------------------------------------------------------------
/// @brief From the fields present in the given settings object, infer
/// the isolate snapshot.
///
/// @attention Depending on the runtime mode of the Flutter application and
/// the target that Flutter is running on, a complex fallback
/// mechanism is in place to infer the locations of each snapshot
/// buffer. If the caller wants to explicitly specify the buffers
/// of the isolate snapshot, the `Settings::isolate_snapshot_data`
/// and `Settings::isolate_snapshots_instr` mapping fields may be
/// used. This specification takes precedence over all fallback
/// search paths.
///
/// @param[in] settings The settings to infer the isolate snapshot from.
///
/// @return A valid isolate snapshot or nullptr.
///
static fml::RefPtr<DartSnapshot> IsolateSnapshotFromSettings(
const Settings& settings);
//----------------------------------------------------------------------------
/// @brief Determines if this snapshot contains a heap component. Since
/// the instructions component is optional, the method does not
/// check for its presence. Use `IsValidForAOT` to determine if
/// both the heap and instructions components of the snapshot are
/// present.
///
/// @return Returns if the snapshot contains a heap component.
///
bool IsValid() const;
//----------------------------------------------------------------------------
/// @brief Determines if this snapshot contains both the heap and
/// instructions components. This is only useful when determining
/// if the snapshot may be used to run AOT code. The instructions
/// component will be absent in JIT modes.
///
/// @return Returns if the snapshot contains both a heap and instructions
/// component.
///
bool IsValidForAOT() const;
//----------------------------------------------------------------------------
/// @brief Get a pointer to the read-only mapping to the heap snapshot.
///
/// @return The data mapping.
///
const uint8_t* GetDataMapping() const;
//----------------------------------------------------------------------------
/// @brief Get a pointer to the read-execute mapping to the instructions
/// snapshot.
///
/// @return The instructions mapping.
///
const uint8_t* GetInstructionsMapping() const;
bool IsNullSafetyEnabled(
const fml::Mapping* application_kernel_mapping) const;
private:
std::shared_ptr<const fml::Mapping> data_;
std::shared_ptr<const fml::Mapping> instructions_;
DartSnapshot(std::shared_ptr<const fml::Mapping> data,
std::shared_ptr<const fml::Mapping> instructions);
~DartSnapshot();
FML_FRIEND_REF_COUNTED_THREAD_SAFE(DartSnapshot);
FML_FRIEND_MAKE_REF_COUNTED(DartSnapshot);
FML_DISALLOW_COPY_AND_ASSIGN(DartSnapshot);
};
} // namespace flutter
#endif // FLUTTER_RUNTIME_DART_SNAPSHOT_H_