dart-sdk/runtime/bin/isolate_data.h
Ryan Macnak c5a94db091 [vm] Initial implementation of deferred loading.
(Assignment of libraries to loading units is already done in the kernel generation step.)

After compiling and before serializing, we walk the program and for each Code we assign its Instructions, CodeSourceMap and CompressedStackMap to the loading unit of that Code's defining library. Deduplication may cause Instructions, CodeSourceMaps and CompressedStackMaps to belong to more than one loading unit; in this case the objects are assigned to the root loading unit. Later they can be more precisely assigned to the dominating loading unit.

All objects except some Instructions, CodeSourceMaps and CompressedStackMaps belong to the root loading unit's snapshot. This snapshot is written like an unsplit snapshot, except that when serializing Code, we will write a reference to a stub or null when the Code's Instructions, CodeSourceMap or CompressedStackMap belongs to a non-root loading unit. The snapshots of non-root loading units contain these deferred objects and references to the corresponding Code objects to patch. The types of objects we defer (Instructions, CodeSourceMaps and CompressedStackMaps) usually represent 70+% of the snapshot size.

Bare instructions mode must be disabled when splitting because we cannot have PC-relative calls between loading units. Later we can re-enable this for calls within loading units.

Broken: Compactor probably crashes we can now have an unbounded number of image pages and the compactor assumes a fixed number.

Embedder's guide:

At compile-time, gen_snapshot should be passed --loading_unit_manifest with a path, which will enable splitting and output a mapping from loading unit ids to snapshot output paths.

At runtime, sometime during isolate startup, an embedder should call Dart_SetDeferredLoadHandler, probably near an existing call to Dart_SetLibraryTagHandler. The callback is given a loading unit id, and should eventually call Dart_DeferredLoadComplete[Error].

Bug: https://github.com/dart-lang/sdk/issues/41974
Change-Id: Ib597eb87c8cd634416d5ee1f00629c5550aebb00
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/152427
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2020-07-17 19:29:47 +00:00

163 lines
4.8 KiB
C++

// Copyright (c) 2012, 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_BIN_ISOLATE_DATA_H_
#define RUNTIME_BIN_ISOLATE_DATA_H_
#include <memory>
#include <utility>
#include "include/dart_api.h"
#include "platform/assert.h"
#include "platform/globals.h"
#include "platform/growable_array.h"
#include "platform/utils.h"
namespace dart {
// Forward declaration.
template <typename T>
class MallocGrowableArray;
} // namespace dart
namespace dart {
namespace bin {
// Forward declaration.
class AppSnapshot;
class EventHandler;
class Loader;
// Data associated with every isolate group in the standalone VM
// embedding. This is used to free external resources for each isolate
// group when the isolate group shuts down.
class IsolateGroupData {
public:
IsolateGroupData(const char* url,
const char* packages_file,
AppSnapshot* app_snapshot,
bool isolate_run_app_snapshot);
~IsolateGroupData();
char* script_url;
const std::shared_ptr<uint8_t>& kernel_buffer() const {
return kernel_buffer_;
}
intptr_t kernel_buffer_size() const { return kernel_buffer_size_; }
// Associate the given kernel buffer with this IsolateGroupData without
// giving it ownership of the buffer.
void SetKernelBufferUnowned(uint8_t* buffer, intptr_t size) {
ASSERT(kernel_buffer_.get() == NULL);
kernel_buffer_ = std::shared_ptr<uint8_t>(buffer, FreeUnownedKernelBuffer);
kernel_buffer_size_ = size;
}
// Associate the given kernel buffer with this IsolateGroupData and give it
// ownership of the buffer. This IsolateGroupData is the first one to own the
// buffer.
void SetKernelBufferNewlyOwned(uint8_t* buffer, intptr_t size) {
ASSERT(kernel_buffer_.get() == NULL);
kernel_buffer_ = std::shared_ptr<uint8_t>(buffer, free);
kernel_buffer_size_ = size;
}
// Associate the given kernel buffer with this IsolateGroupData and give it
// ownership of the buffer. The buffer is already owned by another
// IsolateGroupData.
void SetKernelBufferAlreadyOwned(std::shared_ptr<uint8_t> buffer,
intptr_t size) {
ASSERT(kernel_buffer_.get() == NULL);
kernel_buffer_ = std::move(buffer);
kernel_buffer_size_ = size;
}
const char* resolved_packages_config() const {
return resolved_packages_config_;
}
void set_resolved_packages_config(const char* packages_config) {
if (resolved_packages_config_ != NULL) {
free(resolved_packages_config_);
resolved_packages_config_ = NULL;
}
resolved_packages_config_ = Utils::StrDup(packages_config);
}
bool RunFromAppSnapshot() const {
// If the main isolate is using an app snapshot the [app_snapshot_] pointer
// will be still nullptr (see main.cc:CreateIsolateGroupAndSetupHelper)
//
// Because of thus we have an additional boolean signaling whether the
// isolate was started from an app snapshot.
return app_snapshot_ != nullptr || isolate_run_app_snapshot_;
}
void AddLoadingUnit(AppSnapshot* loading_unit) {
loading_units_.Add(loading_unit);
}
private:
friend class IsolateData; // For packages_file_
std::unique_ptr<AppSnapshot> app_snapshot_;
MallocGrowableArray<AppSnapshot*> loading_units_;
char* resolved_packages_config_;
std::shared_ptr<uint8_t> kernel_buffer_;
intptr_t kernel_buffer_size_;
char* packages_file_ = nullptr;
bool isolate_run_app_snapshot_;
static void FreeUnownedKernelBuffer(uint8_t*) {}
DISALLOW_COPY_AND_ASSIGN(IsolateGroupData);
};
// Data associated with every isolate in the standalone VM
// embedding. This is used to free external resources for each isolate
// when the isolate shuts down.
class IsolateData {
public:
explicit IsolateData(IsolateGroupData* isolate_group_data);
~IsolateData();
IsolateGroupData* isolate_group_data() const { return isolate_group_data_; }
void UpdatePackagesFile(const char* packages_file) {
if (packages_file != nullptr) {
free(packages_file_);
packages_file_ = nullptr;
}
packages_file_ = Utils::StrDup(packages_file);
}
// While loading a loader is associated with the isolate.
bool HasLoader() const { return loader_ != NULL; }
Loader* loader() const {
ASSERT(loader_ != NULL);
return loader_;
}
void set_loader(Loader* loader) {
ASSERT((loader_ == NULL) || (loader == NULL));
loader_ = loader;
}
const char* packages_file() const { return packages_file_; }
private:
IsolateGroupData* isolate_group_data_;
Loader* loader_;
char* packages_file_;
DISALLOW_COPY_AND_ASSIGN(IsolateData);
};
} // namespace bin
} // namespace dart
#endif // RUNTIME_BIN_ISOLATE_DATA_H_