mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
[vm] Defer object pools and object pool entries.
This defers literals, to effectively split binary size for libraries that are more data than code, such as localizations. TEST=ci Bug: https://github.com/dart-lang/sdk/issues/41974 Change-Id: I506722037cc0247b90756959e6a6f12bb5021b5c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/183781 Reviewed-by: Alexander Markov <alexmarkov@google.com> Reviewed-by: Siva Annamalai <asiva@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
parent
82ad11aeb9
commit
dce0b514d4
15 changed files with 851 additions and 309 deletions
21
runtime/tests/vm/dart/split_literals.dart
Normal file
21
runtime/tests/vm/dart/split_literals.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
import "split_literals_deferred.dart" deferred as lib;
|
||||
|
||||
class Box {
|
||||
final contents;
|
||||
const Box(this.contents);
|
||||
String toString() => "Box($contents)";
|
||||
}
|
||||
|
||||
main() async {
|
||||
print("Root literal!");
|
||||
print(const <String>["Root literal in a list!"]);
|
||||
print(const <String, String>{"key": "Root literal in a map!"});
|
||||
print(const Box("Root literal in a box!"));
|
||||
|
||||
await lib.loadLibrary();
|
||||
lib.foo();
|
||||
}
|
12
runtime/tests/vm/dart/split_literals_deferred.dart
Normal file
12
runtime/tests/vm/dart/split_literals_deferred.dart
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
import "split_literals.dart";
|
||||
|
||||
void foo() {
|
||||
print("Deferred literal!");
|
||||
print(const <String>["Deferred literal in a list!"]);
|
||||
print(const <String, String>{"key": "Deferred literal in a map!"});
|
||||
print(const Box("Deferred literal in a box!"));
|
||||
}
|
115
runtime/tests/vm/dart/split_literals_test.dart
Normal file
115
runtime/tests/vm/dart/split_literals_test.dart
Normal file
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
import "dart:convert";
|
||||
import "dart:io";
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import "package:path/path.dart" as path;
|
||||
|
||||
import "use_flag_test_helper.dart";
|
||||
|
||||
main(List<String> args) async {
|
||||
if (!isAOTRuntime) {
|
||||
return; // Running in JIT: AOT binaries not available.
|
||||
}
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
return; // SDK tree not available on the test device.
|
||||
}
|
||||
|
||||
// These are the tools we need to be available to run on a given platform:
|
||||
if (!File(platformDill).existsSync()) {
|
||||
throw "Cannot run test as $platformDill does not exist";
|
||||
}
|
||||
if (!await testExecutable(genSnapshot)) {
|
||||
throw "Cannot run test as $genSnapshot not available";
|
||||
}
|
||||
|
||||
sanitizedPartitioning(manifest) {
|
||||
// Filter core libraries, relativize URIs, and sort to make the results less
|
||||
// sensitive to compiler or test harness changes.
|
||||
print(manifest);
|
||||
var units = <List<String>>[];
|
||||
for (var unit in manifest['loadingUnits']) {
|
||||
var uris = <String>[];
|
||||
for (var uri in unit['libraries']) {
|
||||
if (uri.startsWith("dart:")) continue;
|
||||
uris.add(Uri.parse(uri).pathSegments.last);
|
||||
}
|
||||
uris.sort();
|
||||
units.add(uris);
|
||||
}
|
||||
units.sort((a, b) => a.first.compareTo(b.first));
|
||||
print(units);
|
||||
return units;
|
||||
}
|
||||
|
||||
await withTempDir("split-literals-test", (String tempDir) async {
|
||||
final source =
|
||||
path.join(sdkDir, "runtime/tests/vm/dart_2/split_literals.dart");
|
||||
final dill = path.join(tempDir, "split_literals.dart.dill");
|
||||
final snapshot = path.join(tempDir, "split_literals.so");
|
||||
final manifest = path.join(tempDir, "split_literals.txt");
|
||||
final deferredSnapshot = snapshot + "-2.part.so";
|
||||
|
||||
// Compile source to kernel.
|
||||
await run(genKernel, <String>[
|
||||
"--aot",
|
||||
"--platform=$platformDill",
|
||||
"-o",
|
||||
dill,
|
||||
source,
|
||||
]);
|
||||
|
||||
// Compile kernel to ELF.
|
||||
await run(genSnapshot, <String>[
|
||||
"--use_bare_instructions=false", //# object: ok
|
||||
"--use_bare_instructions=true", //# bare: ok
|
||||
"--snapshot-kind=app-aot-elf",
|
||||
"--elf=$snapshot",
|
||||
"--loading-unit-manifest=$manifest",
|
||||
dill,
|
||||
]);
|
||||
var manifestContent = jsonDecode(await new File(manifest).readAsString());
|
||||
Expect.equals(2, manifestContent["loadingUnits"].length);
|
||||
// Note package:expect doesn't do deep equals on collections.
|
||||
Expect.equals(
|
||||
"[[split_literals.dart],"
|
||||
" [split_literals_deferred.dart]]",
|
||||
sanitizedPartitioning(manifestContent).toString());
|
||||
Expect.isTrue(await new File(deferredSnapshot).exists());
|
||||
|
||||
bool containsSubsequence(haystack, needle) {
|
||||
outer:
|
||||
for (var i = 0, n = haystack.length - needle.length; i < n; i++) {
|
||||
for (var j = 0; j < needle.length; j++) {
|
||||
if (haystack[i + j] != needle.codeUnitAt(j)) continue outer;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var unit_1 = await new File(snapshot).readAsBytes();
|
||||
Expect.isTrue(containsSubsequence(unit_1, "Root literal!"));
|
||||
Expect.isTrue(containsSubsequence(unit_1, "Root literal in a list!"));
|
||||
Expect.isTrue(containsSubsequence(unit_1, "Root literal in a map!"));
|
||||
Expect.isTrue(containsSubsequence(unit_1, "Root literal in a box!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a list!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a map!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a box!"));
|
||||
|
||||
var unit_2 = await new File(deferredSnapshot).readAsBytes();
|
||||
Expect.isTrue(!containsSubsequence(unit_2, "Root literal!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a list!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a map!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a box!"));
|
||||
Expect.isTrue(containsSubsequence(unit_2, "Deferred literal!"));
|
||||
Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a list!"));
|
||||
Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a map!"));
|
||||
Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a box!"));
|
||||
});
|
||||
}
|
21
runtime/tests/vm/dart_2/split_literals.dart
Normal file
21
runtime/tests/vm/dart_2/split_literals.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
import "split_literals_deferred.dart" deferred as lib;
|
||||
|
||||
class Box {
|
||||
final contents;
|
||||
const Box(this.contents);
|
||||
String toString() => "Box($contents)";
|
||||
}
|
||||
|
||||
main() async {
|
||||
print("Root literal!");
|
||||
print(const <String>["Root literal in a list!"]);
|
||||
print(const <String, String>{"key": "Root literal in a map!"});
|
||||
print(const Box("Root literal in a box!"));
|
||||
|
||||
await lib.loadLibrary();
|
||||
lib.foo();
|
||||
}
|
12
runtime/tests/vm/dart_2/split_literals_deferred.dart
Normal file
12
runtime/tests/vm/dart_2/split_literals_deferred.dart
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
import "split_literals.dart";
|
||||
|
||||
void foo() {
|
||||
print("Deferred literal!");
|
||||
print(const <String>["Deferred literal in a list!"]);
|
||||
print(const <String, String>{"key": "Deferred literal in a map!"});
|
||||
print(const Box("Deferred literal in a box!"));
|
||||
}
|
115
runtime/tests/vm/dart_2/split_literals_test.dart
Normal file
115
runtime/tests/vm/dart_2/split_literals_test.dart
Normal file
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
import "dart:convert";
|
||||
import "dart:io";
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import "package:path/path.dart" as path;
|
||||
|
||||
import "use_flag_test_helper.dart";
|
||||
|
||||
main(List<String> args) async {
|
||||
if (!isAOTRuntime) {
|
||||
return; // Running in JIT: AOT binaries not available.
|
||||
}
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
return; // SDK tree not available on the test device.
|
||||
}
|
||||
|
||||
// These are the tools we need to be available to run on a given platform:
|
||||
if (!File(platformDill).existsSync()) {
|
||||
throw "Cannot run test as $platformDill does not exist";
|
||||
}
|
||||
if (!await testExecutable(genSnapshot)) {
|
||||
throw "Cannot run test as $genSnapshot not available";
|
||||
}
|
||||
|
||||
sanitizedPartitioning(manifest) {
|
||||
// Filter core libraries, relativize URIs, and sort to make the results less
|
||||
// sensitive to compiler or test harness changes.
|
||||
print(manifest);
|
||||
var units = <List<String>>[];
|
||||
for (var unit in manifest['loadingUnits']) {
|
||||
var uris = <String>[];
|
||||
for (var uri in unit['libraries']) {
|
||||
if (uri.startsWith("dart:")) continue;
|
||||
uris.add(Uri.parse(uri).pathSegments.last);
|
||||
}
|
||||
uris.sort();
|
||||
units.add(uris);
|
||||
}
|
||||
units.sort((a, b) => a.first.compareTo(b.first));
|
||||
print(units);
|
||||
return units;
|
||||
}
|
||||
|
||||
await withTempDir("split-literals-test", (String tempDir) async {
|
||||
final source =
|
||||
path.join(sdkDir, "runtime/tests/vm/dart_2/split_literals.dart");
|
||||
final dill = path.join(tempDir, "split_literals.dart.dill");
|
||||
final snapshot = path.join(tempDir, "split_literals.so");
|
||||
final manifest = path.join(tempDir, "split_literals.txt");
|
||||
final deferredSnapshot = snapshot + "-2.part.so";
|
||||
|
||||
// Compile source to kernel.
|
||||
await run(genKernel, <String>[
|
||||
"--aot",
|
||||
"--platform=$platformDill",
|
||||
"-o",
|
||||
dill,
|
||||
source,
|
||||
]);
|
||||
|
||||
// Compile kernel to ELF.
|
||||
await run(genSnapshot, <String>[
|
||||
"--use_bare_instructions=false", //# object: ok
|
||||
"--use_bare_instructions=true", //# bare: ok
|
||||
"--snapshot-kind=app-aot-elf",
|
||||
"--elf=$snapshot",
|
||||
"--loading-unit-manifest=$manifest",
|
||||
dill,
|
||||
]);
|
||||
var manifestContent = jsonDecode(await new File(manifest).readAsString());
|
||||
Expect.equals(2, manifestContent["loadingUnits"].length);
|
||||
// Note package:expect doesn't do deep equals on collections.
|
||||
Expect.equals(
|
||||
"[[split_literals.dart],"
|
||||
" [split_literals_deferred.dart]]",
|
||||
sanitizedPartitioning(manifestContent).toString());
|
||||
Expect.isTrue(await new File(deferredSnapshot).exists());
|
||||
|
||||
bool containsSubsequence(haystack, needle) {
|
||||
outer:
|
||||
for (var i = 0, n = haystack.length - needle.length; i < n; i++) {
|
||||
for (var j = 0; j < needle.length; j++) {
|
||||
if (haystack[i + j] != needle.codeUnitAt(j)) continue outer;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var unit_1 = await new File(snapshot).readAsBytes();
|
||||
Expect.isTrue(containsSubsequence(unit_1, "Root literal!"));
|
||||
Expect.isTrue(containsSubsequence(unit_1, "Root literal in a list!"));
|
||||
Expect.isTrue(containsSubsequence(unit_1, "Root literal in a map!"));
|
||||
Expect.isTrue(containsSubsequence(unit_1, "Root literal in a box!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a list!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a map!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a box!"));
|
||||
|
||||
var unit_2 = await new File(deferredSnapshot).readAsBytes();
|
||||
Expect.isTrue(!containsSubsequence(unit_2, "Root literal!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a list!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a map!"));
|
||||
Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a box!"));
|
||||
Expect.isTrue(containsSubsequence(unit_2, "Deferred literal!"));
|
||||
Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a list!"));
|
||||
Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a map!"));
|
||||
Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a box!"));
|
||||
});
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -132,16 +132,20 @@ class DeserializationCluster : public ZoneAllocated {
|
|||
|
||||
// Allocate memory for all objects in the cluster and write their addresses
|
||||
// into the ref array. Do not touch this memory.
|
||||
virtual void ReadAlloc(Deserializer* deserializer, bool is_canonical) = 0;
|
||||
virtual void ReadAlloc(Deserializer* deserializer, bool stamp_canonical) = 0;
|
||||
|
||||
// Initialize the cluster's objects. Do not touch the memory of other objects.
|
||||
virtual void ReadFill(Deserializer* deserializer, bool is_canonical) = 0;
|
||||
virtual void ReadFill(Deserializer* deserializer, bool stamp_canonical) = 0;
|
||||
|
||||
// Complete any action that requires the full graph to be deserialized, such
|
||||
// as rehashing.
|
||||
virtual void PostLoad(Deserializer* deserializer,
|
||||
const Array& refs,
|
||||
bool is_canonical) {}
|
||||
bool canonicalize) {
|
||||
if (canonicalize) {
|
||||
FATAL1("%s needs canonicalization but doesn't define PostLoad", name());
|
||||
}
|
||||
}
|
||||
|
||||
const char* name() const { return name_; }
|
||||
|
||||
|
@ -368,7 +372,7 @@ class Serializer : public ThreadStackResource {
|
|||
Write<int32_t>(cid);
|
||||
}
|
||||
|
||||
void PrepareInstructions(GrowableArray<CodePtr>* codes);
|
||||
void PrepareInstructions();
|
||||
void WriteInstructions(InstructionsPtr instr,
|
||||
uint32_t unchecked_offset,
|
||||
CodePtr code,
|
||||
|
@ -401,6 +405,7 @@ class Serializer : public ThreadStackResource {
|
|||
void set_loading_units(GrowableArray<LoadingUnitSerializationData*>* units) {
|
||||
loading_units_ = units;
|
||||
}
|
||||
intptr_t current_loading_unit_id() { return current_loading_unit_id_; }
|
||||
void set_current_loading_unit_id(intptr_t id) {
|
||||
current_loading_unit_id_ = id;
|
||||
}
|
||||
|
@ -426,6 +431,13 @@ class Serializer : public ThreadStackResource {
|
|||
FATAL("Missing ref");
|
||||
}
|
||||
|
||||
bool HasRef(ObjectPtr object) const {
|
||||
return heap_->GetObjectId(object) != kUnreachableReference;
|
||||
}
|
||||
bool IsWritten(ObjectPtr object) const {
|
||||
return heap_->GetObjectId(object) > num_base_objects_;
|
||||
}
|
||||
|
||||
private:
|
||||
const char* ReadOnlyObjectType(intptr_t cid);
|
||||
|
||||
|
@ -586,6 +598,8 @@ class Deserializer : public ThreadStackResource {
|
|||
|
||||
uword ReadWordWith32BitReads() { return stream_.ReadWordWith32BitReads(); }
|
||||
|
||||
intptr_t position() const { return stream_.Position(); }
|
||||
void set_position(intptr_t p) { stream_.SetPosition(p); }
|
||||
const uint8_t* CurrentBufferAddress() const {
|
||||
return stream_.AddressOfCurrentPosition();
|
||||
}
|
||||
|
@ -653,6 +667,7 @@ class Deserializer : public ThreadStackResource {
|
|||
Zone* zone() const { return zone_; }
|
||||
Snapshot::Kind kind() const { return kind_; }
|
||||
FieldTable* initial_field_table() const { return initial_field_table_; }
|
||||
bool is_non_root_unit() const { return is_non_root_unit_; }
|
||||
|
||||
private:
|
||||
Heap* heap_;
|
||||
|
|
|
@ -71,8 +71,15 @@ void CodeRelocator::Relocate(bool is_vm_isolate) {
|
|||
// We're guaranteed to have all calls resolved, since
|
||||
// * backwards calls are resolved eagerly
|
||||
// * forward calls are resolved once the target is written
|
||||
ASSERT(all_unresolved_calls_.IsEmpty());
|
||||
ASSERT(unresolved_calls_by_destination_.IsEmpty());
|
||||
if (!all_unresolved_calls_.IsEmpty()) {
|
||||
for (auto call : all_unresolved_calls_) {
|
||||
OS::PrintErr("Unresolved call to %s from %s\n",
|
||||
Object::Handle(call->callee).ToCString(),
|
||||
Object::Handle(call->caller).ToCString());
|
||||
}
|
||||
}
|
||||
RELEASE_ASSERT(all_unresolved_calls_.IsEmpty());
|
||||
RELEASE_ASSERT(unresolved_calls_by_destination_.IsEmpty());
|
||||
|
||||
// Any trampolines we created must be patched with the right offsets.
|
||||
auto it = trampolines_by_destination_.GetIterator();
|
||||
|
|
|
@ -20,16 +20,8 @@ void TypeTestingStubGenerator::BuildOptimizedTypeTestStub(
|
|||
const Type& type,
|
||||
const Class& type_class) {
|
||||
BuildOptimizedTypeTestStubFastCases(assembler, hi, type, type_class);
|
||||
if (!compiler::IsSameObject(
|
||||
compiler::NullObject(),
|
||||
compiler::CastHandle<Object>(slow_type_test_stub))) {
|
||||
__ GenerateUnRelocatedPcRelativeTailCall();
|
||||
unresolved_calls->Add(new compiler::UnresolvedPcRelativeCall(
|
||||
__ CodeSize(), slow_type_test_stub, /*is_tail_call=*/true));
|
||||
} else {
|
||||
__ Branch(compiler::Address(
|
||||
THR, compiler::target::Thread::slow_type_test_entry_point_offset()));
|
||||
}
|
||||
__ Branch(compiler::Address(
|
||||
THR, compiler::target::Thread::slow_type_test_entry_point_offset()));
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
|
|
@ -20,19 +20,11 @@ void TypeTestingStubGenerator::BuildOptimizedTypeTestStub(
|
|||
const Type& type,
|
||||
const Class& type_class) {
|
||||
BuildOptimizedTypeTestStubFastCases(assembler, hi, type, type_class);
|
||||
if (!compiler::IsSameObject(
|
||||
compiler::NullObject(),
|
||||
compiler::CastHandle<Object>(slow_type_test_stub))) {
|
||||
__ GenerateUnRelocatedPcRelativeTailCall();
|
||||
unresolved_calls->Add(new compiler::UnresolvedPcRelativeCall(
|
||||
__ CodeSize(), slow_type_test_stub, /*is_tail_call=*/true));
|
||||
} else {
|
||||
__ ldr(TMP,
|
||||
compiler::Address(
|
||||
THR,
|
||||
compiler::target::Thread::slow_type_test_entry_point_offset()));
|
||||
__ br(TMP);
|
||||
}
|
||||
__ ldr(
|
||||
TMP,
|
||||
compiler::Address(
|
||||
THR, compiler::target::Thread::slow_type_test_entry_point_offset()));
|
||||
__ br(TMP);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
|
|
@ -20,16 +20,8 @@ void TypeTestingStubGenerator::BuildOptimizedTypeTestStub(
|
|||
const Type& type,
|
||||
const Class& type_class) {
|
||||
BuildOptimizedTypeTestStubFastCases(assembler, hi, type, type_class);
|
||||
if (!compiler::IsSameObject(
|
||||
compiler::NullObject(),
|
||||
compiler::CastHandle<Object>(slow_type_test_stub))) {
|
||||
__ GenerateUnRelocatedPcRelativeTailCall();
|
||||
unresolved_calls->Add(new compiler::UnresolvedPcRelativeCall(
|
||||
__ CodeSize(), slow_type_test_stub, /*is_tail_call=*/true));
|
||||
} else {
|
||||
__ jmp(compiler::Address(
|
||||
THR, compiler::target::Thread::slow_type_test_entry_point_offset()));
|
||||
}
|
||||
__ jmp(compiler::Address(
|
||||
THR, compiler::target::Thread::slow_type_test_entry_point_offset()));
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
|
|
@ -20401,9 +20401,10 @@ AbstractTypePtr Type::Canonicalize(Thread* thread, TrailPtr trail) const {
|
|||
}
|
||||
}
|
||||
ASSERT(this->Equals(type));
|
||||
ASSERT(type.IsCanonical());
|
||||
ASSERT(type.IsOld());
|
||||
return type.ptr();
|
||||
if (type.IsCanonical()) {
|
||||
return type.ptr();
|
||||
}
|
||||
}
|
||||
|
||||
Type& type = Type::Handle(zone);
|
||||
|
|
|
@ -1371,9 +1371,15 @@ class AssignLoadingUnitsCodeVisitor : public CodeVisitor {
|
|||
MergeAssignment(obj_, id);
|
||||
obj_ = code.compressed_stackmaps();
|
||||
MergeAssignment(obj_, id);
|
||||
if (!FLAG_use_bare_instructions) {
|
||||
obj_ = code.object_pool();
|
||||
MergeAssignment(obj_, id);
|
||||
}
|
||||
}
|
||||
|
||||
void MergeAssignment(const Object& obj, intptr_t id) {
|
||||
if (obj.IsNull()) return;
|
||||
|
||||
intptr_t old_id = heap_->GetLoadingUnit(obj_.ptr());
|
||||
if (old_id == WeakTable::kNoValue) {
|
||||
heap_->SetLoadingUnit(obj_.ptr(), id);
|
||||
|
|
|
@ -1663,6 +1663,8 @@ class UntaggedObjectPool : public UntaggedObject {
|
|||
|
||||
friend class Object;
|
||||
friend class CodeSerializationCluster;
|
||||
friend class UnitSerializationRoots;
|
||||
friend class UnitDeserializationRoots;
|
||||
};
|
||||
|
||||
class UntaggedInstructions : public UntaggedObject {
|
||||
|
|
Loading…
Reference in a new issue