mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[vm/bytecode] Support library dependencies in bytecode for mirrors and vm-service.
Library dependencies are serialized in bytecode as extended annotations. Fixes the following tests with bytecode: co19_2/Language/Metadata/before_export_t01 co19_2/Language/Metadata/before_import_t01 service/library_dependency_test Change-Id: Idfbac6fcd56318d994d179864f0f5fd7d95089a9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/114928 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Régis Crelier <regis@google.com>
This commit is contained in:
parent
aa0af27497
commit
d7c944b4c0
|
@ -327,7 +327,7 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
|
|||
flags |= ClassDeclaration.hasSourcePositionsFlag;
|
||||
position = library.fileOffset;
|
||||
}
|
||||
Annotations annotations = getAnnotations(library.annotations);
|
||||
Annotations annotations = getLibraryAnnotations(library);
|
||||
if (annotations.object != null) {
|
||||
flags |= ClassDeclaration.hasAnnotationsFlag;
|
||||
if (annotations.hasPragma) {
|
||||
|
@ -420,6 +420,66 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
|
|||
return new Annotations(functionDecl, hasPragma);
|
||||
}
|
||||
|
||||
// Insert annotations for library and its dependencies into the
|
||||
// annotations section. Returns annotations for the library only.
|
||||
// Bytecode reader will implicitly find library dependencies by reading
|
||||
// an extra object after reading library annotations.
|
||||
Annotations getLibraryAnnotations(Library library) {
|
||||
Annotations annotations = getAnnotations(library.annotations);
|
||||
final bool emitDependencies =
|
||||
options.emitAnnotations && library.dependencies.isNotEmpty;
|
||||
if (annotations.object == null && !emitDependencies) {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
// We need to emit both annotations and dependencies objects, appending
|
||||
// null if an object is missing.
|
||||
if (annotations.object == null) {
|
||||
final annotationsDecl = new AnnotationsDeclaration(null);
|
||||
bytecodeComponent.annotations.add(annotationsDecl);
|
||||
annotations = new Annotations(annotationsDecl, false);
|
||||
}
|
||||
if (!emitDependencies) {
|
||||
bytecodeComponent.annotations.add(new AnnotationsDeclaration(null));
|
||||
return annotations;
|
||||
}
|
||||
|
||||
// Create a constant object representing library dependencies.
|
||||
// These objects are used by dart:mirrors and vm-service implementation.
|
||||
final deps = <Constant>[];
|
||||
for (var dependency in library.dependencies) {
|
||||
final prefix = dependency.name != null
|
||||
? StringConstant(dependency.name)
|
||||
: NullConstant();
|
||||
final showNames = dependency.combinators
|
||||
.where((c) => c.isShow)
|
||||
.expand((c) => c.names)
|
||||
.map((name) => StringConstant(name))
|
||||
.toList();
|
||||
final hideNames = dependency.combinators
|
||||
.where((c) => c.isHide)
|
||||
.expand((c) => c.names)
|
||||
.map((name) => StringConstant(name))
|
||||
.toList();
|
||||
final depAnnots = dependency.annotations.map(_getConstant).toList();
|
||||
deps.add(ListConstant(const DynamicType(), <Constant>[
|
||||
StringConstant(dependency.targetLibrary.importUri.toString()),
|
||||
BoolConstant(dependency.isExport),
|
||||
BoolConstant(dependency.isDeferred),
|
||||
prefix,
|
||||
ListConstant(const DynamicType(), showNames),
|
||||
ListConstant(const DynamicType(), hideNames),
|
||||
ListConstant(const DynamicType(), depAnnots),
|
||||
]));
|
||||
}
|
||||
final ObjectHandle dependenciesObject =
|
||||
objectTable.getHandle(ListConstant(const DynamicType(), deps));
|
||||
final dependenciesDecl = new AnnotationsDeclaration(dependenciesObject);
|
||||
bytecodeComponent.annotations.add(dependenciesDecl);
|
||||
|
||||
return annotations;
|
||||
}
|
||||
|
||||
FieldDeclaration getFieldDeclaration(Field field, Code initializer) {
|
||||
int flags = 0;
|
||||
Constant value;
|
||||
|
|
|
@ -366,11 +366,14 @@ static RawInstance* CreateCombinatorMirror(const Object& identifiers,
|
|||
|
||||
static RawInstance* CreateLibraryDependencyMirror(Thread* thread,
|
||||
const Instance& importer,
|
||||
const Namespace& ns,
|
||||
const Library& importee,
|
||||
const Array& show_names,
|
||||
const Array& hide_names,
|
||||
const Object& metadata,
|
||||
const LibraryPrefix& prefix,
|
||||
const String& prefix_name,
|
||||
const bool is_import,
|
||||
const bool is_deferred) {
|
||||
const Library& importee = Library::Handle(ns.library());
|
||||
const Instance& importee_mirror =
|
||||
Instance::Handle(CreateLibraryMirror(thread, importee));
|
||||
if (importee_mirror.IsNull()) {
|
||||
|
@ -378,8 +381,6 @@ static RawInstance* CreateLibraryDependencyMirror(Thread* thread,
|
|||
return Instance::null();
|
||||
}
|
||||
|
||||
const Array& show_names = Array::Handle(ns.show_names());
|
||||
const Array& hide_names = Array::Handle(ns.hide_names());
|
||||
intptr_t n = show_names.IsNull() ? 0 : show_names.Length();
|
||||
intptr_t m = hide_names.IsNull() ? 0 : hide_names.Length();
|
||||
const Array& combinators = Array::Handle(Array::New(n + m));
|
||||
|
@ -396,12 +397,6 @@ static RawInstance* CreateLibraryDependencyMirror(Thread* thread,
|
|||
combinators.SetAt(i++, t);
|
||||
}
|
||||
|
||||
Object& metadata = Object::Handle(ns.GetMetadata());
|
||||
if (metadata.IsError()) {
|
||||
Exceptions::PropagateError(Error::Cast(metadata));
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
const Array& args = Array::Handle(Array::New(7));
|
||||
args.SetAt(0, importer);
|
||||
if (importee.Loaded() || prefix.IsNull()) {
|
||||
|
@ -413,14 +408,109 @@ static RawInstance* CreateLibraryDependencyMirror(Thread* thread,
|
|||
args.SetAt(1, prefix);
|
||||
}
|
||||
args.SetAt(2, combinators);
|
||||
args.SetAt(3, prefix.IsNull() ? Object::null_object()
|
||||
: String::Handle(prefix.name()));
|
||||
args.SetAt(3, prefix_name);
|
||||
args.SetAt(4, Bool::Get(is_import));
|
||||
args.SetAt(5, Bool::Get(is_deferred));
|
||||
args.SetAt(6, metadata);
|
||||
return CreateMirror(Symbols::_LocalLibraryDependencyMirror(), args);
|
||||
}
|
||||
|
||||
static RawInstance* CreateLibraryDependencyMirror(Thread* thread,
|
||||
const Instance& importer,
|
||||
const Namespace& ns,
|
||||
const LibraryPrefix& prefix,
|
||||
const bool is_import,
|
||||
const bool is_deferred) {
|
||||
const Library& importee = Library::Handle(ns.library());
|
||||
const Array& show_names = Array::Handle(ns.show_names());
|
||||
const Array& hide_names = Array::Handle(ns.hide_names());
|
||||
|
||||
Object& metadata = Object::Handle(ns.GetMetadata());
|
||||
if (metadata.IsError()) {
|
||||
Exceptions::PropagateError(Error::Cast(metadata));
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
auto& prefix_name = String::Handle();
|
||||
if (!prefix.IsNull()) {
|
||||
prefix_name = prefix.name();
|
||||
}
|
||||
|
||||
return CreateLibraryDependencyMirror(thread, importer, importee, show_names,
|
||||
hide_names, metadata, prefix,
|
||||
prefix_name, is_import, is_deferred);
|
||||
}
|
||||
|
||||
static RawGrowableObjectArray* CreateBytecodeLibraryDependencies(
|
||||
Thread* thread,
|
||||
const Library& lib,
|
||||
const Instance& lib_mirror) {
|
||||
ASSERT(lib.is_declared_in_bytecode());
|
||||
|
||||
// Make sure top level class (containing annotations) is fully loaded.
|
||||
lib.EnsureTopLevelClassIsFinalized();
|
||||
|
||||
const auto& deps = GrowableObjectArray::Handle(GrowableObjectArray::New());
|
||||
Array& metadata = Array::Handle(lib.GetExtendedMetadata(lib, 1));
|
||||
if (metadata.Length() == 0) {
|
||||
return deps.raw();
|
||||
}
|
||||
|
||||
// Library has the only element in the extended metadata.
|
||||
metadata ^= metadata.At(0);
|
||||
if (metadata.IsNull()) {
|
||||
return deps.raw();
|
||||
}
|
||||
|
||||
auto& desc = Array::Handle();
|
||||
auto& target_uri = String::Handle();
|
||||
auto& importee = Library::Handle();
|
||||
auto& is_export = Bool::Handle();
|
||||
auto& is_deferred = Bool::Handle();
|
||||
auto& prefix_name = String::Handle();
|
||||
auto& show_names = Array::Handle();
|
||||
auto& hide_names = Array::Handle();
|
||||
auto& dep_metadata = Instance::Handle();
|
||||
auto& dep = Instance::Handle();
|
||||
const auto& no_prefix = LibraryPrefix::Handle();
|
||||
|
||||
for (intptr_t i = 0, n = metadata.Length(); i < n; ++i) {
|
||||
desc ^= metadata.At(i);
|
||||
// Each dependency is represented as an array with the following layout:
|
||||
// [0] = target library URI (String)
|
||||
// [1] = is_export (bool)
|
||||
// [2] = is_deferred (bool)
|
||||
// [3] = prefix (String or null)
|
||||
// [4] = list of show names (List<String>)
|
||||
// [5] = list of hide names (List<String>)
|
||||
// [6] = annotations
|
||||
// The library dependencies are encoded by getLibraryAnnotations(),
|
||||
// pkg/vm/lib/bytecode/gen_bytecode.dart.
|
||||
target_uri ^= desc.At(0);
|
||||
is_export ^= desc.At(1);
|
||||
is_deferred ^= desc.At(2);
|
||||
prefix_name ^= desc.At(3);
|
||||
show_names ^= desc.At(4);
|
||||
hide_names ^= desc.At(5);
|
||||
dep_metadata ^= desc.At(6);
|
||||
|
||||
importee = Library::LookupLibrary(thread, target_uri);
|
||||
if (importee.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
ASSERT(importee.Loaded());
|
||||
|
||||
dep = CreateLibraryDependencyMirror(
|
||||
thread, lib_mirror, importee, show_names, hide_names, dep_metadata,
|
||||
no_prefix, prefix_name, !is_export.value(), is_deferred.value());
|
||||
if (!dep.IsNull()) {
|
||||
deps.Add(dep);
|
||||
}
|
||||
}
|
||||
|
||||
return deps.raw();
|
||||
}
|
||||
|
||||
DEFINE_NATIVE_ENTRY(LibraryMirror_fromPrefix, 0, 1) {
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(LibraryPrefix, prefix,
|
||||
arguments->NativeArgAt(0));
|
||||
|
@ -436,6 +526,10 @@ DEFINE_NATIVE_ENTRY(LibraryMirror_libraryDependencies, 0, 2) {
|
|||
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
|
||||
const Library& lib = Library::Handle(ref.GetLibraryReferent());
|
||||
|
||||
if (lib.is_declared_in_bytecode()) {
|
||||
return CreateBytecodeLibraryDependencies(thread, lib, lib_mirror);
|
||||
}
|
||||
|
||||
Array& ports = Array::Handle();
|
||||
Namespace& ns = Namespace::Handle();
|
||||
Instance& dep = Instance::Handle();
|
||||
|
|
|
@ -10264,11 +10264,17 @@ RawObject* Library::GetMetadata(const Object& obj) const {
|
|||
metadata = kernel::EvaluateMetadata(
|
||||
field, /* is_annotations_offset = */ obj.IsLibrary());
|
||||
}
|
||||
if (metadata.IsArray()) {
|
||||
ASSERT(Array::Cast(metadata).raw() != Object::empty_array().raw());
|
||||
field.SetStaticValue(Array::Cast(metadata), true);
|
||||
if (metadata.IsArray() || metadata.IsNull()) {
|
||||
ASSERT(metadata.raw() != Object::empty_array().raw());
|
||||
field.SetStaticValue(
|
||||
metadata.IsNull() ? Object::null_array() : Array::Cast(metadata),
|
||||
true);
|
||||
}
|
||||
}
|
||||
if (metadata.IsNull()) {
|
||||
// Metadata field exists in order to reference extended metadata.
|
||||
return Object::empty_array().raw();
|
||||
}
|
||||
return metadata.raw();
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
@ -10278,9 +10284,7 @@ RawArray* Library::GetExtendedMetadata(const Object& obj,
|
|||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
return Object::empty_array().raw();
|
||||
#else
|
||||
if (!obj.IsFunction()) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
RELEASE_ASSERT(obj.IsFunction() || obj.IsLibrary());
|
||||
const String& metaname = String::Handle(MakeMetadataName(obj));
|
||||
Field& field = Field::Handle(GetMetadataField(metaname));
|
||||
if (field.IsNull()) {
|
||||
|
|
|
@ -532,7 +532,7 @@ void Library::PrintJSONImpl(JSONStream* stream, bool ref) const {
|
|||
DictionaryIterator entries(*this);
|
||||
Object& entry = Object::Handle();
|
||||
LibraryPrefix& prefix = LibraryPrefix::Handle();
|
||||
String& prefixName = String::Handle();
|
||||
String& prefix_name = String::Handle();
|
||||
while (entries.HasNext()) {
|
||||
entry = entries.GetNext();
|
||||
if (entry.IsLibraryPrefix()) {
|
||||
|
@ -547,15 +547,62 @@ void Library::PrintJSONImpl(JSONStream* stream, bool ref) const {
|
|||
jsdep.AddProperty("isDeferred", prefix.is_deferred_load());
|
||||
jsdep.AddProperty("isExport", false);
|
||||
jsdep.AddProperty("isImport", true);
|
||||
prefixName = prefix.name();
|
||||
ASSERT(!prefixName.IsNull());
|
||||
jsdep.AddProperty("prefix", prefixName.ToCString());
|
||||
prefix_name = prefix.name();
|
||||
ASSERT(!prefix_name.IsNull());
|
||||
jsdep.AddProperty("prefix", prefix_name.ToCString());
|
||||
target = ns.library();
|
||||
jsdep.AddProperty("target", target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_declared_in_bytecode()) {
|
||||
// Make sure top level class (containing annotations) is fully loaded.
|
||||
EnsureTopLevelClassIsFinalized();
|
||||
Array& metadata = Array::Handle(GetExtendedMetadata(*this, 1));
|
||||
if (metadata.Length() != 0) {
|
||||
// Library has the only element in the extended metadata.
|
||||
metadata ^= metadata.At(0);
|
||||
if (!metadata.IsNull()) {
|
||||
Thread* thread = Thread::Current();
|
||||
auto& desc = Array::Handle();
|
||||
auto& target_uri = String::Handle();
|
||||
auto& is_export = Bool::Handle();
|
||||
auto& is_deferred = Bool::Handle();
|
||||
for (intptr_t i = 0, n = metadata.Length(); i < n; ++i) {
|
||||
desc ^= metadata.At(i);
|
||||
// Each dependency is represented as an array with the following
|
||||
// layout:
|
||||
// [0] = target library URI (String)
|
||||
// [1] = is_export (bool)
|
||||
// [2] = is_deferred (bool)
|
||||
// [3] = prefix (String or null)
|
||||
// ...
|
||||
// The library dependencies are encoded by getLibraryAnnotations(),
|
||||
// pkg/vm/lib/bytecode/gen_bytecode.dart.
|
||||
target_uri ^= desc.At(0);
|
||||
is_export ^= desc.At(1);
|
||||
is_deferred ^= desc.At(2);
|
||||
prefix_name ^= desc.At(3);
|
||||
|
||||
target = Library::LookupLibrary(thread, target_uri);
|
||||
if (target.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JSONObject jsdep(&jsarr);
|
||||
jsdep.AddProperty("isDeferred", is_deferred.value());
|
||||
jsdep.AddProperty("isExport", is_export.value());
|
||||
jsdep.AddProperty("isImport", !is_export.value());
|
||||
if (!prefix_name.IsNull()) {
|
||||
jsdep.AddProperty("prefix", prefix_name.ToCString());
|
||||
}
|
||||
jsdep.AddProperty("target", target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
JSONArray jsarr(&jsobj, "variables");
|
||||
|
|
Loading…
Reference in a new issue