[vm] Reland support for real unboxed floating point fields in AOT
Issue https://github.com/dart-lang/sdk/issues/40404 Change-Id: Icfa801ff0640a6b27bb3c13d0b737c40452cbf7d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133983 Commit-Queue: Victor Agnez Lima <victoragnez@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
906c6ea21c
commit
b68d95ec9e
@@ -0,0 +1,151 @@
|
||||
// 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.
|
||||
// VMOptions=
|
||||
// VMOptions=--use_compactor
|
||||
// VMOptions=--use_compactor --force_evacuation
|
||||
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:observatory/service_io.dart';
|
||||
import 'package:unittest/unittest.dart';
|
||||
import 'test_helper.dart';
|
||||
|
||||
double getDoubleWithHeapObjectTag() {
|
||||
final bd = ByteData(8);
|
||||
bd.setUint64(0, 0x8000000000000001, Endian.host);
|
||||
final double v = bd.getFloat64(0, Endian.host);
|
||||
return v;
|
||||
}
|
||||
|
||||
// small example from [Lenguaer & Tarjan 1979]
|
||||
class R {
|
||||
final double fld = getDoubleWithHeapObjectTag();
|
||||
var x;
|
||||
var y;
|
||||
var z;
|
||||
}
|
||||
|
||||
class A {
|
||||
var x;
|
||||
}
|
||||
|
||||
class B {
|
||||
var x;
|
||||
var y;
|
||||
var z;
|
||||
}
|
||||
|
||||
class C {
|
||||
var x;
|
||||
var y;
|
||||
}
|
||||
|
||||
class D {
|
||||
var x;
|
||||
}
|
||||
|
||||
class E {
|
||||
var x;
|
||||
}
|
||||
|
||||
class F {
|
||||
var x;
|
||||
}
|
||||
|
||||
class G {
|
||||
var x;
|
||||
var y;
|
||||
}
|
||||
|
||||
class H {
|
||||
var x;
|
||||
var y;
|
||||
}
|
||||
|
||||
class I {
|
||||
var x;
|
||||
}
|
||||
|
||||
class J {
|
||||
var x;
|
||||
}
|
||||
|
||||
class K {
|
||||
var x;
|
||||
var y;
|
||||
}
|
||||
|
||||
class L {
|
||||
var x;
|
||||
}
|
||||
|
||||
var r;
|
||||
|
||||
buildGraph() {
|
||||
r = new R();
|
||||
var a = new A();
|
||||
var b = new B();
|
||||
var c = new C();
|
||||
var d = new D();
|
||||
var e = new E();
|
||||
var f = new F();
|
||||
var g = new G();
|
||||
var h = new H();
|
||||
var i = new I();
|
||||
var j = new J();
|
||||
var k = new K();
|
||||
var l = new L();
|
||||
|
||||
r.x = a;
|
||||
r.y = b;
|
||||
r.z = c;
|
||||
a.x = d;
|
||||
b.x = a;
|
||||
b.y = d;
|
||||
b.z = e;
|
||||
c.x = f;
|
||||
c.y = g;
|
||||
d.x = l;
|
||||
e.x = h;
|
||||
f.x = i;
|
||||
g.x = i;
|
||||
g.y = j;
|
||||
h.x = e;
|
||||
h.y = k;
|
||||
i.x = k;
|
||||
j.x = i;
|
||||
k.x = i;
|
||||
k.y = r;
|
||||
l.x = h;
|
||||
|
||||
expect(r.fld, getDoubleWithHeapObjectTag());
|
||||
}
|
||||
|
||||
var tests = <IsolateTest>[
|
||||
(Isolate isolate) async {
|
||||
final graph = await isolate.fetchHeapSnapshot().done;
|
||||
|
||||
node(String className) {
|
||||
return graph.objects.singleWhere((v) => v.klass.name == className);
|
||||
}
|
||||
|
||||
expect(node('I').parent, equals(node('R')));
|
||||
expect(node('K').parent, equals(node('R')));
|
||||
expect(node('C').parent, equals(node('R')));
|
||||
expect(node('H').parent, equals(node('R')));
|
||||
expect(node('E').parent, equals(node('R')));
|
||||
expect(node('A').parent, equals(node('R')));
|
||||
expect(node('D').parent, equals(node('R')));
|
||||
expect(node('B').parent, equals(node('R')));
|
||||
|
||||
expect(node('F').parent, equals(node('C')));
|
||||
expect(node('G').parent, equals(node('C')));
|
||||
expect(node('J').parent, equals(node('G')));
|
||||
expect(node('L').parent, equals(node('D')));
|
||||
|
||||
expect(node('R'), isNotNull); // The field.
|
||||
},
|
||||
];
|
||||
|
||||
main(args) => runIsolateTests(args, tests, testeeBefore: buildGraph);
|
||||
@@ -14,6 +14,11 @@ valid_source_locations_test: Pass, Slow # Generally slow, even in release-x64.
|
||||
[ $arch == arm ]
|
||||
process_service_test: Pass, Fail # Issue 24344
|
||||
|
||||
# Test uses service API and relies on correct class names
|
||||
[ $builder_tag == obfuscated ]
|
||||
dominator_tree_vm_test: SkipByDesign
|
||||
dominator_tree_vm_with_double_field_test: SkipByDesign
|
||||
|
||||
# Tests with known analyzer issues
|
||||
[ $compiler == dart2analyzer ]
|
||||
developer_extension_test: SkipByDesign
|
||||
|
||||
@@ -417,6 +417,10 @@ typedef simd128_value_t fpu_register_t;
|
||||
#define DUAL_MAPPING_SUPPORTED 1
|
||||
#endif
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
|
||||
#define SUPPORT_UNBOXED_INSTANCE_FIELDS
|
||||
#endif
|
||||
|
||||
// Short form printf format specifiers
|
||||
#define Pd PRIdPTR
|
||||
#define Pu PRIuPTR
|
||||
|
||||
@@ -21,7 +21,7 @@ class Utils {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T Maximum(T x, T y) {
|
||||
static constexpr inline T Maximum(T x, T y) {
|
||||
return x > y ? x : y;
|
||||
}
|
||||
|
||||
@@ -352,12 +352,18 @@ class Utils {
|
||||
return bit_cast<word>(mask);
|
||||
}
|
||||
|
||||
static uword Bit(uint32_t n) {
|
||||
ASSERT(n < kBitsPerWord);
|
||||
uword bit = 1;
|
||||
template <typename T = uword>
|
||||
static T Bit(uint32_t n) {
|
||||
ASSERT(n < sizeof(T) * kBitsPerByte);
|
||||
T bit = 1;
|
||||
return bit << n;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DART_FORCE_INLINE static bool TestBit(T mask, intptr_t position) {
|
||||
return ((mask >> position) & 1) != 0;
|
||||
}
|
||||
|
||||
// Decode integer in SLEB128 format from |data| and update |byte_index|.
|
||||
template <typename ValueType>
|
||||
static ValueType DecodeSLEB128(const uint8_t* data,
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// 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:typed_data';
|
||||
import 'dart:async';
|
||||
import 'dart:isolate';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
double getDoubleWithHeapObjectTag() {
|
||||
final bd = ByteData(8);
|
||||
bd.setUint64(0, 0x8000000000000001, Endian.host);
|
||||
final double v = bd.getFloat64(0, Endian.host);
|
||||
return v;
|
||||
}
|
||||
|
||||
class Foo {
|
||||
final String clazz = "foo";
|
||||
final double x = getDoubleWithHeapObjectTag();
|
||||
}
|
||||
|
||||
// Here we ensure to have a GC pointer and a non-GC pointer field, and then a
|
||||
// type argument vector, so the offset in number of words for the type arguments
|
||||
// will be different between host and target when compiling from 64-bit to
|
||||
// 32-bit architectures.
|
||||
class Bar<T> extends Foo {
|
||||
final String clazz = "bar";
|
||||
final double y = getDoubleWithHeapObjectTag();
|
||||
final T value;
|
||||
Bar(T val) : value = val;
|
||||
}
|
||||
|
||||
main() async {
|
||||
final receivePort = new ReceivePort();
|
||||
receivePort.sendPort.send(Foo());
|
||||
receivePort.sendPort.send(Bar<String>("StringBar"));
|
||||
receivePort.sendPort.send(Bar<double>(4.2));
|
||||
final it = StreamIterator(receivePort);
|
||||
|
||||
Expect.isTrue(await it.moveNext());
|
||||
final foo = it.current as Foo;
|
||||
|
||||
Expect.isTrue(await it.moveNext());
|
||||
final string_bar = it.current as Bar<String>;
|
||||
|
||||
Expect.isTrue(await it.moveNext());
|
||||
final double_bar = it.current as Bar<double>;
|
||||
|
||||
Expect.equals(string_bar.value, "StringBar");
|
||||
Expect.equals(string_bar.clazz, "bar");
|
||||
Expect.equals(string_bar.y, getDoubleWithHeapObjectTag());
|
||||
Expect.equals(string_bar.x, getDoubleWithHeapObjectTag());
|
||||
Expect.equals(double_bar.value, 4.2);
|
||||
Expect.equals(foo.clazz, "foo");
|
||||
Expect.equals(foo.x, getDoubleWithHeapObjectTag());
|
||||
|
||||
await it.cancel();
|
||||
}
|
||||
@@ -71,17 +71,17 @@ static void Finish(Thread* thread) {
|
||||
// Verify that closure field offsets are identical in Dart and C++.
|
||||
ASSERT(fields.Length() == 6);
|
||||
field ^= fields.At(0);
|
||||
ASSERT(field.Offset() == Closure::instantiator_type_arguments_offset());
|
||||
ASSERT(field.HostOffset() == Closure::instantiator_type_arguments_offset());
|
||||
field ^= fields.At(1);
|
||||
ASSERT(field.Offset() == Closure::function_type_arguments_offset());
|
||||
ASSERT(field.HostOffset() == Closure::function_type_arguments_offset());
|
||||
field ^= fields.At(2);
|
||||
ASSERT(field.Offset() == Closure::delayed_type_arguments_offset());
|
||||
ASSERT(field.HostOffset() == Closure::delayed_type_arguments_offset());
|
||||
field ^= fields.At(3);
|
||||
ASSERT(field.Offset() == Closure::function_offset());
|
||||
ASSERT(field.HostOffset() == Closure::function_offset());
|
||||
field ^= fields.At(4);
|
||||
ASSERT(field.Offset() == Closure::context_offset());
|
||||
ASSERT(field.HostOffset() == Closure::context_offset());
|
||||
field ^= fields.At(5);
|
||||
ASSERT(field.Offset() == Closure::hash_offset());
|
||||
ASSERT(field.HostOffset() == Closure::hash_offset());
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
// Eagerly compile Bool class, bool constants are used from within compiler.
|
||||
|
||||
@@ -240,33 +240,33 @@ void ClassFinalizer::VerifyBootstrapClasses() {
|
||||
#if defined(DEBUG)
|
||||
// Basic checking.
|
||||
cls = object_store->object_class();
|
||||
ASSERT(Instance::InstanceSize() == cls.instance_size());
|
||||
ASSERT(Instance::InstanceSize() == cls.host_instance_size());
|
||||
cls = object_store->integer_implementation_class();
|
||||
ASSERT(Integer::InstanceSize() == cls.instance_size());
|
||||
ASSERT(Integer::InstanceSize() == cls.host_instance_size());
|
||||
cls = object_store->smi_class();
|
||||
ASSERT(Smi::InstanceSize() == cls.instance_size());
|
||||
ASSERT(Smi::InstanceSize() == cls.host_instance_size());
|
||||
cls = object_store->mint_class();
|
||||
ASSERT(Mint::InstanceSize() == cls.instance_size());
|
||||
ASSERT(Mint::InstanceSize() == cls.host_instance_size());
|
||||
cls = object_store->one_byte_string_class();
|
||||
ASSERT(OneByteString::InstanceSize() == cls.instance_size());
|
||||
ASSERT(OneByteString::InstanceSize() == cls.host_instance_size());
|
||||
cls = object_store->two_byte_string_class();
|
||||
ASSERT(TwoByteString::InstanceSize() == cls.instance_size());
|
||||
ASSERT(TwoByteString::InstanceSize() == cls.host_instance_size());
|
||||
cls = object_store->external_one_byte_string_class();
|
||||
ASSERT(ExternalOneByteString::InstanceSize() == cls.instance_size());
|
||||
ASSERT(ExternalOneByteString::InstanceSize() == cls.host_instance_size());
|
||||
cls = object_store->external_two_byte_string_class();
|
||||
ASSERT(ExternalTwoByteString::InstanceSize() == cls.instance_size());
|
||||
ASSERT(ExternalTwoByteString::InstanceSize() == cls.host_instance_size());
|
||||
cls = object_store->double_class();
|
||||
ASSERT(Double::InstanceSize() == cls.instance_size());
|
||||
ASSERT(Double::InstanceSize() == cls.host_instance_size());
|
||||
cls = object_store->bool_class();
|
||||
ASSERT(Bool::InstanceSize() == cls.instance_size());
|
||||
ASSERT(Bool::InstanceSize() == cls.host_instance_size());
|
||||
cls = object_store->array_class();
|
||||
ASSERT(Array::InstanceSize() == cls.instance_size());
|
||||
ASSERT(Array::InstanceSize() == cls.host_instance_size());
|
||||
cls = object_store->immutable_array_class();
|
||||
ASSERT(ImmutableArray::InstanceSize() == cls.instance_size());
|
||||
ASSERT(ImmutableArray::InstanceSize() == cls.host_instance_size());
|
||||
cls = object_store->weak_property_class();
|
||||
ASSERT(WeakProperty::InstanceSize() == cls.instance_size());
|
||||
ASSERT(WeakProperty::InstanceSize() == cls.host_instance_size());
|
||||
cls = object_store->linked_hash_map_class();
|
||||
ASSERT(LinkedHashMap::InstanceSize() == cls.instance_size());
|
||||
ASSERT(LinkedHashMap::InstanceSize() == cls.host_instance_size());
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
// Remember the currently pending classes.
|
||||
@@ -1358,7 +1358,7 @@ void ClassFinalizer::VerifyImplicitFieldOffsets() {
|
||||
fields_array ^= cls.fields();
|
||||
ASSERT(fields_array.Length() == ByteBuffer::NumberOfFields());
|
||||
field ^= fields_array.At(0);
|
||||
ASSERT(field.Offset() == ByteBuffer::data_offset());
|
||||
ASSERT(field.HostOffset() == ByteBuffer::data_offset());
|
||||
name ^= field.name();
|
||||
expected_name ^= String::New("_data");
|
||||
ASSERT(String::EqualsIgnoringPrivateKey(name, expected_name));
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "vm/class_table.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "platform/atomic.h"
|
||||
#include "vm/flags.h"
|
||||
#include "vm/growable_array.h"
|
||||
@@ -21,7 +23,9 @@ SharedClassTable::SharedClassTable()
|
||||
: top_(kNumPredefinedCids),
|
||||
capacity_(0),
|
||||
table_(NULL),
|
||||
old_tables_(new MallocGrowableArray<intptr_t*>()) {
|
||||
old_tables_(new MallocGrowableArray<intptr_t*>()),
|
||||
unboxed_fields_map_(nullptr),
|
||||
old_unboxed_fields_maps_(new MallocGrowableArray<UnboxedFieldBitmap*>()) {
|
||||
if (Dart::vm_isolate() == NULL) {
|
||||
ASSERT(kInitialCapacity >= kNumPredefinedCids);
|
||||
capacity_ = kInitialCapacity;
|
||||
@@ -47,6 +51,11 @@ SharedClassTable::SharedClassTable()
|
||||
table_[kVoidCid] = vm_shared_class_table->SizeAt(kVoidCid);
|
||||
table_[kNeverCid] = vm_shared_class_table->SizeAt(kNeverCid);
|
||||
}
|
||||
#if defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
unboxed_fields_map_ = static_cast<UnboxedFieldBitmap*>(
|
||||
malloc(capacity_ * sizeof(UnboxedFieldBitmap)));
|
||||
memset(unboxed_fields_map_, 0, sizeof(UnboxedFieldBitmap) * capacity_);
|
||||
#endif // defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
#ifndef PRODUCT
|
||||
trace_allocation_table_ =
|
||||
static_cast<uint8_t*>(malloc(capacity_ * sizeof(uint8_t))); // NOLINT
|
||||
@@ -61,6 +70,16 @@ SharedClassTable::~SharedClassTable() {
|
||||
delete old_tables_;
|
||||
free(table_);
|
||||
}
|
||||
|
||||
if (old_unboxed_fields_maps_ != nullptr) {
|
||||
FreeOldUnboxedFieldsMaps();
|
||||
delete old_unboxed_fields_maps_;
|
||||
}
|
||||
|
||||
if (unboxed_fields_map_ != nullptr) {
|
||||
free(unboxed_fields_map_);
|
||||
}
|
||||
|
||||
NOT_IN_PRODUCT(free(trace_allocation_table_));
|
||||
}
|
||||
|
||||
@@ -133,6 +152,12 @@ void SharedClassTable::FreeOldTables() {
|
||||
}
|
||||
}
|
||||
|
||||
void SharedClassTable::FreeOldUnboxedFieldsMaps() {
|
||||
while (old_unboxed_fields_maps_->length() > 0) {
|
||||
free(old_unboxed_fields_maps_->RemoveLast());
|
||||
}
|
||||
}
|
||||
|
||||
void ClassTable::Register(const Class& cls) {
|
||||
ASSERT(Thread::Current()->IsMutatorThread());
|
||||
|
||||
@@ -142,7 +167,7 @@ void ClassTable::Register(const Class& cls) {
|
||||
// parallel to [ClassTable].
|
||||
|
||||
const intptr_t instance_size =
|
||||
cls.is_abstract() ? 0 : Class::instance_size(cls.raw());
|
||||
cls.is_abstract() ? 0 : Class::host_instance_size(cls.raw());
|
||||
|
||||
const intptr_t expected_cid =
|
||||
shared_class_table_->Register(index, instance_size);
|
||||
@@ -239,6 +264,7 @@ void SharedClassTable::Grow(intptr_t new_capacity) {
|
||||
|
||||
intptr_t* new_table = static_cast<intptr_t*>(
|
||||
malloc(new_capacity * sizeof(intptr_t))); // NOLINT
|
||||
|
||||
memmove(new_table, table_, top_ * sizeof(intptr_t));
|
||||
memset(new_table + top_, 0, (new_capacity - top_) * sizeof(intptr_t));
|
||||
#ifndef PRODUCT
|
||||
@@ -250,10 +276,22 @@ void SharedClassTable::Grow(intptr_t new_capacity) {
|
||||
new_table[i] = 0;
|
||||
NOT_IN_PRODUCT(new_stats_table[i] = 0);
|
||||
}
|
||||
|
||||
capacity_ = new_capacity;
|
||||
old_tables_->Add(table_);
|
||||
table_ = new_table; // TODO(koda): This should use atomics.
|
||||
NOT_IN_PRODUCT(trace_allocation_table_ = new_stats_table);
|
||||
|
||||
#if defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
auto new_unboxed_fields_map = static_cast<UnboxedFieldBitmap*>(
|
||||
malloc(new_capacity * sizeof(UnboxedFieldBitmap)));
|
||||
memmove(new_unboxed_fields_map, unboxed_fields_map_,
|
||||
top_ * sizeof(UnboxedFieldBitmap));
|
||||
memset(new_unboxed_fields_map + top_, 0,
|
||||
(new_capacity - top_) * sizeof(UnboxedFieldBitmap));
|
||||
old_unboxed_fields_maps_->Add(unboxed_fields_map_);
|
||||
unboxed_fields_map_ = new_unboxed_fields_map;
|
||||
#endif // defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
}
|
||||
|
||||
void ClassTable::Unregister(intptr_t index) {
|
||||
@@ -263,6 +301,9 @@ void ClassTable::Unregister(intptr_t index) {
|
||||
|
||||
void SharedClassTable::Unregister(intptr_t index) {
|
||||
table_[index] = 0;
|
||||
#if defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
unboxed_fields_map_[index].Reset();
|
||||
#endif // defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
}
|
||||
|
||||
void ClassTable::Remap(intptr_t* old_to_new_cid) {
|
||||
@@ -281,14 +322,24 @@ void ClassTable::Remap(intptr_t* old_to_new_cid) {
|
||||
void SharedClassTable::Remap(intptr_t* old_to_new_cid) {
|
||||
ASSERT(Thread::Current()->IsAtSafepoint());
|
||||
const intptr_t num_cids = NumCids();
|
||||
intptr_t* cls_by_old_cid = new intptr_t[num_cids];
|
||||
std::unique_ptr<intptr_t[]> cls_by_old_cid(new intptr_t[num_cids]);
|
||||
for (intptr_t i = 0; i < num_cids; i++) {
|
||||
cls_by_old_cid[i] = table_[i];
|
||||
}
|
||||
for (intptr_t i = 0; i < num_cids; i++) {
|
||||
table_[old_to_new_cid[i]] = cls_by_old_cid[i];
|
||||
}
|
||||
delete[] cls_by_old_cid;
|
||||
|
||||
#if defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
std::unique_ptr<UnboxedFieldBitmap[]> unboxed_fields_by_old_cid(
|
||||
new UnboxedFieldBitmap[num_cids]);
|
||||
for (intptr_t i = 0; i < num_cids; i++) {
|
||||
unboxed_fields_by_old_cid[i] = unboxed_fields_map_[i];
|
||||
}
|
||||
for (intptr_t i = 0; i < num_cids; i++) {
|
||||
unboxed_fields_map_[old_to_new_cid[i]] = unboxed_fields_by_old_cid[i];
|
||||
}
|
||||
#endif // defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
}
|
||||
|
||||
void ClassTable::VisitObjectPointers(ObjectPointerVisitor* visitor) {
|
||||
@@ -344,7 +395,8 @@ void ClassTable::Print() {
|
||||
void ClassTable::SetAt(intptr_t index, RawClass* raw_cls) {
|
||||
// This is called by snapshot reader and class finalizer.
|
||||
ASSERT(index < capacity_);
|
||||
const intptr_t size = raw_cls == nullptr ? 0 : Class::instance_size(raw_cls);
|
||||
const intptr_t size =
|
||||
raw_cls == nullptr ? 0 : Class::host_instance_size(raw_cls);
|
||||
shared_class_table_->SetSizeAt(index, size);
|
||||
table_[index] = raw_cls;
|
||||
}
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/atomic.h"
|
||||
#include "platform/utils.h"
|
||||
|
||||
#include "vm/bitfield.h"
|
||||
#include "vm/class_id.h"
|
||||
#include "vm/flags.h"
|
||||
#include "vm/globals.h"
|
||||
|
||||
namespace dart {
|
||||
@@ -28,6 +30,33 @@ class MallocGrowableArray;
|
||||
class ObjectPointerVisitor;
|
||||
class RawClass;
|
||||
|
||||
// Wraps a 64-bit integer to represent the bitmap of unboxed fields
|
||||
// stored in the shared class table.
|
||||
class UnboxedFieldBitmap {
|
||||
public:
|
||||
UnboxedFieldBitmap() : bitmap_(0) {}
|
||||
explicit UnboxedFieldBitmap(uint64_t bitmap) : bitmap_(bitmap) {}
|
||||
UnboxedFieldBitmap(const UnboxedFieldBitmap&) = default;
|
||||
UnboxedFieldBitmap& operator=(const UnboxedFieldBitmap&) = default;
|
||||
|
||||
DART_FORCE_INLINE bool Get(intptr_t position) const {
|
||||
return Utils::TestBit(bitmap_, position);
|
||||
}
|
||||
DART_FORCE_INLINE void Set(intptr_t position) {
|
||||
bitmap_ |= Utils::Bit<decltype(bitmap_)>(position);
|
||||
}
|
||||
DART_FORCE_INLINE uint64_t Value() const { return bitmap_; }
|
||||
DART_FORCE_INLINE bool IsEmpty() const { return bitmap_ == 0; }
|
||||
DART_FORCE_INLINE void Reset() { bitmap_ = 0; }
|
||||
|
||||
DART_FORCE_INLINE static constexpr intptr_t Length() {
|
||||
return sizeof(decltype(bitmap_)) * kBitsPerByte;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t bitmap_;
|
||||
};
|
||||
|
||||
// Registry of all known classes and their sizes.
|
||||
//
|
||||
// The GC will only need the information in this shared class table to scan
|
||||
@@ -62,6 +91,19 @@ class SharedClassTable {
|
||||
intptr_t NumCids() const { return top_; }
|
||||
intptr_t Capacity() const { return capacity_; }
|
||||
|
||||
UnboxedFieldBitmap GetUnboxedFieldsMapAt(intptr_t index) const {
|
||||
ASSERT(IsValidIndex(index));
|
||||
return FLAG_precompiled_mode ? unboxed_fields_map_[index]
|
||||
: UnboxedFieldBitmap();
|
||||
}
|
||||
|
||||
void SetUnboxedFieldsMapAt(intptr_t index,
|
||||
UnboxedFieldBitmap unboxed_fields_map) {
|
||||
ASSERT(IsValidIndex(index));
|
||||
ASSERT(unboxed_fields_map_[index].IsEmpty());
|
||||
unboxed_fields_map_[index] = unboxed_fields_map;
|
||||
}
|
||||
|
||||
// Used to drop recently added classes.
|
||||
void SetNumCids(intptr_t num_cids) {
|
||||
ASSERT(num_cids <= top_);
|
||||
@@ -117,6 +159,9 @@ class SharedClassTable {
|
||||
// Deallocates table copies. Do not call during concurrent access to table.
|
||||
void FreeOldTables();
|
||||
|
||||
// Deallocates bitmap copies. Do not call during concurrent access to table.
|
||||
void FreeOldUnboxedFieldsMaps();
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
bool IsReloading() const { return reload_context_ != nullptr; }
|
||||
|
||||
@@ -171,6 +216,14 @@ class SharedClassTable {
|
||||
|
||||
IsolateGroupReloadContext* reload_context_ = nullptr;
|
||||
|
||||
// Stores a 64-bit bitmap for each class. There is one bit for each word in an
|
||||
// instance of the class. A 0 bit indicates that the word contains a pointer
|
||||
// the GC has to scan, a 1 indicates that the word is part of e.g. an unboxed
|
||||
// double and does not need to be scanned. (see Class::Calculate...() where
|
||||
// the bitmap is constructed)
|
||||
UnboxedFieldBitmap* unboxed_fields_map_;
|
||||
MallocGrowableArray<UnboxedFieldBitmap*>* old_unboxed_fields_maps_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SharedClassTable);
|
||||
};
|
||||
|
||||
|
||||
@@ -182,19 +182,57 @@ class ClassSerializationCluster : public SerializationCluster {
|
||||
if (s->kind() != Snapshot::kFullAOT) {
|
||||
s->Write<uint32_t>(cls->ptr()->binary_declaration_);
|
||||
}
|
||||
s->Write<int32_t>(cls->ptr()->instance_size_in_words_);
|
||||
s->Write<int32_t>(cls->ptr()->next_field_offset_in_words_);
|
||||
s->Write<int32_t>(cls->ptr()->type_arguments_field_offset_in_words_);
|
||||
s->Write<int32_t>(Class::target_instance_size_in_words(cls));
|
||||
s->Write<int32_t>(Class::target_next_field_offset_in_words(cls));
|
||||
s->Write<int32_t>(Class::target_type_arguments_field_offset_in_words(cls));
|
||||
s->Write<int16_t>(cls->ptr()->num_type_arguments_);
|
||||
s->Write<uint16_t>(cls->ptr()->num_native_fields_);
|
||||
s->WriteTokenPosition(cls->ptr()->token_pos_);
|
||||
s->WriteTokenPosition(cls->ptr()->end_token_pos_);
|
||||
s->Write<uint32_t>(cls->ptr()->state_bits_);
|
||||
|
||||
// In AOT, the bitmap of unboxed fields should also be serialized
|
||||
if (FLAG_precompiled_mode) {
|
||||
s->WriteUnsigned64(
|
||||
CalculateTargetUnboxedFieldsBitmap(s, class_id).Value());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
GrowableArray<RawClass*> predefined_;
|
||||
GrowableArray<RawClass*> objects_;
|
||||
|
||||
UnboxedFieldBitmap CalculateTargetUnboxedFieldsBitmap(Serializer* s,
|
||||
intptr_t class_id) {
|
||||
const auto unboxed_fields_bitmap_host =
|
||||
s->isolate()->shared_class_table()->GetUnboxedFieldsMapAt(class_id);
|
||||
|
||||
UnboxedFieldBitmap unboxed_fields_bitmap;
|
||||
if (unboxed_fields_bitmap_host.IsEmpty() ||
|
||||
kWordSize == compiler::target::kWordSize) {
|
||||
unboxed_fields_bitmap = unboxed_fields_bitmap_host;
|
||||
} else {
|
||||
ASSERT(kWordSize == 8 && compiler::target::kWordSize == 4);
|
||||
// A new bitmap is built if the word sizes in the target and
|
||||
// host are different
|
||||
unboxed_fields_bitmap.Reset();
|
||||
intptr_t target_i = 0, host_i = 0;
|
||||
|
||||
while (host_i < UnboxedFieldBitmap::Length()) {
|
||||
// Each unboxed field has constant length, therefore the number of
|
||||
// words used by it should double when compiling from 64-bit to 32-bit.
|
||||
if (unboxed_fields_bitmap_host.Get(host_i++)) {
|
||||
unboxed_fields_bitmap.Set(target_i++);
|
||||
unboxed_fields_bitmap.Set(target_i++);
|
||||
} else {
|
||||
// For object pointers, the field is always one word length
|
||||
target_i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return unboxed_fields_bitmap;
|
||||
}
|
||||
};
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
|
||||
@@ -240,18 +278,35 @@ class ClassDeserializationCluster : public DeserializationCluster {
|
||||
}
|
||||
#endif
|
||||
if (!RawObject::IsInternalVMdefinedClassId(class_id)) {
|
||||
cls->ptr()->instance_size_in_words_ = d->Read<int32_t>();
|
||||
cls->ptr()->next_field_offset_in_words_ = d->Read<int32_t>();
|
||||
cls->ptr()->host_instance_size_in_words_ = d->Read<int32_t>();
|
||||
cls->ptr()->host_next_field_offset_in_words_ = d->Read<int32_t>();
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
// Only one pair is serialized. The target field only exists when
|
||||
// DART_PRECOMPILED_RUNTIME is not defined
|
||||
cls->ptr()->target_instance_size_in_words_ =
|
||||
cls->ptr()->host_instance_size_in_words_;
|
||||
cls->ptr()->target_next_field_offset_in_words_ =
|
||||
cls->ptr()->host_next_field_offset_in_words_;
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
} else {
|
||||
d->Read<int32_t>(); // Skip.
|
||||
d->Read<int32_t>(); // Skip.
|
||||
}
|
||||
cls->ptr()->type_arguments_field_offset_in_words_ = d->Read<int32_t>();
|
||||
cls->ptr()->host_type_arguments_field_offset_in_words_ =
|
||||
d->Read<int32_t>();
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
cls->ptr()->target_type_arguments_field_offset_in_words_ =
|
||||
cls->ptr()->host_type_arguments_field_offset_in_words_;
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
cls->ptr()->num_type_arguments_ = d->Read<int16_t>();
|
||||
cls->ptr()->num_native_fields_ = d->Read<uint16_t>();
|
||||
cls->ptr()->token_pos_ = d->ReadTokenPosition();
|
||||
cls->ptr()->end_token_pos_ = d->ReadTokenPosition();
|
||||
cls->ptr()->state_bits_ = d->Read<uint32_t>();
|
||||
|
||||
if (FLAG_precompiled_mode) {
|
||||
d->ReadUnsigned64(); // Skip unboxed fields bitmap.
|
||||
}
|
||||
}
|
||||
|
||||
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
||||
@@ -268,9 +323,18 @@ class ClassDeserializationCluster : public DeserializationCluster {
|
||||
cls->ptr()->binary_declaration_ = d->Read<uint32_t>();
|
||||
}
|
||||
#endif
|
||||
cls->ptr()->instance_size_in_words_ = d->Read<int32_t>();
|
||||
cls->ptr()->next_field_offset_in_words_ = d->Read<int32_t>();
|
||||
cls->ptr()->type_arguments_field_offset_in_words_ = d->Read<int32_t>();
|
||||
cls->ptr()->host_instance_size_in_words_ = d->Read<int32_t>();
|
||||
cls->ptr()->host_next_field_offset_in_words_ = d->Read<int32_t>();
|
||||
cls->ptr()->host_type_arguments_field_offset_in_words_ =
|
||||
d->Read<int32_t>();
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
cls->ptr()->target_instance_size_in_words_ =
|
||||
cls->ptr()->host_instance_size_in_words_;
|
||||
cls->ptr()->target_next_field_offset_in_words_ =
|
||||
cls->ptr()->host_next_field_offset_in_words_;
|
||||
cls->ptr()->target_type_arguments_field_offset_in_words_ =
|
||||
cls->ptr()->host_type_arguments_field_offset_in_words_;
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
cls->ptr()->num_type_arguments_ = d->Read<int16_t>();
|
||||
cls->ptr()->num_native_fields_ = d->Read<uint16_t>();
|
||||
cls->ptr()->token_pos_ = d->ReadTokenPosition();
|
||||
@@ -279,6 +343,12 @@ class ClassDeserializationCluster : public DeserializationCluster {
|
||||
|
||||
table->AllocateIndex(class_id);
|
||||
table->SetAt(class_id, cls);
|
||||
|
||||
if (FLAG_precompiled_mode) {
|
||||
const UnboxedFieldBitmap unboxed_fields_map(d->ReadUnsigned64());
|
||||
d->isolate()->shared_class_table()->SetUnboxedFieldsMapAt(
|
||||
class_id, unboxed_fields_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -935,13 +1005,13 @@ class FieldSerializationCluster : public SerializationCluster {
|
||||
kind == Snapshot::kFullAOT ||
|
||||
// Do not reset const fields.
|
||||
Field::ConstBit::decode(field->ptr()->kind_bits_)) {
|
||||
s->Push(s->field_table()->At(field->ptr()->offset_or_field_id_));
|
||||
s->Push(s->field_table()->At(field->ptr()->host_offset_or_field_id_));
|
||||
} else {
|
||||
// Otherwise, for static fields we write out the initial static value.
|
||||
s->Push(field->ptr()->saved_initial_value_);
|
||||
}
|
||||
} else {
|
||||
s->Push(Smi::New(field->ptr()->offset_or_field_id_));
|
||||
s->Push(Smi::New(Field::TargetOffsetOf(field)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1001,14 +1071,14 @@ class FieldSerializationCluster : public SerializationCluster {
|
||||
Field::ConstBit::decode(field->ptr()->kind_bits_)) {
|
||||
WriteFieldValue(
|
||||
"static value",
|
||||
s->field_table()->At(field->ptr()->offset_or_field_id_));
|
||||
s->field_table()->At(field->ptr()->host_offset_or_field_id_));
|
||||
} else {
|
||||
// Otherwise, for static fields we write out the initial static value.
|
||||
WriteFieldValue("static value", field->ptr()->saved_initial_value_);
|
||||
}
|
||||
s->WriteUnsigned(field->ptr()->offset_or_field_id_);
|
||||
s->WriteUnsigned(field->ptr()->host_offset_or_field_id_);
|
||||
} else {
|
||||
WriteFieldValue("offset", Smi::New(field->ptr()->offset_or_field_id_));
|
||||
WriteFieldValue("offset", Smi::New(Field::TargetOffsetOf(field)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1057,10 +1127,13 @@ class FieldDeserializationCluster : public DeserializationCluster {
|
||||
intptr_t field_id = d->ReadUnsigned();
|
||||
d->field_table()->SetAt(
|
||||
field_id, reinterpret_cast<RawInstance*>(value_or_offset));
|
||||
field->ptr()->offset_or_field_id_ = field_id;
|
||||
field->ptr()->host_offset_or_field_id_ = field_id;
|
||||
} else {
|
||||
field->ptr()->offset_or_field_id_ =
|
||||
field->ptr()->host_offset_or_field_id_ =
|
||||
Smi::Value(Smi::RawCast(value_or_offset));
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
field->ptr()->target_offset_ = field->ptr()->host_offset_or_field_id_;
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2722,23 +2795,34 @@ class InstanceSerializationCluster : public SerializationCluster {
|
||||
explicit InstanceSerializationCluster(intptr_t cid)
|
||||
: SerializationCluster("Instance"), cid_(cid) {
|
||||
RawClass* cls = Isolate::Current()->class_table()->At(cid);
|
||||
next_field_offset_in_words_ = cls->ptr()->next_field_offset_in_words_;
|
||||
instance_size_in_words_ = cls->ptr()->instance_size_in_words_;
|
||||
ASSERT(next_field_offset_in_words_ > 0);
|
||||
ASSERT(instance_size_in_words_ > 0);
|
||||
host_next_field_offset_in_words_ =
|
||||
cls->ptr()->host_next_field_offset_in_words_;
|
||||
ASSERT(host_next_field_offset_in_words_ > 0);
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
target_next_field_offset_in_words_ =
|
||||
cls->ptr()->target_next_field_offset_in_words_;
|
||||
target_instance_size_in_words_ = cls->ptr()->target_instance_size_in_words_;
|
||||
ASSERT(target_next_field_offset_in_words_ > 0);
|
||||
ASSERT(target_instance_size_in_words_ > 0);
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
~InstanceSerializationCluster() {}
|
||||
|
||||
void Trace(Serializer* s, RawObject* object) {
|
||||
RawInstance* instance = Instance::RawCast(object);
|
||||
objects_.Add(instance);
|
||||
|
||||
intptr_t next_field_offset = next_field_offset_in_words_ << kWordSizeLog2;
|
||||
const intptr_t next_field_offset = host_next_field_offset_in_words_
|
||||
<< kWordSizeLog2;
|
||||
const auto unboxed_fields_bitmap =
|
||||
s->isolate()->shared_class_table()->GetUnboxedFieldsMapAt(cid_);
|
||||
intptr_t offset = Instance::NextFieldOffset();
|
||||
while (offset < next_field_offset) {
|
||||
RawObject* raw_obj = *reinterpret_cast<RawObject**>(
|
||||
reinterpret_cast<uword>(instance->ptr()) + offset);
|
||||
s->Push(raw_obj);
|
||||
// Skips unboxed fields
|
||||
if (!unboxed_fields_bitmap.Get(offset / kWordSize)) {
|
||||
RawObject* raw_obj = *reinterpret_cast<RawObject**>(
|
||||
reinterpret_cast<uword>(instance->ptr()) + offset);
|
||||
s->Push(raw_obj);
|
||||
}
|
||||
offset += kWordSize;
|
||||
}
|
||||
}
|
||||
@@ -2748,8 +2832,12 @@ class InstanceSerializationCluster : public SerializationCluster {
|
||||
const intptr_t count = objects_.length();
|
||||
s->WriteUnsigned(count);
|
||||
|
||||
s->Write<int32_t>(next_field_offset_in_words_);
|
||||
s->Write<int32_t>(instance_size_in_words_);
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
s->Write<int32_t>(target_next_field_offset_in_words_);
|
||||
s->Write<int32_t>(target_instance_size_in_words_);
|
||||
#else
|
||||
s->Write<int32_t>(host_next_field_offset_in_words_);
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
RawInstance* instance = objects_[i];
|
||||
@@ -2758,17 +2846,28 @@ class InstanceSerializationCluster : public SerializationCluster {
|
||||
}
|
||||
|
||||
void WriteFill(Serializer* s) {
|
||||
intptr_t next_field_offset = next_field_offset_in_words_ << kWordSizeLog2;
|
||||
intptr_t next_field_offset = host_next_field_offset_in_words_
|
||||
<< kWordSizeLog2;
|
||||
const intptr_t count = objects_.length();
|
||||
const auto shared_class_table = s->isolate()->shared_class_table();
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
RawInstance* instance = objects_[i];
|
||||
AutoTraceObject(instance);
|
||||
s->Write<bool>(instance->IsCanonical());
|
||||
const auto unboxed_fields_bitmap =
|
||||
shared_class_table->GetUnboxedFieldsMapAt(cid_);
|
||||
intptr_t offset = Instance::NextFieldOffset();
|
||||
while (offset < next_field_offset) {
|
||||
RawObject* raw_obj = *reinterpret_cast<RawObject**>(
|
||||
reinterpret_cast<uword>(instance->ptr()) + offset);
|
||||
s->WriteElementRef(raw_obj, offset);
|
||||
if (unboxed_fields_bitmap.Get(offset / kWordSize)) {
|
||||
// Writes 32 bits of the unboxed value at a time
|
||||
const uword value = *reinterpret_cast<uword*>(
|
||||
reinterpret_cast<uword>(instance->ptr()) + offset);
|
||||
s->WriteWordWith32BitWrites(value);
|
||||
} else {
|
||||
RawObject* raw_obj = *reinterpret_cast<RawObject**>(
|
||||
reinterpret_cast<uword>(instance->ptr()) + offset);
|
||||
s->WriteElementRef(raw_obj, offset);
|
||||
}
|
||||
offset += kWordSize;
|
||||
}
|
||||
}
|
||||
@@ -2776,8 +2875,11 @@ class InstanceSerializationCluster : public SerializationCluster {
|
||||
|
||||
private:
|
||||
const intptr_t cid_;
|
||||
intptr_t next_field_offset_in_words_;
|
||||
intptr_t instance_size_in_words_;
|
||||
intptr_t host_next_field_offset_in_words_;
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
intptr_t target_next_field_offset_in_words_;
|
||||
intptr_t target_instance_size_in_words_;
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
GrowableArray<RawInstance*> objects_;
|
||||
};
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
@@ -2806,16 +2908,26 @@ class InstanceDeserializationCluster : public DeserializationCluster {
|
||||
intptr_t instance_size =
|
||||
Object::RoundedAllocationSize(instance_size_in_words_ * kWordSize);
|
||||
|
||||
const auto shared_class_table = d->isolate()->shared_class_table();
|
||||
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(d->Ref(id));
|
||||
bool is_canonical = d->Read<bool>();
|
||||
Deserializer::InitializeHeader(instance, cid_, instance_size,
|
||||
is_canonical);
|
||||
const auto unboxed_fields_bitmap =
|
||||
shared_class_table->GetUnboxedFieldsMapAt(cid_);
|
||||
intptr_t offset = Instance::NextFieldOffset();
|
||||
while (offset < next_field_offset) {
|
||||
RawObject** p = reinterpret_cast<RawObject**>(
|
||||
reinterpret_cast<uword>(instance->ptr()) + offset);
|
||||
*p = d->ReadRef();
|
||||
if (unboxed_fields_bitmap.Get(offset / kWordSize)) {
|
||||
uword* p = reinterpret_cast<uword*>(
|
||||
reinterpret_cast<uword>(instance->ptr()) + offset);
|
||||
// Reads 32 bits of the unboxed value at a time
|
||||
*p = d->ReadWordWith32BitReads();
|
||||
} else {
|
||||
RawObject** p = reinterpret_cast<RawObject**>(
|
||||
reinterpret_cast<uword>(instance->ptr()) + offset);
|
||||
*p = d->ReadRef();
|
||||
}
|
||||
offset += kWordSize;
|
||||
}
|
||||
if (offset < instance_size) {
|
||||
|
||||
@@ -234,6 +234,12 @@ class Serializer : public ThreadStackResource {
|
||||
WriteStream::Raw<sizeof(T), T>::Write(&stream_, value);
|
||||
}
|
||||
void WriteUnsigned(intptr_t value) { stream_.WriteUnsigned(value); }
|
||||
void WriteUnsigned64(uint64_t value) { stream_.WriteUnsigned(value); }
|
||||
|
||||
void WriteWordWith32BitWrites(uword value) {
|
||||
stream_.WriteWordWith32BitWrites(value);
|
||||
}
|
||||
|
||||
void WriteBytes(const uint8_t* addr, intptr_t len) {
|
||||
stream_.WriteBytes(addr, len);
|
||||
}
|
||||
@@ -496,8 +502,11 @@ class Deserializer : public ThreadStackResource {
|
||||
return ReadStream::Raw<sizeof(T), T>::Read(&stream_);
|
||||
}
|
||||
intptr_t ReadUnsigned() { return stream_.ReadUnsigned(); }
|
||||
uint64_t ReadUnsigned64() { return stream_.ReadUnsigned<uint64_t>(); }
|
||||
void ReadBytes(uint8_t* addr, intptr_t len) { stream_.ReadBytes(addr, len); }
|
||||
|
||||
uword ReadWordWith32BitReads() { return stream_.ReadWordWith32BitReads(); }
|
||||
|
||||
const uint8_t* CurrentBufferAddress() const {
|
||||
return stream_.AddressOfCurrentPosition();
|
||||
}
|
||||
|
||||
@@ -5498,7 +5498,7 @@ class AllocateObjectInstr : public AllocationInstr {
|
||||
}
|
||||
|
||||
static bool WillAllocateNewOrRemembered(const Class& cls) {
|
||||
return Heap::IsAllocatableInNewSpace(cls.instance_size());
|
||||
return Heap::IsAllocatableInNewSpace(cls.target_instance_size());
|
||||
}
|
||||
|
||||
PRINT_OPERANDS_TO_SUPPORT
|
||||
|
||||
@@ -2557,7 +2557,8 @@ LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
const intptr_t kNumInputs = 2;
|
||||
const intptr_t kNumTemps =
|
||||
((IsUnboxedStore() && opt) ? 2 : ((IsPotentialUnboxedStore()) ? 3 : 0));
|
||||
((IsUnboxedStore() && opt) ? (FLAG_precompiled_mode ? 0 : 2)
|
||||
: (IsPotentialUnboxedStore() ? 3 : 0));
|
||||
LocationSummary* summary = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps,
|
||||
((IsUnboxedStore() && opt && is_initialization()) ||
|
||||
@@ -2568,8 +2569,10 @@ LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
summary->set_in(0, Location::RequiresRegister());
|
||||
if (IsUnboxedStore() && opt) {
|
||||
summary->set_in(1, Location::RequiresFpuRegister());
|
||||
summary->set_temp(0, Location::RequiresRegister());
|
||||
summary->set_temp(1, Location::RequiresRegister());
|
||||
if (!FLAG_precompiled_mode) {
|
||||
summary->set_temp(0, Location::RequiresRegister());
|
||||
summary->set_temp(1, Location::RequiresRegister());
|
||||
}
|
||||
} else if (IsPotentialUnboxedStore()) {
|
||||
summary->set_in(1, ShouldEmitStoreBarrier() ? Location::WritableRegister()
|
||||
: Location::RequiresRegister());
|
||||
@@ -2615,10 +2618,33 @@ void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(offset_in_bytes > 0); // Field is finalized and points after header.
|
||||
|
||||
if (IsUnboxedStore() && compiler->is_optimizing()) {
|
||||
const intptr_t cid = slot().field().UnboxedFieldCid();
|
||||
const DRegister value = EvenDRegisterOf(locs()->in(1).fpu_reg());
|
||||
|
||||
if (FLAG_precompiled_mode) {
|
||||
switch (cid) {
|
||||
case kDoubleCid:
|
||||
__ Comment("UnboxedDoubleStoreInstanceFieldInstr");
|
||||
__ StoreDToOffset(value, instance_reg,
|
||||
offset_in_bytes - kHeapObjectTag);
|
||||
return;
|
||||
case kFloat32x4Cid:
|
||||
__ Comment("UnboxedFloat32x4StoreInstanceFieldInstr");
|
||||
__ StoreMultipleDToOffset(value, 2, instance_reg,
|
||||
offset_in_bytes - kHeapObjectTag);
|
||||
return;
|
||||
case kFloat64x2Cid:
|
||||
__ Comment("UnboxedFloat64x2StoreInstanceFieldInstr");
|
||||
__ StoreMultipleDToOffset(value, 2, instance_reg,
|
||||
offset_in_bytes - kHeapObjectTag);
|
||||
return;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
const Register temp = locs()->temp(0).reg();
|
||||
const Register temp2 = locs()->temp(1).reg();
|
||||
const intptr_t cid = slot().field().UnboxedFieldCid();
|
||||
|
||||
if (is_initialization()) {
|
||||
const Class* cls = NULL;
|
||||
@@ -2963,8 +2989,9 @@ void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps =
|
||||
(IsUnboxedLoad() && opt) ? 1 : ((IsPotentialUnboxedLoad()) ? 3 : 0);
|
||||
const intptr_t kNumTemps = (IsUnboxedLoad() && opt)
|
||||
? (FLAG_precompiled_mode ? 0 : 1)
|
||||
: (IsPotentialUnboxedLoad() ? 3 : 0);
|
||||
|
||||
LocationSummary* locs = new (zone) LocationSummary(
|
||||
zone, kNumInputs, kNumTemps,
|
||||
@@ -2974,7 +3001,9 @@ LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
locs->set_in(0, Location::RequiresRegister());
|
||||
|
||||
if (IsUnboxedLoad() && opt) {
|
||||
locs->set_temp(0, Location::RequiresRegister());
|
||||
if (!FLAG_precompiled_mode) {
|
||||
locs->set_temp(0, Location::RequiresRegister());
|
||||
}
|
||||
} else if (IsPotentialUnboxedLoad()) {
|
||||
locs->set_temp(0, opt ? Location::RequiresFpuRegister()
|
||||
: Location::FpuRegisterLocation(Q1));
|
||||
@@ -2990,10 +3019,33 @@ void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
|
||||
const Register instance_reg = locs()->in(0).reg();
|
||||
if (IsUnboxedLoad() && compiler->is_optimizing()) {
|
||||
const intptr_t cid = slot().field().UnboxedFieldCid();
|
||||
const DRegister result = EvenDRegisterOf(locs()->out(0).fpu_reg());
|
||||
|
||||
if (FLAG_precompiled_mode) {
|
||||
switch (cid) {
|
||||
case kDoubleCid:
|
||||
__ Comment("UnboxedDoubleLoadFieldInstr");
|
||||
__ LoadDFromOffset(result, instance_reg,
|
||||
OffsetInBytes() - kHeapObjectTag);
|
||||
return;
|
||||
case kFloat32x4Cid:
|
||||
__ Comment("UnboxedFloat32x4LoadFieldInstr");
|
||||
__ LoadMultipleDFromOffset(result, 2, instance_reg,
|
||||
OffsetInBytes() - kHeapObjectTag);
|
||||
return;
|
||||
case kFloat64x2Cid:
|
||||
__ Comment("UnboxedFloat64x2LoadFieldInstr");
|
||||
__ LoadMultipleDFromOffset(result, 2, instance_reg,
|
||||
OffsetInBytes() - kHeapObjectTag);
|
||||
return;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
const Register temp = locs()->temp(0).reg();
|
||||
__ LoadFieldFromOffset(kWord, temp, instance_reg, OffsetInBytes());
|
||||
const intptr_t cid = slot().field().UnboxedFieldCid();
|
||||
switch (cid) {
|
||||
case kDoubleCid:
|
||||
__ Comment("UnboxedDoubleLoadFieldInstr");
|
||||
@@ -3320,7 +3372,7 @@ void InitInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
Register temp = locs()->temp(0).reg();
|
||||
compiler::Label no_call;
|
||||
|
||||
__ ldr(temp, compiler::FieldAddress(instance, field().Offset()));
|
||||
__ ldr(temp, compiler::FieldAddress(instance, field().TargetOffset()));
|
||||
__ CompareObject(temp, Object::sentinel());
|
||||
__ b(&no_call, NE);
|
||||
|
||||
|
||||
@@ -2158,8 +2158,9 @@ static void EnsureMutableBox(FlowGraphCompiler* compiler,
|
||||
LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
const intptr_t kNumInputs = 2;
|
||||
const intptr_t kNumTemps =
|
||||
(IsUnboxedStore() && opt) ? 2 : ((IsPotentialUnboxedStore()) ? 2 : 0);
|
||||
const intptr_t kNumTemps = (IsUnboxedStore() && opt)
|
||||
? (FLAG_precompiled_mode ? 0 : 2)
|
||||
: (IsPotentialUnboxedStore() ? 2 : 0);
|
||||
LocationSummary* summary = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps,
|
||||
((IsUnboxedStore() && opt && is_initialization()) ||
|
||||
@@ -2170,8 +2171,10 @@ LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
summary->set_in(0, Location::RequiresRegister());
|
||||
if (IsUnboxedStore() && opt) {
|
||||
summary->set_in(1, Location::RequiresFpuRegister());
|
||||
summary->set_temp(0, Location::RequiresRegister());
|
||||
summary->set_temp(1, Location::RequiresRegister());
|
||||
if (!FLAG_precompiled_mode) {
|
||||
summary->set_temp(0, Location::RequiresRegister());
|
||||
summary->set_temp(1, Location::RequiresRegister());
|
||||
}
|
||||
} else if (IsPotentialUnboxedStore()) {
|
||||
summary->set_in(1, ShouldEmitStoreBarrier() ? Location::WritableRegister()
|
||||
: Location::RequiresRegister());
|
||||
@@ -2195,9 +2198,29 @@ void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
|
||||
if (IsUnboxedStore() && compiler->is_optimizing()) {
|
||||
const VRegister value = locs()->in(1).fpu_reg();
|
||||
const intptr_t cid = slot().field().UnboxedFieldCid();
|
||||
|
||||
if (FLAG_precompiled_mode) {
|
||||
switch (cid) {
|
||||
case kDoubleCid:
|
||||
__ Comment("UnboxedDoubleStoreInstanceFieldInstr");
|
||||
__ StoreDFieldToOffset(value, instance_reg, offset_in_bytes);
|
||||
return;
|
||||
case kFloat32x4Cid:
|
||||
__ Comment("UnboxedFloat32x4StoreInstanceFieldInstr");
|
||||
__ StoreQFieldToOffset(value, instance_reg, offset_in_bytes);
|
||||
return;
|
||||
case kFloat64x2Cid:
|
||||
__ Comment("UnboxedFloat64x2StoreInstanceFieldInstr");
|
||||
__ StoreQFieldToOffset(value, instance_reg, offset_in_bytes);
|
||||
return;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
const Register temp = locs()->temp(0).reg();
|
||||
const Register temp2 = locs()->temp(1).reg();
|
||||
const intptr_t cid = slot().field().UnboxedFieldCid();
|
||||
|
||||
if (is_initialization()) {
|
||||
const Class* cls = NULL;
|
||||
@@ -2534,8 +2557,9 @@ void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps =
|
||||
(IsUnboxedLoad() && opt) ? 1 : ((IsPotentialUnboxedLoad()) ? 1 : 0);
|
||||
const intptr_t kNumTemps = (IsUnboxedLoad() && opt)
|
||||
? (FLAG_precompiled_mode ? 0 : 1)
|
||||
: (IsPotentialUnboxedLoad() ? 1 : 0);
|
||||
LocationSummary* locs = new (zone) LocationSummary(
|
||||
zone, kNumInputs, kNumTemps,
|
||||
(opt && !IsPotentialUnboxedLoad()) ? LocationSummary::kNoCall
|
||||
@@ -2544,7 +2568,9 @@ LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
locs->set_in(0, Location::RequiresRegister());
|
||||
|
||||
if (IsUnboxedLoad() && opt) {
|
||||
locs->set_temp(0, Location::RequiresRegister());
|
||||
if (!FLAG_precompiled_mode) {
|
||||
locs->set_temp(0, Location::RequiresRegister());
|
||||
}
|
||||
} else if (IsPotentialUnboxedLoad()) {
|
||||
locs->set_temp(0, Location::RequiresRegister());
|
||||
}
|
||||
@@ -2557,9 +2583,30 @@ void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
const Register instance_reg = locs()->in(0).reg();
|
||||
if (IsUnboxedLoad() && compiler->is_optimizing()) {
|
||||
const VRegister result = locs()->out(0).fpu_reg();
|
||||
const Register temp = locs()->temp(0).reg();
|
||||
__ LoadFieldFromOffset(temp, instance_reg, OffsetInBytes());
|
||||
const intptr_t cid = slot().field().UnboxedFieldCid();
|
||||
|
||||
if (FLAG_precompiled_mode) {
|
||||
switch (cid) {
|
||||
case kDoubleCid:
|
||||
__ Comment("UnboxedDoubleLoadFieldInstr");
|
||||
__ LoadDFieldFromOffset(result, instance_reg, OffsetInBytes());
|
||||
return;
|
||||
case kFloat32x4Cid:
|
||||
__ Comment("UnboxedFloat32x4LoadFieldInstr");
|
||||
__ LoadQFieldFromOffset(result, instance_reg, OffsetInBytes());
|
||||
return;
|
||||
case kFloat64x2Cid:
|
||||
__ Comment("UnboxedFloat64x2LoadFieldInstr");
|
||||
__ LoadQFieldFromOffset(result, instance_reg, OffsetInBytes());
|
||||
return;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
const Register temp = locs()->temp(0).reg();
|
||||
|
||||
__ LoadFieldFromOffset(temp, instance_reg, OffsetInBytes());
|
||||
switch (cid) {
|
||||
case kDoubleCid:
|
||||
__ Comment("UnboxedDoubleLoadFieldInstr");
|
||||
@@ -2875,7 +2922,7 @@ void InitInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
Register temp = locs()->temp(0).reg();
|
||||
compiler::Label no_call;
|
||||
|
||||
__ ldr(temp, compiler::FieldAddress(instance, field().Offset()));
|
||||
__ ldr(temp, compiler::FieldAddress(instance, field().TargetOffset()));
|
||||
__ CompareObject(temp, Object::sentinel());
|
||||
__ b(&no_call, NE);
|
||||
|
||||
|
||||
@@ -2753,7 +2753,7 @@ void InitInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
|
||||
compiler::Label no_call;
|
||||
|
||||
__ movl(temp, compiler::FieldAddress(instance, field().Offset()));
|
||||
__ movl(temp, compiler::FieldAddress(instance, field().TargetOffset()));
|
||||
__ CompareObject(temp, Object::sentinel());
|
||||
__ j(NOT_EQUAL, &no_call, compiler::Assembler::kNearJump);
|
||||
|
||||
|
||||
@@ -1308,7 +1308,7 @@ void AllocateObjectInstr::AddExtraInfoToSExpression(
|
||||
SExpList* sexp,
|
||||
FlowGraphSerializer* s) const {
|
||||
Instruction::AddExtraInfoToSExpression(sexp, s);
|
||||
s->AddExtraInteger(sexp, "size", cls().instance_size());
|
||||
s->AddExtraInteger(sexp, "size", cls().target_instance_size());
|
||||
if (auto const closure = s->DartValueToSExp(closure_function())) {
|
||||
sexp->AddExtra("closure_function", closure);
|
||||
}
|
||||
|
||||
@@ -2128,8 +2128,9 @@ void GuardFieldTypeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
const intptr_t kNumInputs = 2;
|
||||
const intptr_t kNumTemps =
|
||||
(IsUnboxedStore() && opt) ? 2 : ((IsPotentialUnboxedStore()) ? 3 : 0);
|
||||
const intptr_t kNumTemps = (IsUnboxedStore() && opt)
|
||||
? (FLAG_precompiled_mode ? 0 : 2)
|
||||
: (IsPotentialUnboxedStore() ? 3 : 0);
|
||||
LocationSummary* summary = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps,
|
||||
((IsUnboxedStore() && opt && is_initialization()) ||
|
||||
@@ -2140,8 +2141,10 @@ LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
summary->set_in(0, Location::RequiresRegister());
|
||||
if (IsUnboxedStore() && opt) {
|
||||
summary->set_in(1, Location::RequiresFpuRegister());
|
||||
summary->set_temp(0, Location::RequiresRegister());
|
||||
summary->set_temp(1, Location::RequiresRegister());
|
||||
if (!FLAG_precompiled_mode) {
|
||||
summary->set_temp(0, Location::RequiresRegister());
|
||||
summary->set_temp(1, Location::RequiresRegister());
|
||||
}
|
||||
} else if (IsPotentialUnboxedStore()) {
|
||||
summary->set_in(1, ShouldEmitStoreBarrier() ? Location::WritableRegister()
|
||||
: Location::RequiresRegister());
|
||||
@@ -2186,9 +2189,33 @@ void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
|
||||
if (IsUnboxedStore() && compiler->is_optimizing()) {
|
||||
XmmRegister value = locs()->in(1).fpu_reg();
|
||||
const intptr_t cid = slot().field().UnboxedFieldCid();
|
||||
|
||||
// Real unboxed field
|
||||
if (FLAG_precompiled_mode) {
|
||||
switch (cid) {
|
||||
case kDoubleCid:
|
||||
__ Comment("UnboxedDoubleStoreInstanceFieldInstr");
|
||||
__ movsd(compiler::FieldAddress(instance_reg, offset_in_bytes),
|
||||
value);
|
||||
return;
|
||||
case kFloat32x4Cid:
|
||||
__ Comment("UnboxedFloat32x4StoreInstanceFieldInstr");
|
||||
__ movups(compiler::FieldAddress(instance_reg, offset_in_bytes),
|
||||
value);
|
||||
return;
|
||||
case kFloat64x2Cid:
|
||||
__ Comment("UnboxedFloat64x2StoreInstanceFieldInstr");
|
||||
__ movups(compiler::FieldAddress(instance_reg, offset_in_bytes),
|
||||
value);
|
||||
return;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
Register temp = locs()->temp(0).reg();
|
||||
Register temp2 = locs()->temp(1).reg();
|
||||
const intptr_t cid = slot().field().UnboxedFieldCid();
|
||||
|
||||
if (is_initialization()) {
|
||||
const Class* cls = NULL;
|
||||
@@ -2533,8 +2560,9 @@ void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps =
|
||||
(IsUnboxedLoad() && opt) ? 1 : ((IsPotentialUnboxedLoad()) ? 2 : 0);
|
||||
const intptr_t kNumTemps = (IsUnboxedLoad() && opt)
|
||||
? (FLAG_precompiled_mode ? 0 : 1)
|
||||
: (IsPotentialUnboxedLoad() ? 2 : 0);
|
||||
LocationSummary* locs = new (zone) LocationSummary(
|
||||
zone, kNumInputs, kNumTemps,
|
||||
(opt && !IsPotentialUnboxedLoad()) ? LocationSummary::kNoCall
|
||||
@@ -2543,7 +2571,9 @@ LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
locs->set_in(0, Location::RequiresRegister());
|
||||
|
||||
if (IsUnboxedLoad() && opt) {
|
||||
locs->set_temp(0, Location::RequiresRegister());
|
||||
if (!FLAG_precompiled_mode) {
|
||||
locs->set_temp(0, Location::RequiresRegister());
|
||||
}
|
||||
} else if (IsPotentialUnboxedLoad()) {
|
||||
locs->set_temp(0, opt ? Location::RequiresFpuRegister()
|
||||
: Location::FpuRegisterLocation(XMM1));
|
||||
@@ -2558,9 +2588,34 @@ void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
Register instance_reg = locs()->in(0).reg();
|
||||
if (IsUnboxedLoad() && compiler->is_optimizing()) {
|
||||
XmmRegister result = locs()->out(0).fpu_reg();
|
||||
const intptr_t cid = slot().field().UnboxedFieldCid();
|
||||
|
||||
// Real unboxed field
|
||||
if (FLAG_precompiled_mode) {
|
||||
switch (cid) {
|
||||
case kDoubleCid:
|
||||
__ Comment("UnboxedDoubleLoadFieldInstr");
|
||||
__ movsd(result,
|
||||
compiler::FieldAddress(instance_reg, OffsetInBytes()));
|
||||
break;
|
||||
case kFloat32x4Cid:
|
||||
__ Comment("UnboxedFloat32x4LoadFieldInstr");
|
||||
__ movups(result,
|
||||
compiler::FieldAddress(instance_reg, OffsetInBytes()));
|
||||
break;
|
||||
case kFloat64x2Cid:
|
||||
__ Comment("UnboxedFloat64x2LoadFieldInstr");
|
||||
__ movups(result,
|
||||
compiler::FieldAddress(instance_reg, OffsetInBytes()));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Register temp = locs()->temp(0).reg();
|
||||
__ movq(temp, compiler::FieldAddress(instance_reg, OffsetInBytes()));
|
||||
intptr_t cid = slot().field().UnboxedFieldCid();
|
||||
switch (cid) {
|
||||
case kDoubleCid:
|
||||
__ Comment("UnboxedDoubleLoadFieldInstr");
|
||||
@@ -2890,7 +2945,7 @@ void InitInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
|
||||
compiler::Label no_call;
|
||||
|
||||
__ movq(temp, compiler::FieldAddress(instance, field().Offset()));
|
||||
__ movq(temp, compiler::FieldAddress(instance, field().TargetOffset()));
|
||||
__ CompareObject(temp, Object::sentinel());
|
||||
__ j(NOT_EQUAL, &no_call, compiler::Assembler::kNearJump);
|
||||
|
||||
|
||||
@@ -1151,7 +1151,7 @@ void BytecodeFlowGraphBuilder::BuildCreateArrayTOS() {
|
||||
}
|
||||
|
||||
const Slot& ClosureSlotByField(const Field& field) {
|
||||
const intptr_t offset = field.Offset();
|
||||
const intptr_t offset = field.HostOffset();
|
||||
if (offset == Closure::instantiator_type_arguments_offset()) {
|
||||
return Slot::Closure_instantiator_type_arguments();
|
||||
} else if (offset == Closure::function_type_arguments_offset()) {
|
||||
@@ -1178,7 +1178,7 @@ void BytecodeFlowGraphBuilder::BuildStoreFieldTOS() {
|
||||
|
||||
const Field& field = Field::Cast(ConstantAt(cp_index, 1).value());
|
||||
ASSERT(Smi::Cast(ConstantAt(cp_index).value()).Value() * kWordSize ==
|
||||
field.Offset());
|
||||
field.HostOffset());
|
||||
|
||||
if (field.Owner() == isolate()->object_store()->closure_class()) {
|
||||
// Stores to _Closure fields are lower-level.
|
||||
@@ -1204,7 +1204,7 @@ void BytecodeFlowGraphBuilder::BuildLoadFieldTOS() {
|
||||
|
||||
const Field& field = Field::Cast(ConstantAt(cp_index, 1).value());
|
||||
ASSERT(Smi::Cast(ConstantAt(cp_index).value()).Value() * kWordSize ==
|
||||
field.Offset());
|
||||
field.HostOffset());
|
||||
|
||||
if (field.Owner() == isolate()->object_store()->closure_class()) {
|
||||
// Loads from _Closure fields are lower-level.
|
||||
@@ -1292,7 +1292,7 @@ void BytecodeFlowGraphBuilder::BuildInitLateField() {
|
||||
|
||||
const Field& field = Field::Cast(ConstantAt(cp_index, 1).value());
|
||||
ASSERT(Smi::Cast(ConstantAt(cp_index).value()).Value() * kWordSize ==
|
||||
field.Offset());
|
||||
field.HostOffset());
|
||||
|
||||
code_ += B->Constant(Object::sentinel());
|
||||
code_ += B->StoreInstanceField(
|
||||
|
||||
@@ -748,7 +748,7 @@ intptr_t BytecodeReaderHelper::ReadConstantPool(const Function& function,
|
||||
field ^= ReadObject();
|
||||
// InstanceField constant occupies 2 entries.
|
||||
// The first entry is used for field offset.
|
||||
obj = Smi::New(field.Offset() / kWordSize);
|
||||
obj = Smi::New(field.HostOffset() / kWordSize);
|
||||
pool.SetTypeAt(i, ObjectPool::EntryType::kTaggedObject,
|
||||
ObjectPool::Patchability::kNotPatchable);
|
||||
pool.SetObjectAt(i, obj);
|
||||
@@ -763,7 +763,7 @@ intptr_t BytecodeReaderHelper::ReadConstantPool(const Function& function,
|
||||
break;
|
||||
case ConstantPoolTag::kTypeArgumentsField:
|
||||
cls ^= ReadObject();
|
||||
obj = Smi::New(cls.type_arguments_field_offset() / kWordSize);
|
||||
obj = Smi::New(cls.host_type_arguments_field_offset() / kWordSize);
|
||||
break;
|
||||
case ConstantPoolTag::kType:
|
||||
obj = ReadObject();
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/compiler/runtime_api.h"
|
||||
#include "platform/utils.h"
|
||||
|
||||
namespace dart {
|
||||
namespace compiler {
|
||||
@@ -199,7 +198,7 @@ const Field& LookupMathRandomStateFieldOffset() {
|
||||
}
|
||||
|
||||
word LookupFieldOffsetInBytes(const Field& field) {
|
||||
return field.Offset();
|
||||
return field.TargetOffset();
|
||||
}
|
||||
|
||||
#if defined(TARGET_ARCH_IA32)
|
||||
@@ -337,10 +336,10 @@ static uword GetInstanceSizeImpl(const dart::Class& handle) {
|
||||
case kExternalTypedData##clazz##Cid:
|
||||
CLASS_LIST_TYPED_DATA(HANDLE_CASE)
|
||||
#undef HANDLE_CASE
|
||||
return TranslateOffsetInWords(handle.instance_size());
|
||||
return handle.target_instance_size();
|
||||
default:
|
||||
if (handle.id() >= kNumPredefinedCids) {
|
||||
return TranslateOffsetInWords(handle.instance_size());
|
||||
return handle.target_instance_size();
|
||||
}
|
||||
}
|
||||
FATAL3("Unsupported class for size translation: %s (id=%" Pd
|
||||
@@ -359,11 +358,12 @@ intptr_t Class::NumTypeArguments(const dart::Class& klass) {
|
||||
}
|
||||
|
||||
bool Class::HasTypeArgumentsField(const dart::Class& klass) {
|
||||
return klass.type_arguments_field_offset() != dart::Class::kNoTypeArguments;
|
||||
return klass.host_type_arguments_field_offset() !=
|
||||
dart::Class::kNoTypeArguments;
|
||||
}
|
||||
|
||||
intptr_t Class::TypeArgumentsFieldOffset(const dart::Class& klass) {
|
||||
return TranslateOffsetInWords(klass.type_arguments_field_offset());
|
||||
return klass.target_type_arguments_field_offset();
|
||||
}
|
||||
|
||||
bool Class::TraceAllocation(const dart::Class& klass) {
|
||||
@@ -643,7 +643,7 @@ bool Heap::IsAllocatableInNewSpace(intptr_t instance_size) {
|
||||
}
|
||||
|
||||
word Field::OffsetOf(const dart::Field& field) {
|
||||
return TranslateOffsetInWords(field.Offset());
|
||||
return field.TargetOffset();
|
||||
}
|
||||
|
||||
word FieldTable::OffsetOf(const dart::Field& field) {
|
||||
@@ -651,6 +651,314 @@ word FieldTable::OffsetOf(const dart::Field& field) {
|
||||
dart::FieldTable::FieldOffsetFor(field.field_id()));
|
||||
}
|
||||
|
||||
word FreeListElement::FakeInstance::InstanceSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
word ForwardingCorpse::FakeInstance::InstanceSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
word Instance::NextFieldOffset() {
|
||||
return TranslateOffsetInWords(dart::Instance::NextFieldOffset());
|
||||
}
|
||||
|
||||
word Pointer::NextFieldOffset() {
|
||||
return TranslateOffsetInWords(dart::Pointer::NextFieldOffset());
|
||||
}
|
||||
|
||||
word ObjectPool::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Class::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Function::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word ICData::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word MegamorphicCache::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word SingleTargetCache::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Array::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word GrowableObjectArray::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word TypedDataBase::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word TypedData::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word ExternalTypedData::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word TypedDataView::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word LinkedHashMap::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Type::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word TypeRef::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Double::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Mint::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word String::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word OneByteString::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word TwoByteString::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word ExternalOneByteString::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word ExternalTwoByteString::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Int32x4::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Float32x4::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Float64x2::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word DynamicLibrary::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word PatchClass::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word SignatureData::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word RedirectionData::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word FfiTrampolineData::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Script::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Library::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Namespace::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word KernelProgramInfo::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Bytecode::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word PcDescriptors::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word CodeSourceMap::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word CompressedStackMaps::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word LocalVarDescriptors::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word ExceptionHandlers::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word ContextScope::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word ParameterTypeCheck::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word UnlinkedCall::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word ApiError::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word LanguageError::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word UnhandledException::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word UnwindError::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Bool::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word TypeParameter::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word LibraryPrefix::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Capability::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word ReceivePort::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word SendPort::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word TransferableTypedData::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word StackTrace::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Integer::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Smi::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word WeakProperty::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word MirrorReference::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Number::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word MonomorphicSmiableCall::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Instructions::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Code::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word SubtypeTestCache::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Context::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Closure::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word ClosureData::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word RegExp::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word UserTag::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Field::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word TypeArguments::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word FreeListElement::FakeInstance::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word ForwardingCorpse::FakeInstance::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
} // namespace target
|
||||
} // namespace compiler
|
||||
} // namespace dart
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
// in compiler::target namespace.
|
||||
|
||||
#include "platform/globals.h"
|
||||
#include "platform/utils.h"
|
||||
#include "vm/allocation.h"
|
||||
#include "vm/bitfield.h"
|
||||
#include "vm/bss_relocs.h"
|
||||
@@ -285,6 +286,11 @@ extern const word kPageSize;
|
||||
extern const word kPageSizeInWords;
|
||||
extern const word kPageMask;
|
||||
|
||||
static constexpr intptr_t kObjectAlignment = ObjectAlignment::kObjectAlignment;
|
||||
|
||||
inline intptr_t RoundedAllocationSize(intptr_t size) {
|
||||
return Utils::RoundUp(size, kObjectAlignment);
|
||||
}
|
||||
// Information about frame_layout that compiler should be targeting.
|
||||
extern FrameLayout frame_layout;
|
||||
|
||||
@@ -376,11 +382,15 @@ class ObjectPool : public AllStatic {
|
||||
public:
|
||||
// Return offset to the element with the given [index] in the object pool.
|
||||
static word element_offset(intptr_t index);
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Class : public AllStatic {
|
||||
public:
|
||||
static word type_arguments_field_offset_in_words_offset();
|
||||
static word host_type_arguments_field_offset_in_words_offset();
|
||||
|
||||
static word target_type_arguments_field_offset_in_words_offset();
|
||||
|
||||
static word declaration_type_offset();
|
||||
|
||||
@@ -392,6 +402,10 @@ class Class : public AllStatic {
|
||||
// The value used if no type arguments vector is present.
|
||||
static const word kNoTypeArguments;
|
||||
|
||||
static word InstanceSize();
|
||||
|
||||
static word NextFieldOffset();
|
||||
|
||||
// Return class id of the given class on the target.
|
||||
static classid_t GetId(const dart::Class& handle);
|
||||
|
||||
@@ -418,6 +432,7 @@ class Instance : public AllStatic {
|
||||
static word DataOffsetFor(intptr_t cid);
|
||||
static word ElementSizeFor(intptr_t cid);
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Function : public AllStatic {
|
||||
@@ -425,6 +440,8 @@ class Function : public AllStatic {
|
||||
static word code_offset();
|
||||
static word entry_point_offset(CodeEntryKind kind = CodeEntryKind::kNormal);
|
||||
static word usage_counter_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class ICData : public AllStatic {
|
||||
@@ -443,6 +460,8 @@ class ICData : public AllStatic {
|
||||
static word EntryPointIndexFor(word num_args);
|
||||
static word NumArgsTestedShift();
|
||||
static word NumArgsTestedMask();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class MegamorphicCache : public AllStatic {
|
||||
@@ -451,6 +470,8 @@ class MegamorphicCache : public AllStatic {
|
||||
static word mask_offset();
|
||||
static word buckets_offset();
|
||||
static word arguments_descriptor_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class SingleTargetCache : public AllStatic {
|
||||
@@ -459,6 +480,8 @@ class SingleTargetCache : public AllStatic {
|
||||
static word upper_limit_offset();
|
||||
static word entry_point_offset();
|
||||
static word target_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Array : public AllStatic {
|
||||
@@ -469,6 +492,8 @@ class Array : public AllStatic {
|
||||
static word type_arguments_offset();
|
||||
static word length_offset();
|
||||
static word element_offset(intptr_t index);
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
|
||||
static const word kMaxElements;
|
||||
static const word kMaxNewSpaceElements;
|
||||
@@ -480,6 +505,7 @@ class GrowableObjectArray : public AllStatic {
|
||||
static word type_arguments_offset();
|
||||
static word length_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class TypedDataBase : public AllStatic {
|
||||
@@ -487,23 +513,29 @@ class TypedDataBase : public AllStatic {
|
||||
static word data_field_offset();
|
||||
static word length_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class TypedData : public AllStatic {
|
||||
public:
|
||||
static word data_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class ExternalTypedData : public AllStatic {
|
||||
public:
|
||||
static word data_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class TypedDataView : public AllStatic {
|
||||
public:
|
||||
static word offset_in_bytes_offset();
|
||||
static word data_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class LinkedHashMap : public AllStatic {
|
||||
@@ -513,7 +545,9 @@ class LinkedHashMap : public AllStatic {
|
||||
static word hash_mask_offset();
|
||||
static word used_data_offset();
|
||||
static word deleted_keys_offset();
|
||||
static word type_arguments_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class ArgumentsDescriptor : public AllStatic {
|
||||
@@ -530,6 +564,9 @@ class ArgumentsDescriptor : public AllStatic {
|
||||
class Pointer : public AllStatic {
|
||||
public:
|
||||
static word c_memory_address_offset();
|
||||
static word type_arguments_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class AbstractType : public AllStatic {
|
||||
@@ -545,11 +582,15 @@ class Type : public AllStatic {
|
||||
static word signature_offset();
|
||||
static word type_class_id_offset();
|
||||
static word nullability_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class TypeRef : public AllStatic {
|
||||
public:
|
||||
static word type_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Nullability : public AllStatic {
|
||||
@@ -564,12 +605,14 @@ class Double : public AllStatic {
|
||||
public:
|
||||
static word value_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Mint : public AllStatic {
|
||||
public:
|
||||
static word value_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class String : public AllStatic {
|
||||
@@ -579,43 +622,265 @@ class String : public AllStatic {
|
||||
static word hash_offset();
|
||||
static word length_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class OneByteString : public AllStatic {
|
||||
public:
|
||||
static word data_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class TwoByteString : public AllStatic {
|
||||
public:
|
||||
static word data_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class ExternalOneByteString : public AllStatic {
|
||||
public:
|
||||
static word external_data_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class ExternalTwoByteString : public AllStatic {
|
||||
public:
|
||||
static word external_data_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Int32x4 : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Float32x4 : public AllStatic {
|
||||
public:
|
||||
static word value_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Float64x2 : public AllStatic {
|
||||
public:
|
||||
static word value_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class DynamicLibrary : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class PatchClass : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class SignatureData : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class RedirectionData : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class FfiTrampolineData : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Script : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Library : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Namespace : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class KernelProgramInfo : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Bytecode : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class PcDescriptors : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class CodeSourceMap : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class CompressedStackMaps : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class LocalVarDescriptors : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class ExceptionHandlers : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class ContextScope : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class ParameterTypeCheck : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class UnlinkedCall : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class ApiError : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class LanguageError : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class UnhandledException : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class UnwindError : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Bool : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class TypeParameter : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class LibraryPrefix : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Capability : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class ReceivePort : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class SendPort : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class TransferableTypedData : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class StackTrace : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Integer : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Smi : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class WeakProperty : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class MirrorReference : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Number : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class TimelineStream : public AllStatic {
|
||||
@@ -633,6 +898,8 @@ class MonomorphicSmiableCall : public AllStatic {
|
||||
static word expected_cid_offset();
|
||||
static word entrypoint_offset();
|
||||
static word target_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Thread : public AllStatic {
|
||||
@@ -803,6 +1070,8 @@ class Instructions : public AllStatic {
|
||||
static const word kPolymorphicEntryOffsetAOT;
|
||||
static word HeaderSize();
|
||||
static word UnalignedHeaderSize();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Code : public AllStatic {
|
||||
@@ -815,6 +1084,8 @@ class Code : public AllStatic {
|
||||
static word entry_point_offset(CodeEntryKind kind = CodeEntryKind::kNormal);
|
||||
static word saved_instructions_offset();
|
||||
static word owner_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class SubtypeTestCache : public AllStatic {
|
||||
@@ -829,6 +1100,8 @@ class SubtypeTestCache : public AllStatic {
|
||||
static const word kInstanceParentFunctionTypeArguments;
|
||||
static const word kInstanceDelayedFunctionTypeArguments;
|
||||
static const word kTestResult;
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Context : public AllStatic {
|
||||
@@ -838,6 +1111,8 @@ class Context : public AllStatic {
|
||||
static word num_variables_offset();
|
||||
static word variable_offset(word i);
|
||||
static word InstanceSize(word n);
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Closure : public AllStatic {
|
||||
@@ -849,6 +1124,13 @@ class Closure : public AllStatic {
|
||||
static word instantiator_type_arguments_offset();
|
||||
static word hash_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class ClosureData : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class HeapPage : public AllStatic {
|
||||
@@ -883,11 +1165,15 @@ class NativeEntry {
|
||||
class RegExp : public AllStatic {
|
||||
public:
|
||||
static word function_offset(classid_t cid, bool sticky);
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class UserTag : public AllStatic {
|
||||
public:
|
||||
static word tag_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Symbols : public AllStatic {
|
||||
@@ -906,12 +1192,34 @@ class Field : public AllStatic {
|
||||
static word is_nullable_offset();
|
||||
static word static_value_offset();
|
||||
static word kind_bits_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class TypeArguments : public AllStatic {
|
||||
public:
|
||||
static word instantiations_offset();
|
||||
static word type_at_offset(intptr_t i);
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class FreeListElement : public AllStatic {
|
||||
public:
|
||||
class FakeInstance : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
};
|
||||
|
||||
class ForwardingCorpse : public AllStatic {
|
||||
public:
|
||||
class FakeInstance : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
};
|
||||
|
||||
class FieldTable : public AllStatic {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -64,7 +64,7 @@
|
||||
FIELD(Class, declaration_type_offset) \
|
||||
FIELD(Class, num_type_arguments_offset) \
|
||||
FIELD(Class, super_type_offset) \
|
||||
FIELD(Class, type_arguments_field_offset_in_words_offset) \
|
||||
FIELD(Class, host_type_arguments_field_offset_in_words_offset) \
|
||||
FIELD(ClassTable, shared_class_table_offset) \
|
||||
FIELD(ClassTable, table_offset) \
|
||||
NOT_IN_PRODUCT(FIELD(SharedClassTable, class_heap_stats_table_offset)) \
|
||||
@@ -115,6 +115,7 @@
|
||||
FIELD(LinkedHashMap, deleted_keys_offset) \
|
||||
FIELD(LinkedHashMap, hash_mask_offset) \
|
||||
FIELD(LinkedHashMap, index_offset) \
|
||||
FIELD(LinkedHashMap, type_arguments_offset) \
|
||||
FIELD(LinkedHashMap, used_data_offset) \
|
||||
FIELD(MarkingStackBlock, pointers_offset) \
|
||||
FIELD(MarkingStackBlock, top_offset) \
|
||||
@@ -131,6 +132,7 @@
|
||||
FIELD(ObjectStore, string_type_offset) \
|
||||
FIELD(OneByteString, data_offset) \
|
||||
FIELD(Pointer, c_memory_address_offset) \
|
||||
FIELD(Pointer, type_arguments_offset) \
|
||||
FIELD(SingleTargetCache, entry_point_offset) \
|
||||
FIELD(SingleTargetCache, lower_limit_offset) \
|
||||
FIELD(SingleTargetCache, target_offset) \
|
||||
@@ -251,22 +253,84 @@
|
||||
Thread, write_barrier_wrappers_thread_offset, Register, 0, \
|
||||
kNumberOfCpuRegisters - 1, \
|
||||
[](Register reg) { return (kDartAvailableCpuRegs & (1 << reg)) != 0; })) \
|
||||
\
|
||||
SIZEOF(ApiError, InstanceSize, RawApiError) \
|
||||
SIZEOF(Array, InstanceSize, RawArray) \
|
||||
SIZEOF(Array, header_size, RawArray) \
|
||||
SIZEOF(Bool, InstanceSize, RawBool) \
|
||||
SIZEOF(Bytecode, InstanceSize, RawBytecode) \
|
||||
SIZEOF(Capability, InstanceSize, RawCapability) \
|
||||
SIZEOF(Class, InstanceSize, RawClass) \
|
||||
SIZEOF(Closure, InstanceSize, RawClosure) \
|
||||
SIZEOF(ClosureData, InstanceSize, RawClosureData) \
|
||||
SIZEOF(Code, InstanceSize, RawCode) \
|
||||
SIZEOF(CodeSourceMap, InstanceSize, RawCodeSourceMap) \
|
||||
SIZEOF(CompressedStackMaps, InstanceSize, RawCompressedStackMaps) \
|
||||
SIZEOF(Context, InstanceSize, RawContext) \
|
||||
SIZEOF(Context, header_size, RawContext) \
|
||||
SIZEOF(ContextScope, InstanceSize, RawContextScope) \
|
||||
SIZEOF(Double, InstanceSize, RawDouble) \
|
||||
SIZEOF(DynamicLibrary, InstanceSize, RawDynamicLibrary) \
|
||||
SIZEOF(ExceptionHandlers, InstanceSize, RawExceptionHandlers) \
|
||||
SIZEOF(ExternalOneByteString, InstanceSize, RawExternalOneByteString) \
|
||||
SIZEOF(ExternalTwoByteString, InstanceSize, RawExternalTwoByteString) \
|
||||
SIZEOF(ExternalTypedData, InstanceSize, RawExternalTypedData) \
|
||||
SIZEOF(FfiTrampolineData, InstanceSize, RawFfiTrampolineData) \
|
||||
SIZEOF(Field, InstanceSize, RawField) \
|
||||
SIZEOF(Float32x4, InstanceSize, RawFloat32x4) \
|
||||
SIZEOF(Float64x2, InstanceSize, RawFloat64x2) \
|
||||
SIZEOF(Function, InstanceSize, RawFunction) \
|
||||
SIZEOF(GrowableObjectArray, InstanceSize, RawGrowableObjectArray) \
|
||||
SIZEOF(ICData, InstanceSize, RawICData) \
|
||||
SIZEOF(Instance, InstanceSize, RawInstance) \
|
||||
SIZEOF(Instructions, InstanceSize, RawInstructions) \
|
||||
SIZEOF(Instructions, UnalignedHeaderSize, RawInstructions) \
|
||||
SIZEOF(Int32x4, InstanceSize, RawInt32x4) \
|
||||
SIZEOF(Integer, InstanceSize, RawInteger) \
|
||||
SIZEOF(KernelProgramInfo, InstanceSize, RawKernelProgramInfo) \
|
||||
SIZEOF(LanguageError, InstanceSize, RawLanguageError) \
|
||||
SIZEOF(Library, InstanceSize, RawLibrary) \
|
||||
SIZEOF(LibraryPrefix, InstanceSize, RawLibraryPrefix) \
|
||||
SIZEOF(LinkedHashMap, InstanceSize, RawLinkedHashMap) \
|
||||
SIZEOF(LocalVarDescriptors, InstanceSize, RawLocalVarDescriptors) \
|
||||
SIZEOF(MegamorphicCache, InstanceSize, RawMegamorphicCache) \
|
||||
SIZEOF(Mint, InstanceSize, RawMint) \
|
||||
SIZEOF(MirrorReference, InstanceSize, RawMirrorReference) \
|
||||
SIZEOF(MonomorphicSmiableCall, InstanceSize, RawMonomorphicSmiableCall) \
|
||||
SIZEOF(Namespace, InstanceSize, RawNamespace) \
|
||||
SIZEOF(NativeArguments, StructSize, NativeArguments) \
|
||||
SIZEOF(String, InstanceSize, RawString) \
|
||||
SIZEOF(TypedData, InstanceSize, RawTypedData) \
|
||||
SIZEOF(Number, InstanceSize, RawNumber) \
|
||||
SIZEOF(Object, InstanceSize, RawObject) \
|
||||
SIZEOF(ObjectPool, InstanceSize, RawObjectPool) \
|
||||
SIZEOF(OneByteString, InstanceSize, RawOneByteString) \
|
||||
SIZEOF(ParameterTypeCheck, InstanceSize, RawParameterTypeCheck) \
|
||||
SIZEOF(PatchClass, InstanceSize, RawPatchClass) \
|
||||
SIZEOF(PcDescriptors, InstanceSize, RawPcDescriptors) \
|
||||
SIZEOF(Pointer, InstanceSize, RawPointer) \
|
||||
SIZEOF(ReceivePort, InstanceSize, RawReceivePort) \
|
||||
SIZEOF(RedirectionData, InstanceSize, RawRedirectionData) \
|
||||
SIZEOF(RegExp, InstanceSize, RawRegExp) \
|
||||
SIZEOF(Script, InstanceSize, RawScript) \
|
||||
SIZEOF(SendPort, InstanceSize, RawSendPort) \
|
||||
SIZEOF(SignatureData, InstanceSize, RawSignatureData) \
|
||||
SIZEOF(SingleTargetCache, InstanceSize, RawSingleTargetCache) \
|
||||
SIZEOF(Smi, InstanceSize, RawSmi) \
|
||||
SIZEOF(StackTrace, InstanceSize, RawStackTrace) \
|
||||
SIZEOF(String, InstanceSize, RawString) \
|
||||
SIZEOF(SubtypeTestCache, InstanceSize, RawSubtypeTestCache) \
|
||||
SIZEOF(TransferableTypedData, InstanceSize, RawTransferableTypedData) \
|
||||
SIZEOF(TwoByteString, InstanceSize, RawTwoByteString) \
|
||||
SIZEOF(Type, InstanceSize, RawType) \
|
||||
SIZEOF(TypeArguments, InstanceSize, RawTypeArguments) \
|
||||
SIZEOF(TypeParameter, InstanceSize, RawTypeParameter) \
|
||||
SIZEOF(TypeRef, InstanceSize, RawTypeRef) \
|
||||
SIZEOF(TypedData, InstanceSize, RawTypedData) \
|
||||
SIZEOF(TypedDataBase, InstanceSize, RawTypedDataBase) \
|
||||
SIZEOF(Closure, InstanceSize, RawClosure) \
|
||||
SIZEOF(GrowableObjectArray, InstanceSize, RawGrowableObjectArray) \
|
||||
SIZEOF(Instance, InstanceSize, RawInstance) \
|
||||
SIZEOF(LinkedHashMap, InstanceSize, RawLinkedHashMap)
|
||||
SIZEOF(TypedDataView, InstanceSize, RawTypedDataView) \
|
||||
SIZEOF(UnhandledException, InstanceSize, RawUnhandledException) \
|
||||
SIZEOF(UnlinkedCall, InstanceSize, RawUnlinkedCall) \
|
||||
SIZEOF(UnwindError, InstanceSize, RawUnwindError) \
|
||||
SIZEOF(UserTag, InstanceSize, RawUserTag) \
|
||||
SIZEOF(WeakProperty, InstanceSize, RawWeakProperty)
|
||||
|
||||
#endif // RUNTIME_VM_COMPILER_RUNTIME_OFFSETS_LIST_H_
|
||||
|
||||
@@ -2726,8 +2726,8 @@ static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
|
||||
__ mov(kInstanceInstantiatorTypeArgumentsReg, Operand(kNullReg));
|
||||
__ ldr(R9,
|
||||
FieldAddress(
|
||||
R9,
|
||||
target::Class::type_arguments_field_offset_in_words_offset()));
|
||||
R9, target::Class::
|
||||
host_type_arguments_field_offset_in_words_offset()));
|
||||
__ CompareImmediate(R9, target::Class::kNoTypeArguments);
|
||||
__ b(&has_no_type_arguments, EQ);
|
||||
__ add(R9, kInstanceReg, Operand(R9, LSL, 2));
|
||||
|
||||
@@ -2851,7 +2851,8 @@ static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
|
||||
__ LoadClassById(R5, kInstanceCidOrFunction);
|
||||
__ mov(kInstanceInstantiatorTypeArgumentsReg, kNullReg);
|
||||
__ LoadFieldFromOffset(
|
||||
R5, R5, target::Class::type_arguments_field_offset_in_words_offset(),
|
||||
R5, R5,
|
||||
target::Class::host_type_arguments_field_offset_in_words_offset(),
|
||||
kWord);
|
||||
__ CompareImmediate(R5, target::Class::kNoTypeArguments);
|
||||
__ b(&has_no_type_arguments, EQ);
|
||||
|
||||
@@ -2349,11 +2349,10 @@ static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
|
||||
Label has_no_type_arguments;
|
||||
__ LoadClassById(EDI, kInstanceCidOrFunction);
|
||||
__ movl(kInstanceInstantiatorTypeArgumentsReg, raw_null);
|
||||
__ movl(
|
||||
EDI,
|
||||
FieldAddress(
|
||||
EDI,
|
||||
target::Class::type_arguments_field_offset_in_words_offset()));
|
||||
__ movl(EDI,
|
||||
FieldAddress(
|
||||
EDI, target::Class::
|
||||
host_type_arguments_field_offset_in_words_offset()));
|
||||
__ cmpl(EDI, Immediate(target::Class::kNoTypeArguments));
|
||||
__ j(EQUAL, &has_no_type_arguments, Assembler::kNearJump);
|
||||
__ movl(kInstanceInstantiatorTypeArgumentsReg,
|
||||
|
||||
@@ -2807,11 +2807,10 @@ static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
|
||||
Label has_no_type_arguments;
|
||||
__ LoadClassById(RDI, kInstanceCidOrFunction);
|
||||
__ movq(kInstanceInstantiatorTypeArgumentsReg, kNullReg);
|
||||
__ movl(
|
||||
RDI,
|
||||
FieldAddress(
|
||||
RDI,
|
||||
target::Class::type_arguments_field_offset_in_words_offset()));
|
||||
__ movl(RDI,
|
||||
FieldAddress(
|
||||
RDI, target::Class::
|
||||
host_type_arguments_field_offset_in_words_offset()));
|
||||
__ cmpl(RDI, Immediate(target::Class::kNoTypeArguments));
|
||||
__ j(EQUAL, &has_no_type_arguments, Assembler::kNearJump);
|
||||
__ movq(kInstanceInstantiatorTypeArgumentsReg,
|
||||
|
||||
@@ -4393,7 +4393,7 @@ TEST_CASE(DartAPI_InjectNativeFields3) {
|
||||
intptr_t header_size = sizeof(RawObject);
|
||||
EXPECT_EQ(
|
||||
Utils::RoundUp(((1 + 2) * kWordSize) + header_size, kObjectAlignment),
|
||||
cls.instance_size());
|
||||
cls.host_instance_size());
|
||||
EXPECT_EQ(kNumNativeFields, cls.num_native_fields());
|
||||
}
|
||||
|
||||
|
||||
+32
-3
@@ -72,7 +72,10 @@ class ReadStream : public ValueObject {
|
||||
current_ += len;
|
||||
}
|
||||
|
||||
intptr_t ReadUnsigned() { return Read<intptr_t>(kEndUnsignedByteMarker); }
|
||||
template <typename T = intptr_t>
|
||||
T ReadUnsigned() {
|
||||
return Read<T>(kEndUnsignedByteMarker);
|
||||
}
|
||||
|
||||
intptr_t Position() const { return current_ - buffer_; }
|
||||
void SetPosition(intptr_t value) {
|
||||
@@ -103,6 +106,19 @@ class ReadStream : public ValueObject {
|
||||
return Read<T>(kEndByteMarker);
|
||||
}
|
||||
|
||||
uword ReadWordWith32BitReads() {
|
||||
constexpr intptr_t kNumBytesPerRead32 = sizeof(uint32_t);
|
||||
constexpr intptr_t kNumRead32PerWord = sizeof(uword) / kNumBytesPerRead32;
|
||||
constexpr intptr_t kNumBitsPerRead32 = kNumBytesPerRead32 * kBitsPerByte;
|
||||
|
||||
uword value = 0;
|
||||
for (intptr_t j = 0; j < kNumRead32PerWord; j++) {
|
||||
const auto partial_value = Raw<kNumBytesPerRead32, uint32_t>::Read(this);
|
||||
value |= (static_cast<uword>(partial_value) << (j * kNumBitsPerRead32));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
int16_t Read16() { return Read16(kEndByteMarker); }
|
||||
|
||||
@@ -363,8 +379,21 @@ class WriteStream : public ValueObject {
|
||||
}
|
||||
};
|
||||
|
||||
void WriteUnsigned(intptr_t value) {
|
||||
ASSERT((value >= 0) && (value <= kIntptrMax));
|
||||
void WriteWordWith32BitWrites(uword value) {
|
||||
constexpr intptr_t kNumBytesPerWrite32 = sizeof(uint32_t);
|
||||
constexpr intptr_t kNumWrite32PerWord = sizeof(uword) / kNumBytesPerWrite32;
|
||||
constexpr intptr_t kNumBitsPerWrite32 = kNumBytesPerWrite32 * kBitsPerByte;
|
||||
|
||||
const uint32_t mask = Utils::NBitMask(kNumBitsPerWrite32);
|
||||
for (intptr_t j = 0; j < kNumWrite32PerWord; j++) {
|
||||
const uint32_t shifted_value = (value >> (j * kNumBitsPerWrite32));
|
||||
Raw<kNumBytesPerWrite32, uint32_t>::Write(this, shifted_value & mask);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void WriteUnsigned(T value) {
|
||||
ASSERT(value >= 0);
|
||||
while (value > kMaxUnsignedDataPerByte) {
|
||||
WriteByte(static_cast<uint8_t>(value & kByteMask));
|
||||
value = value >> kDataBitsPerByte;
|
||||
|
||||
@@ -307,7 +307,7 @@ void DeferredObject::Fill() {
|
||||
// materialization of e.g. _ByteDataView objects which don't have
|
||||
// explicit fields in Dart (all accesses to the fields are done via
|
||||
// recognized native methods).
|
||||
ASSERT(offset.Value() < cls.instance_size());
|
||||
ASSERT(offset.Value() < cls.host_instance_size());
|
||||
obj.SetFieldAtOffset(offset.Value(), value);
|
||||
if (FLAG_trace_deoptimization_verbose) {
|
||||
OS::PrintErr(" null Field @ offset(%" Pd ") <- %s\n",
|
||||
|
||||
@@ -137,7 +137,7 @@ class ScavengerVisitor : public ObjectPointerVisitor {
|
||||
view->RecomputeDataFieldForInternalTypedData();
|
||||
}
|
||||
|
||||
void VisitPointers(RawObject** first, RawObject** last) {
|
||||
virtual void VisitPointers(RawObject** first, RawObject** last) {
|
||||
ASSERT(Utils::IsAligned(first, sizeof(*first)));
|
||||
ASSERT(Utils::IsAligned(last, sizeof(*last)));
|
||||
for (RawObject** current = first; current <= last; current++) {
|
||||
|
||||
+17
-17
@@ -126,10 +126,9 @@ class InterpreterHelpers {
|
||||
RawClass* instance_class =
|
||||
thread->isolate()->class_table()->At(GetClassId(instance));
|
||||
return instance_class->ptr()->num_type_arguments_ > 0
|
||||
? reinterpret_cast<RawTypeArguments**>(
|
||||
instance
|
||||
->ptr())[instance_class->ptr()
|
||||
->type_arguments_field_offset_in_words_]
|
||||
? reinterpret_cast<RawTypeArguments**>(instance->ptr())
|
||||
[instance_class->ptr()
|
||||
->host_type_arguments_field_offset_in_words_]
|
||||
: TypeArguments::null();
|
||||
}
|
||||
|
||||
@@ -1205,7 +1204,7 @@ bool Interpreter::AssertAssignable(Thread* thread,
|
||||
} else if (instance_class->ptr()->num_type_arguments_ > 0) {
|
||||
instance_type_arguments = reinterpret_cast<RawTypeArguments**>(
|
||||
instance->ptr())[instance_class->ptr()
|
||||
->type_arguments_field_offset_in_words_];
|
||||
->host_type_arguments_field_offset_in_words_];
|
||||
}
|
||||
parent_function_type_arguments =
|
||||
static_cast<RawTypeArguments*>(null_value);
|
||||
@@ -2333,7 +2332,7 @@ SwitchDispatch:
|
||||
BYTECODE(InitLateField, D);
|
||||
RawField* field = RAW_CAST(Field, LOAD_CONSTANT(rD + 1));
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[0]);
|
||||
intptr_t offset_in_words = field->ptr()->offset_or_field_id_;
|
||||
intptr_t offset_in_words = field->ptr()->host_offset_or_field_id_;
|
||||
|
||||
instance->StorePointer(
|
||||
reinterpret_cast<RawObject**>(instance->ptr()) + offset_in_words,
|
||||
@@ -2362,7 +2361,7 @@ SwitchDispatch:
|
||||
BYTECODE(StoreStaticTOS, D);
|
||||
RawField* field = reinterpret_cast<RawField*>(LOAD_CONSTANT(rD));
|
||||
RawInstance* value = static_cast<RawInstance*>(*SP--);
|
||||
intptr_t field_id = field->ptr()->offset_or_field_id_;
|
||||
intptr_t field_id = field->ptr()->host_offset_or_field_id_;
|
||||
thread->field_table_values()[field_id] = value;
|
||||
DISPATCH();
|
||||
}
|
||||
@@ -2370,7 +2369,7 @@ SwitchDispatch:
|
||||
{
|
||||
BYTECODE(LoadStatic, D);
|
||||
RawField* field = reinterpret_cast<RawField*>(LOAD_CONSTANT(rD));
|
||||
intptr_t field_id = field->ptr()->offset_or_field_id_;
|
||||
intptr_t field_id = field->ptr()->host_offset_or_field_id_;
|
||||
RawInstance* value = thread->field_table_values()[field_id];
|
||||
ASSERT((value != Object::sentinel().raw()) &&
|
||||
(value != Object::transition_sentinel().raw()));
|
||||
@@ -2383,7 +2382,7 @@ SwitchDispatch:
|
||||
RawField* field = RAW_CAST(Field, LOAD_CONSTANT(rD + 1));
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[-1]);
|
||||
RawObject* value = reinterpret_cast<RawObject*>(SP[0]);
|
||||
intptr_t offset_in_words = field->ptr()->offset_or_field_id_;
|
||||
intptr_t offset_in_words = field->ptr()->host_offset_or_field_id_;
|
||||
|
||||
if (InterpreterHelpers::FieldNeedsGuardUpdate(field, value)) {
|
||||
SP[1] = 0; // Unused result of runtime call.
|
||||
@@ -2558,7 +2557,7 @@ SwitchDispatch:
|
||||
RawClass* cls = Class::RawCast(LOAD_CONSTANT(rD));
|
||||
if (LIKELY(InterpreterHelpers::IsFinalized(cls))) {
|
||||
const intptr_t class_id = cls->ptr()->id_;
|
||||
const intptr_t instance_size = cls->ptr()->instance_size_in_words_
|
||||
const intptr_t instance_size = cls->ptr()->host_instance_size_in_words_
|
||||
<< kWordSizeLog2;
|
||||
RawObject* result;
|
||||
if (TryAllocate(thread, class_id, instance_size, &result)) {
|
||||
@@ -2588,7 +2587,7 @@ SwitchDispatch:
|
||||
RawTypeArguments* type_args = TypeArguments::RawCast(SP[-1]);
|
||||
if (LIKELY(InterpreterHelpers::IsFinalized(cls))) {
|
||||
const intptr_t class_id = cls->ptr()->id_;
|
||||
const intptr_t instance_size = cls->ptr()->instance_size_in_words_
|
||||
const intptr_t instance_size = cls->ptr()->host_instance_size_in_words_
|
||||
<< kWordSizeLog2;
|
||||
RawObject* result;
|
||||
if (TryAllocate(thread, class_id, instance_size, &result)) {
|
||||
@@ -2598,7 +2597,8 @@ SwitchDispatch:
|
||||
*reinterpret_cast<RawObject**>(start + offset) = null_value;
|
||||
}
|
||||
const intptr_t type_args_offset =
|
||||
cls->ptr()->type_arguments_field_offset_in_words_ << kWordSizeLog2;
|
||||
cls->ptr()->host_type_arguments_field_offset_in_words_
|
||||
<< kWordSizeLog2;
|
||||
*reinterpret_cast<RawObject**>(start + type_args_offset) = type_args;
|
||||
*--SP = result;
|
||||
DISPATCH();
|
||||
@@ -3168,7 +3168,7 @@ SwitchDispatch:
|
||||
|
||||
// Field object is cached in function's data_.
|
||||
RawField* field = reinterpret_cast<RawField*>(function->ptr()->data_);
|
||||
intptr_t offset_in_words = field->ptr()->offset_or_field_id_;
|
||||
intptr_t offset_in_words = field->ptr()->host_offset_or_field_id_;
|
||||
|
||||
const intptr_t kArgc = 1;
|
||||
RawInstance* instance =
|
||||
@@ -3188,7 +3188,7 @@ SwitchDispatch:
|
||||
function = FrameFunction(FP);
|
||||
instance = reinterpret_cast<RawInstance*>(SP[2]);
|
||||
field = reinterpret_cast<RawField*>(SP[3]);
|
||||
offset_in_words = field->ptr()->offset_or_field_id_;
|
||||
offset_in_words = field->ptr()->host_offset_or_field_id_;
|
||||
value = reinterpret_cast<RawInstance**>(instance->ptr())[offset_in_words];
|
||||
}
|
||||
|
||||
@@ -3249,7 +3249,7 @@ SwitchDispatch:
|
||||
|
||||
// Field object is cached in function's data_.
|
||||
RawField* field = reinterpret_cast<RawField*>(function->ptr()->data_);
|
||||
intptr_t offset_in_words = field->ptr()->offset_or_field_id_;
|
||||
intptr_t offset_in_words = field->ptr()->host_offset_or_field_id_;
|
||||
const intptr_t kArgc = 2;
|
||||
RawInstance* instance =
|
||||
reinterpret_cast<RawInstance*>(FrameArguments(FP, kArgc)[0]);
|
||||
@@ -3329,7 +3329,7 @@ SwitchDispatch:
|
||||
|
||||
// Field object is cached in function's data_.
|
||||
RawField* field = reinterpret_cast<RawField*>(function->ptr()->data_);
|
||||
intptr_t field_id = field->ptr()->offset_or_field_id_;
|
||||
intptr_t field_id = field->ptr()->host_offset_or_field_id_;
|
||||
RawInstance* value = thread->field_table_values()[field_id];
|
||||
if (value == Object::sentinel().raw() ||
|
||||
value == Object::transition_sentinel().raw()) {
|
||||
@@ -3343,7 +3343,7 @@ SwitchDispatch:
|
||||
function = FrameFunction(FP);
|
||||
field = reinterpret_cast<RawField*>(function->ptr()->data_);
|
||||
// The field is initialized by the runtime call, but not returned.
|
||||
intptr_t field_id = field->ptr()->offset_or_field_id_;
|
||||
intptr_t field_id = field->ptr()->host_offset_or_field_id_;
|
||||
value = thread->field_table_values()[field_id];
|
||||
}
|
||||
|
||||
|
||||
@@ -110,9 +110,9 @@ InstanceMorpher* InstanceMorpher::CreateFromClassDescriptors(
|
||||
|
||||
if (from.NumTypeArguments() > 0) {
|
||||
// Add copying of the optional type argument field.
|
||||
intptr_t from_offset = from.type_arguments_field_offset();
|
||||
intptr_t from_offset = from.host_type_arguments_field_offset();
|
||||
ASSERT(from_offset != Class::kNoTypeArguments);
|
||||
intptr_t to_offset = to.type_arguments_field_offset();
|
||||
intptr_t to_offset = to.host_type_arguments_field_offset();
|
||||
ASSERT(to_offset != Class::kNoTypeArguments);
|
||||
mapping->Add(from_offset);
|
||||
mapping->Add(to_offset);
|
||||
@@ -152,8 +152,8 @@ InstanceMorpher* InstanceMorpher::CreateFromClassDescriptors(
|
||||
from_name = from_field.name();
|
||||
if (from_name.Equals(to_name)) {
|
||||
// Success
|
||||
mapping->Add(from_field.Offset());
|
||||
mapping->Add(to_field.Offset());
|
||||
mapping->Add(from_field.HostOffset());
|
||||
mapping->Add(to_field.HostOffset());
|
||||
// Field did exist in old class deifnition.
|
||||
new_field = false;
|
||||
}
|
||||
@@ -163,7 +163,7 @@ InstanceMorpher* InstanceMorpher::CreateFromClassDescriptors(
|
||||
const Field& field = Field::Handle(to_field.raw());
|
||||
field.set_needs_load_guard(true);
|
||||
field.set_is_unboxing_candidate(false);
|
||||
new_fields_offsets->Add(field.Offset());
|
||||
new_fields_offsets->Add(field.HostOffset());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1247,8 +1247,9 @@ void IsolateGroupReloadContext::FindModifiedSources(
|
||||
uri = script.url();
|
||||
const bool dart_scheme = uri.StartsWith(Symbols::DartScheme());
|
||||
if (dart_scheme) {
|
||||
// If a user-defined class mixes in a mixin from dart:*, it's list of scripts will have
|
||||
// a dart:* script as well. We don't consider those during reload.
|
||||
// If a user-defined class mixes in a mixin from dart:*, it's list of
|
||||
// scripts will have a dart:* script as well. We don't consider those
|
||||
// during reload.
|
||||
continue;
|
||||
}
|
||||
if (ContainsScriptUri(modified_sources_uris, uri.ToCString())) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "vm/compiler/backend/flow_graph_compiler.h"
|
||||
#include "vm/compiler/frontend/constant_reader.h"
|
||||
#include "vm/compiler/frontend/kernel_translation_helper.h"
|
||||
#include "vm/dart_api_impl.h"
|
||||
@@ -948,6 +949,17 @@ void KernelLoader::ReadInferredType(const Field& field,
|
||||
field.set_guarded_cid(type.cid);
|
||||
field.set_is_nullable(type.IsNullable());
|
||||
field.set_guarded_list_length(Field::kNoFixedLength);
|
||||
if (FLAG_precompiled_mode) {
|
||||
field.set_is_unboxing_candidate(
|
||||
!field.is_late() && !field.is_static() &&
|
||||
((field.guarded_cid() == kDoubleCid &&
|
||||
FlowGraphCompiler::SupportsUnboxedDoubles()) ||
|
||||
(field.guarded_cid() == kFloat32x4Cid &&
|
||||
FlowGraphCompiler::SupportsUnboxedSimd128()) ||
|
||||
(field.guarded_cid() == kFloat64x2Cid &&
|
||||
FlowGraphCompiler::SupportsUnboxedSimd128())) &&
|
||||
!field.is_nullable());
|
||||
}
|
||||
}
|
||||
|
||||
void KernelLoader::CheckForInitializer(const Field& field) {
|
||||
|
||||
+473
-237
File diff suppressed because it is too large
Load Diff
+219
-52
@@ -266,6 +266,15 @@ class ZoneTextBuffer;
|
||||
#define MINT_OBJECT_IMPLEMENTATION(object, rettype, super) \
|
||||
FINAL_HEAP_OBJECT_IMPLEMENTATION_HELPER(object, rettype, super)
|
||||
|
||||
// In precompiled runtime, there is no access to runtime_api.cc since host
|
||||
// and target are the same. In those cases, the namespace dart is used to refer
|
||||
// to the target namespace
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
namespace RTN = dart;
|
||||
#else
|
||||
namespace RTN = dart::compiler::target;
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
class Object {
|
||||
public:
|
||||
using RawObjectType = RawObject;
|
||||
@@ -885,36 +894,88 @@ class Class : public Object {
|
||||
kInvocationDispatcherEntrySize,
|
||||
};
|
||||
|
||||
intptr_t instance_size() const {
|
||||
intptr_t host_instance_size() const {
|
||||
ASSERT(is_finalized() || is_prefinalized());
|
||||
return (raw_ptr()->instance_size_in_words_ * kWordSize);
|
||||
return (raw_ptr()->host_instance_size_in_words_ * kWordSize);
|
||||
}
|
||||
static intptr_t instance_size(RawClass* clazz) {
|
||||
return (clazz->ptr()->instance_size_in_words_ * kWordSize);
|
||||
intptr_t target_instance_size() const {
|
||||
ASSERT(is_finalized() || is_prefinalized());
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
return (raw_ptr()->target_instance_size_in_words_ *
|
||||
compiler::target::kWordSize);
|
||||
#else
|
||||
return host_instance_size();
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
void set_instance_size(intptr_t value_in_bytes) const {
|
||||
static intptr_t host_instance_size(RawClass* clazz) {
|
||||
return (clazz->ptr()->host_instance_size_in_words_ * kWordSize);
|
||||
}
|
||||
static intptr_t target_instance_size(RawClass* clazz) {
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
return (clazz->ptr()->target_instance_size_in_words_ *
|
||||
compiler::target::kWordSize);
|
||||
#else
|
||||
return host_instance_size(clazz);
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
void set_instance_size(intptr_t host_value_in_bytes,
|
||||
intptr_t target_value_in_bytes) const {
|
||||
ASSERT(kWordSize != 0);
|
||||
set_instance_size_in_words(value_in_bytes / kWordSize);
|
||||
set_instance_size_in_words(
|
||||
host_value_in_bytes / kWordSize,
|
||||
target_value_in_bytes / compiler::target::kWordSize);
|
||||
}
|
||||
void set_instance_size_in_words(intptr_t value) const {
|
||||
ASSERT(Utils::IsAligned((value * kWordSize), kObjectAlignment));
|
||||
StoreNonPointer(&raw_ptr()->instance_size_in_words_, value);
|
||||
void set_instance_size_in_words(intptr_t host_value,
|
||||
intptr_t target_value) const {
|
||||
ASSERT(Utils::IsAligned((host_value * kWordSize), kObjectAlignment));
|
||||
StoreNonPointer(&raw_ptr()->host_instance_size_in_words_, host_value);
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
ASSERT(Utils::IsAligned((target_value * compiler::target::kWordSize),
|
||||
compiler::target::kObjectAlignment));
|
||||
StoreNonPointer(&raw_ptr()->target_instance_size_in_words_, target_value);
|
||||
#else
|
||||
ASSERT(host_value == target_value);
|
||||
#endif // #!defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
||||
intptr_t next_field_offset() const {
|
||||
return raw_ptr()->next_field_offset_in_words_ * kWordSize;
|
||||
intptr_t host_next_field_offset() const {
|
||||
return raw_ptr()->host_next_field_offset_in_words_ * kWordSize;
|
||||
}
|
||||
void set_next_field_offset(intptr_t value_in_bytes) const {
|
||||
ASSERT(kWordSize != 0);
|
||||
set_next_field_offset_in_words(value_in_bytes / kWordSize);
|
||||
intptr_t target_next_field_offset() const {
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
return raw_ptr()->target_next_field_offset_in_words_ *
|
||||
compiler::target::kWordSize;
|
||||
#else
|
||||
return host_next_field_offset();
|
||||
#endif // #!defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
void set_next_field_offset_in_words(intptr_t value) const {
|
||||
ASSERT((value == -1) ||
|
||||
(Utils::IsAligned((value * kWordSize), kObjectAlignment) &&
|
||||
(value == raw_ptr()->instance_size_in_words_)) ||
|
||||
(!Utils::IsAligned((value * kWordSize), kObjectAlignment) &&
|
||||
((value + 1) == raw_ptr()->instance_size_in_words_)));
|
||||
StoreNonPointer(&raw_ptr()->next_field_offset_in_words_, value);
|
||||
void set_next_field_offset(intptr_t host_value_in_bytes,
|
||||
intptr_t target_value_in_bytes) const {
|
||||
set_next_field_offset_in_words(
|
||||
host_value_in_bytes / kWordSize,
|
||||
target_value_in_bytes / compiler::target::kWordSize);
|
||||
}
|
||||
void set_next_field_offset_in_words(intptr_t host_value,
|
||||
intptr_t target_value) const {
|
||||
ASSERT((host_value == -1) ||
|
||||
(Utils::IsAligned((host_value * kWordSize), kObjectAlignment) &&
|
||||
(host_value == raw_ptr()->host_instance_size_in_words_)) ||
|
||||
(!Utils::IsAligned((host_value * kWordSize), kObjectAlignment) &&
|
||||
((host_value + 1) == raw_ptr()->host_instance_size_in_words_)));
|
||||
StoreNonPointer(&raw_ptr()->host_next_field_offset_in_words_, host_value);
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
ASSERT((target_value == -1) ||
|
||||
(Utils::IsAligned((target_value * compiler::target::kWordSize),
|
||||
compiler::target::kObjectAlignment) &&
|
||||
(target_value == raw_ptr()->target_instance_size_in_words_)) ||
|
||||
(!Utils::IsAligned((target_value * compiler::target::kWordSize),
|
||||
compiler::target::kObjectAlignment) &&
|
||||
((target_value + 1) == raw_ptr()->target_instance_size_in_words_)));
|
||||
StoreNonPointer(&raw_ptr()->target_next_field_offset_in_words_,
|
||||
target_value);
|
||||
#else
|
||||
ASSERT(host_value == target_value);
|
||||
#endif // #!defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
||||
static bool is_valid_id(intptr_t value) {
|
||||
@@ -1013,28 +1074,64 @@ class Class : public Object {
|
||||
|
||||
// If this class is parameterized, each instance has a type_arguments field.
|
||||
static const intptr_t kNoTypeArguments = -1;
|
||||
intptr_t type_arguments_field_offset() const {
|
||||
intptr_t host_type_arguments_field_offset() const {
|
||||
ASSERT(is_type_finalized() || is_prefinalized());
|
||||
if (raw_ptr()->type_arguments_field_offset_in_words_ == kNoTypeArguments) {
|
||||
if (raw_ptr()->host_type_arguments_field_offset_in_words_ ==
|
||||
kNoTypeArguments) {
|
||||
return kNoTypeArguments;
|
||||
}
|
||||
return raw_ptr()->type_arguments_field_offset_in_words_ * kWordSize;
|
||||
return raw_ptr()->host_type_arguments_field_offset_in_words_ * kWordSize;
|
||||
}
|
||||
void set_type_arguments_field_offset(intptr_t value_in_bytes) const {
|
||||
intptr_t value;
|
||||
if (value_in_bytes == kNoTypeArguments) {
|
||||
value = kNoTypeArguments;
|
||||
} else {
|
||||
ASSERT(kWordSize != 0);
|
||||
value = value_in_bytes / kWordSize;
|
||||
intptr_t target_type_arguments_field_offset() const {
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
ASSERT(is_type_finalized() || is_prefinalized());
|
||||
if (raw_ptr()->target_type_arguments_field_offset_in_words_ ==
|
||||
compiler::target::Class::kNoTypeArguments) {
|
||||
return compiler::target::Class::kNoTypeArguments;
|
||||
}
|
||||
set_type_arguments_field_offset_in_words(value);
|
||||
return raw_ptr()->target_type_arguments_field_offset_in_words_ *
|
||||
compiler::target::kWordSize;
|
||||
#else
|
||||
return host_type_arguments_field_offset();
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
void set_type_arguments_field_offset_in_words(intptr_t value) const {
|
||||
StoreNonPointer(&raw_ptr()->type_arguments_field_offset_in_words_, value);
|
||||
void set_type_arguments_field_offset(intptr_t host_value_in_bytes,
|
||||
intptr_t target_value_in_bytes) const {
|
||||
intptr_t host_value, target_value;
|
||||
if (host_value_in_bytes == kNoTypeArguments ||
|
||||
target_value_in_bytes == RTN::Class::kNoTypeArguments) {
|
||||
ASSERT(host_value_in_bytes == kNoTypeArguments &&
|
||||
target_value_in_bytes == RTN::Class::kNoTypeArguments);
|
||||
host_value = kNoTypeArguments;
|
||||
target_value = RTN::Class::kNoTypeArguments;
|
||||
} else {
|
||||
ASSERT(kWordSize != 0 && compiler::target::kWordSize);
|
||||
host_value = host_value_in_bytes / kWordSize;
|
||||
target_value = target_value_in_bytes / compiler::target::kWordSize;
|
||||
}
|
||||
set_type_arguments_field_offset_in_words(host_value, target_value);
|
||||
}
|
||||
static intptr_t type_arguments_field_offset_in_words_offset() {
|
||||
return OFFSET_OF(RawClass, type_arguments_field_offset_in_words_);
|
||||
void set_type_arguments_field_offset_in_words(intptr_t host_value,
|
||||
intptr_t target_value) const {
|
||||
StoreNonPointer(&raw_ptr()->host_type_arguments_field_offset_in_words_,
|
||||
host_value);
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
StoreNonPointer(&raw_ptr()->target_type_arguments_field_offset_in_words_,
|
||||
target_value);
|
||||
#else
|
||||
ASSERT(host_value == target_value);
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
static intptr_t host_type_arguments_field_offset_in_words_offset() {
|
||||
return OFFSET_OF(RawClass, host_type_arguments_field_offset_in_words_);
|
||||
}
|
||||
|
||||
static intptr_t target_type_arguments_field_offset_in_words_offset() {
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
return OFFSET_OF(RawClass, target_type_arguments_field_offset_in_words_);
|
||||
#else
|
||||
return host_type_arguments_field_offset_in_words_offset();
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
||||
// The super type of this class, Object type if not explicitly specified.
|
||||
@@ -1395,7 +1492,7 @@ class Class : public Object {
|
||||
RawError* EnsureIsFinalized(Thread* thread) const;
|
||||
|
||||
// Allocate a class used for VM internal objects.
|
||||
template <class FakeObject>
|
||||
template <class FakeObject, class TargetFakeObject>
|
||||
static RawClass* New(Isolate* isolate, bool register_class = true);
|
||||
|
||||
// Allocate instance classes.
|
||||
@@ -1460,6 +1557,44 @@ class Class : public Object {
|
||||
const Array& args_desc,
|
||||
const Function& dispatcher) const;
|
||||
|
||||
static int32_t host_instance_size_in_words(const RawClass* cls) {
|
||||
return cls->ptr()->host_instance_size_in_words_;
|
||||
}
|
||||
|
||||
static int32_t target_instance_size_in_words(const RawClass* cls) {
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
return cls->ptr()->target_instance_size_in_words_;
|
||||
#else
|
||||
return host_instance_size_in_words(cls);
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
||||
static int32_t host_next_field_offset_in_words(const RawClass* cls) {
|
||||
return cls->ptr()->host_next_field_offset_in_words_;
|
||||
}
|
||||
|
||||
static int32_t target_next_field_offset_in_words(const RawClass* cls) {
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
return cls->ptr()->target_next_field_offset_in_words_;
|
||||
#else
|
||||
return host_next_field_offset_in_words(cls);
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
||||
static int32_t host_type_arguments_field_offset_in_words(
|
||||
const RawClass* cls) {
|
||||
return cls->ptr()->host_type_arguments_field_offset_in_words_;
|
||||
}
|
||||
|
||||
static int32_t target_type_arguments_field_offset_in_words(
|
||||
const RawClass* cls) {
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
return cls->ptr()->target_type_arguments_field_offset_in_words_;
|
||||
#else
|
||||
return host_type_arguments_field_offset_in_words(cls);
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
||||
private:
|
||||
RawType* declaration_type() const { return raw_ptr()->declaration_type_; }
|
||||
|
||||
@@ -1474,7 +1609,7 @@ class Class : public Object {
|
||||
// Tells whether instances need morphing for reload.
|
||||
bool RequiresInstanceMorphing(const Class& replacement) const;
|
||||
|
||||
template <class FakeObject>
|
||||
template <class FakeInstance, class TargetFakeInstance>
|
||||
static RawClass* NewCommon(intptr_t index);
|
||||
|
||||
enum MemberKind {
|
||||
@@ -1538,7 +1673,8 @@ class Class : public Object {
|
||||
const Array& args_desc,
|
||||
RawFunction::Kind kind) const;
|
||||
|
||||
void CalculateFieldOffsets() const;
|
||||
// Returns the bitmap of unboxed fields
|
||||
UnboxedFieldBitmap CalculateFieldOffsets() const;
|
||||
|
||||
// functions_hash_table is in use iff there are at least this many functions.
|
||||
static const intptr_t kFunctionLookupHashTreshold = 16;
|
||||
@@ -1576,7 +1712,7 @@ class Class : public Object {
|
||||
const String& name) const;
|
||||
|
||||
// Allocate an instance class which has a VM implementation.
|
||||
template <class FakeInstance>
|
||||
template <class FakeInstance, class TargetFakeInstance>
|
||||
static RawClass* New(intptr_t id,
|
||||
Isolate* isolate,
|
||||
bool register_class = true,
|
||||
@@ -3643,15 +3779,19 @@ class Field : public Object {
|
||||
|
||||
intptr_t KernelDataProgramOffset() const;
|
||||
|
||||
inline intptr_t Offset() const;
|
||||
// Called during class finalization.
|
||||
inline void SetOffset(intptr_t offset_in_bytes) const;
|
||||
inline void SetOffset(intptr_t host_offset_in_bytes,
|
||||
intptr_t target_offset_in_bytes) const;
|
||||
|
||||
inline intptr_t HostOffset() const;
|
||||
|
||||
inline intptr_t TargetOffset() const;
|
||||
|
||||
inline RawInstance* StaticValue() const;
|
||||
void SetStaticValue(const Instance& value,
|
||||
bool save_initial_value = false) const;
|
||||
|
||||
intptr_t field_id() const { return raw_ptr()->offset_or_field_id_; }
|
||||
intptr_t field_id() const { return raw_ptr()->host_offset_or_field_id_; }
|
||||
inline void set_field_id(intptr_t field_id) const;
|
||||
|
||||
#ifndef DART_PRECOMPILED_RUNTIME
|
||||
@@ -3748,6 +3888,14 @@ class Field : public Object {
|
||||
return OFFSET_OF(RawField, static_type_exactness_state_);
|
||||
}
|
||||
|
||||
static inline intptr_t TargetOffsetOf(const RawField* field) {
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
return field->ptr()->target_offset_;
|
||||
#else
|
||||
return field->ptr()->host_offset_or_field_id_;
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
||||
// Return class id that any non-null value read from this field is guaranteed
|
||||
// to have or kDynamicCid if such class id is not known.
|
||||
// Stores to this field must update this information hence the name.
|
||||
@@ -6554,7 +6702,7 @@ class Instance : public Object {
|
||||
const Class& cls = Class::Handle(clazz());
|
||||
ASSERT(cls.is_finalized() || cls.is_prefinalized());
|
||||
#endif
|
||||
return (clazz()->ptr()->instance_size_in_words_ * kWordSize);
|
||||
return (clazz()->ptr()->host_instance_size_in_words_ * kWordSize);
|
||||
}
|
||||
|
||||
// Returns Instance::null() if instance cannot be canonicalized.
|
||||
@@ -6576,7 +6724,7 @@ class Instance : public Object {
|
||||
virtual bool CheckIsCanonical(Thread* thread) const;
|
||||
#endif // DEBUG
|
||||
|
||||
RawObject* GetField(const Field& field) const { return *FieldAddr(field); }
|
||||
RawObject* GetField(const Field& field) const;
|
||||
|
||||
void SetField(const Field& field, const Object& value) const;
|
||||
|
||||
@@ -6713,7 +6861,7 @@ class Instance : public Object {
|
||||
return reinterpret_cast<RawObject**>(raw_value() - kHeapObjectTag + offset);
|
||||
}
|
||||
RawObject** FieldAddr(const Field& field) const {
|
||||
return FieldAddrAtOffset(field.Offset());
|
||||
return FieldAddrAtOffset(field.HostOffset());
|
||||
}
|
||||
RawObject** NativeFieldsAddr() const {
|
||||
return FieldAddrAtOffset(sizeof(RawObject));
|
||||
@@ -10313,26 +10461,45 @@ bool Function::HasBytecode(RawFunction* function) {
|
||||
}
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
intptr_t Field::Offset() const {
|
||||
intptr_t Field::HostOffset() const {
|
||||
ASSERT(is_instance()); // Valid only for dart instance fields.
|
||||
return (raw_ptr()->offset_or_field_id_ * kWordSize);
|
||||
return (raw_ptr()->host_offset_or_field_id_ * kWordSize);
|
||||
}
|
||||
|
||||
void Field::SetOffset(intptr_t offset_in_bytes) const {
|
||||
intptr_t Field::TargetOffset() const {
|
||||
ASSERT(is_instance()); // Valid only for dart instance fields.
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
return (raw_ptr()->target_offset_ * compiler::target::kWordSize);
|
||||
#else
|
||||
return HostOffset();
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
||||
void Field::SetOffset(intptr_t host_offset_in_bytes,
|
||||
intptr_t target_offset_in_bytes) const {
|
||||
ASSERT(is_instance()); // Valid only for dart instance fields.
|
||||
ASSERT(kWordSize != 0);
|
||||
StoreNonPointer(&raw_ptr()->offset_or_field_id_, offset_in_bytes / kWordSize);
|
||||
StoreNonPointer(&raw_ptr()->host_offset_or_field_id_,
|
||||
host_offset_in_bytes / kWordSize);
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
ASSERT(compiler::target::kWordSize != 0);
|
||||
StoreNonPointer(&raw_ptr()->target_offset_,
|
||||
target_offset_in_bytes / compiler::target::kWordSize);
|
||||
#else
|
||||
ASSERT(host_offset_in_bytes == target_offset_in_bytes);
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
||||
RawInstance* Field::StaticValue() const {
|
||||
ASSERT(is_static()); // Valid only for static dart fields.
|
||||
return Isolate::Current()->field_table()->At(raw_ptr()->offset_or_field_id_);
|
||||
return Isolate::Current()->field_table()->At(
|
||||
raw_ptr()->host_offset_or_field_id_);
|
||||
}
|
||||
|
||||
void Field::set_field_id(intptr_t field_id) const {
|
||||
ASSERT(is_static());
|
||||
ASSERT(Thread::Current()->IsMutatorThread());
|
||||
StoreNonPointer(&raw_ptr()->offset_or_field_id_, field_id);
|
||||
StoreNonPointer(&raw_ptr()->host_offset_or_field_id_, field_id);
|
||||
}
|
||||
|
||||
#ifndef DART_PRECOMPILED_RUNTIME
|
||||
|
||||
@@ -1097,7 +1097,7 @@ void HeapSnapshotWriter::Write() {
|
||||
if (field.is_instance()) {
|
||||
intptr_t flags = 1; // Strong.
|
||||
WriteUnsigned(flags);
|
||||
intptr_t index = field.Offset() / kWordSize - 1;
|
||||
intptr_t index = field.HostOffset() / kWordSize - 1;
|
||||
ASSERT(index >= 0);
|
||||
WriteUnsigned(index);
|
||||
str = field.name();
|
||||
|
||||
@@ -663,8 +663,8 @@ class InstanceSizeConflict : public ClassReasonForCancelling {
|
||||
return String::NewFormatted("Instance size mismatch between '%s' (%" Pd
|
||||
") and replacement "
|
||||
"'%s' ( %" Pd ")",
|
||||
from_.ToCString(), from_.instance_size(),
|
||||
to_.ToCString(), to_.instance_size());
|
||||
from_.ToCString(), from_.host_instance_size(),
|
||||
to_.ToCString(), to_.host_instance_size());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -748,7 +748,9 @@ bool Class::RequiresInstanceMorphing(const Class& replacement) const {
|
||||
// Check that we have the same next field offset. This check is not
|
||||
// redundant with the one above because the instance OffsetToFieldMap
|
||||
// array length is based on the instance size (which may be aligned up).
|
||||
if (next_field_offset() != replacement.next_field_offset()) return true;
|
||||
if (host_next_field_offset() != replacement.host_next_field_offset()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Verify that field names / offsets match across the entire hierarchy.
|
||||
Field& field = Field::Handle();
|
||||
@@ -805,7 +807,7 @@ bool Class::CanReloadPreFinalized(const Class& replacement,
|
||||
return false;
|
||||
}
|
||||
// Check the instance sizes are equal.
|
||||
if (instance_size() != replacement.instance_size()) {
|
||||
if (host_instance_size() != replacement.host_instance_size()) {
|
||||
context->group_reload_context()->AddReasonForCancelling(
|
||||
new (context->zone())
|
||||
InstanceSizeConflict(context->zone(), *this, replacement));
|
||||
|
||||
@@ -217,7 +217,7 @@ ISOLATE_UNIT_TEST_CASE(InstanceClass) {
|
||||
ClassFinalizer::FinalizeTypesInClass(empty_class);
|
||||
empty_class.Finalize();
|
||||
|
||||
EXPECT_EQ(kObjectAlignment, empty_class.instance_size());
|
||||
EXPECT_EQ(kObjectAlignment, empty_class.host_instance_size());
|
||||
Instance& instance = Instance::Handle(Instance::New(empty_class));
|
||||
EXPECT_EQ(empty_class.raw(), instance.clazz());
|
||||
|
||||
@@ -242,8 +242,8 @@ ISOLATE_UNIT_TEST_CASE(InstanceClass) {
|
||||
one_field_class.Finalize();
|
||||
intptr_t header_size = sizeof(RawObject);
|
||||
EXPECT_EQ(Utils::RoundUp((header_size + (1 * kWordSize)), kObjectAlignment),
|
||||
one_field_class.instance_size());
|
||||
EXPECT_EQ(header_size, field.Offset());
|
||||
one_field_class.host_instance_size());
|
||||
EXPECT_EQ(header_size, field.HostOffset());
|
||||
EXPECT(!one_field_class.is_implemented());
|
||||
one_field_class.set_is_implemented();
|
||||
EXPECT(one_field_class.is_implemented());
|
||||
|
||||
@@ -377,14 +377,32 @@ void RawObject::VisitPointersPrecise(ObjectPointerVisitor* visitor) {
|
||||
uword next_field_offset = visitor->isolate()
|
||||
->GetClassForHeapWalkAt(class_id)
|
||||
->ptr()
|
||||
->next_field_offset_in_words_
|
||||
->host_next_field_offset_in_words_
|
||||
<< kWordSizeLog2;
|
||||
ASSERT(next_field_offset > 0);
|
||||
uword obj_addr = RawObject::ToAddr(this);
|
||||
uword from = obj_addr + sizeof(RawObject);
|
||||
uword to = obj_addr + next_field_offset - kWordSize;
|
||||
visitor->VisitPointers(reinterpret_cast<RawObject**>(from),
|
||||
reinterpret_cast<RawObject**>(to));
|
||||
const auto first = reinterpret_cast<RawObject**>(from);
|
||||
const auto last = reinterpret_cast<RawObject**>(to);
|
||||
|
||||
#if defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
const auto unboxed_fields_bitmap =
|
||||
visitor->shared_class_table()->GetUnboxedFieldsMapAt(class_id);
|
||||
|
||||
if (!unboxed_fields_bitmap.IsEmpty()) {
|
||||
intptr_t bit = sizeof(RawObject) / kWordSize;
|
||||
for (RawObject** current = first; current <= last; current++) {
|
||||
if (!unboxed_fields_bitmap.Get(bit++)) {
|
||||
visitor->VisitPointer(current);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
visitor->VisitPointers(first, last);
|
||||
}
|
||||
#else
|
||||
visitor->VisitPointers(first, last);
|
||||
#endif // defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
}
|
||||
|
||||
bool RawObject::FindObject(FindObjectVisitor* visitor) {
|
||||
|
||||
+70
-10
@@ -474,10 +474,27 @@ class RawObject {
|
||||
uword obj_addr = ToAddr(this);
|
||||
uword from = obj_addr + sizeof(RawObject);
|
||||
uword to = obj_addr + instance_size - kWordSize;
|
||||
const auto first = reinterpret_cast<RawObject**>(from);
|
||||
const auto last = reinterpret_cast<RawObject**>(to);
|
||||
|
||||
#if defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
const auto unboxed_fields_bitmap =
|
||||
visitor->shared_class_table()->GetUnboxedFieldsMapAt(class_id);
|
||||
|
||||
if (!unboxed_fields_bitmap.IsEmpty()) {
|
||||
intptr_t bit = sizeof(RawObject) / kWordSize;
|
||||
for (RawObject** current = first; current <= last; current++) {
|
||||
if (!unboxed_fields_bitmap.Get(bit++)) {
|
||||
visitor->VisitPointer(current);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
visitor->VisitPointers(first, last);
|
||||
}
|
||||
#else
|
||||
// Call visitor function virtually
|
||||
visitor->VisitPointers(reinterpret_cast<RawObject**>(from),
|
||||
reinterpret_cast<RawObject**>(to));
|
||||
visitor->VisitPointers(first, last);
|
||||
#endif // defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
|
||||
return instance_size;
|
||||
}
|
||||
@@ -495,10 +512,27 @@ class RawObject {
|
||||
uword obj_addr = ToAddr(this);
|
||||
uword from = obj_addr + sizeof(RawObject);
|
||||
uword to = obj_addr + instance_size - kWordSize;
|
||||
const auto first = reinterpret_cast<RawObject**>(from);
|
||||
const auto last = reinterpret_cast<RawObject**>(to);
|
||||
|
||||
#if defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
const auto unboxed_fields_bitmap =
|
||||
visitor->shared_class_table()->GetUnboxedFieldsMapAt(class_id);
|
||||
|
||||
if (!unboxed_fields_bitmap.IsEmpty()) {
|
||||
intptr_t bit = sizeof(RawObject) / kWordSize;
|
||||
for (RawObject** current = first; current <= last; current++) {
|
||||
if (!unboxed_fields_bitmap.Get(bit++)) {
|
||||
visitor->V::VisitPointers(current, current);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
visitor->V::VisitPointers(first, last);
|
||||
}
|
||||
#else
|
||||
// Call visitor function non-virtually
|
||||
visitor->V::VisitPointers(reinterpret_cast<RawObject**>(from),
|
||||
reinterpret_cast<RawObject**>(to));
|
||||
visitor->V::VisitPointers(first, last);
|
||||
#endif // defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
|
||||
|
||||
return instance_size;
|
||||
}
|
||||
@@ -814,14 +848,32 @@ class RawClass : public RawObject {
|
||||
|
||||
TokenPosition token_pos_;
|
||||
TokenPosition end_token_pos_;
|
||||
int32_t instance_size_in_words_; // Size if fixed len or 0 if variable len.
|
||||
int32_t type_arguments_field_offset_in_words_; // Offset of type args fld.
|
||||
int32_t next_field_offset_in_words_; // Offset of the next instance field.
|
||||
|
||||
classid_t id_; // Class Id, also index in the class table.
|
||||
int16_t num_type_arguments_; // Number of type arguments in flattened vector.
|
||||
uint16_t num_native_fields_;
|
||||
uint32_t state_bits_;
|
||||
|
||||
// Size if fixed len or 0 if variable len.
|
||||
int32_t host_instance_size_in_words_;
|
||||
|
||||
// Offset of type args fld.
|
||||
int32_t host_type_arguments_field_offset_in_words_;
|
||||
|
||||
// Offset of the next instance field.
|
||||
int32_t host_next_field_offset_in_words_;
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
// Size if fixed len or 0 if variable len (target).
|
||||
int32_t target_instance_size_in_words_;
|
||||
|
||||
// Offset of type args fld.
|
||||
int32_t target_type_arguments_field_offset_in_words_;
|
||||
|
||||
// Offset of the next instance field (target).
|
||||
int32_t target_next_field_offset_in_words_;
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
typedef BitField<uint32_t, bool, 0, 1> IsDeclaredInBytecode;
|
||||
typedef BitField<uint32_t, uint32_t, 1, 31> BinaryDeclarationOffset;
|
||||
@@ -1177,11 +1229,16 @@ class RawField : public RawObject {
|
||||
// field.
|
||||
int8_t static_type_exactness_state_;
|
||||
|
||||
uint16_t kind_bits_; // static, final, const, has initializer....
|
||||
|
||||
// - for instance fields: offset in words to the value in the class instance.
|
||||
// - for static fields: index into field_table.
|
||||
intptr_t offset_or_field_id_;
|
||||
intptr_t host_offset_or_field_id_;
|
||||
|
||||
uint16_t kind_bits_; // static, final, const, has initializer....
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
// for instance fields, the offset in words in the target architecture
|
||||
int32_t target_offset_;
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
friend class CidRewriteVisitor;
|
||||
};
|
||||
@@ -1429,7 +1486,7 @@ class RawCode : public RawObject {
|
||||
#endif
|
||||
|
||||
// Compilation timestamp.
|
||||
NOT_IN_PRODUCT(int64_t compile_timestamp_);
|
||||
NOT_IN_PRODUCT(alignas(8) int64_t compile_timestamp_);
|
||||
|
||||
// state_bits_ is a bitfield with three fields:
|
||||
// The optimized bit, the alive bit, and a count of the number of pointer
|
||||
@@ -2258,6 +2315,7 @@ class RawDouble : public RawNumber {
|
||||
|
||||
friend class Api;
|
||||
friend class SnapshotReader;
|
||||
friend class Class;
|
||||
};
|
||||
COMPILE_ASSERT(sizeof(RawDouble) == 16);
|
||||
|
||||
@@ -2528,6 +2586,7 @@ class RawFloat32x4 : public RawInstance {
|
||||
ALIGN8 float value_[4];
|
||||
|
||||
friend class SnapshotReader;
|
||||
friend class Class;
|
||||
|
||||
public:
|
||||
float x() const { return value_[0]; }
|
||||
@@ -2560,6 +2619,7 @@ class RawFloat64x2 : public RawInstance {
|
||||
ALIGN8 double value_[2];
|
||||
|
||||
friend class SnapshotReader;
|
||||
friend class Class;
|
||||
|
||||
public:
|
||||
double x() const { return value_[0]; }
|
||||
|
||||
+47
-24
@@ -593,47 +593,59 @@ RawObject* SnapshotReader::ReadInstance(intptr_t object_id,
|
||||
ASSERT(!cls_.IsNull());
|
||||
// Closure instances are handled by Closure::ReadFrom().
|
||||
ASSERT(!cls_.IsClosureClass());
|
||||
instance_size = cls_.instance_size();
|
||||
instance_size = cls_.host_instance_size();
|
||||
ASSERT(instance_size > 0);
|
||||
// Allocate the instance and read in all the fields for the object.
|
||||
*result ^= Object::Allocate(cls_.id(), instance_size, Heap::kNew);
|
||||
} else {
|
||||
cls_ ^= ReadObjectImpl(kAsInlinedObject);
|
||||
ASSERT(!cls_.IsNull());
|
||||
instance_size = cls_.instance_size();
|
||||
instance_size = cls_.host_instance_size();
|
||||
}
|
||||
if (cls_.id() == set_class_.id()) {
|
||||
EnqueueRehashingOfSet(*result);
|
||||
}
|
||||
if (!as_reference) {
|
||||
// Read all the individual fields for inlined objects.
|
||||
intptr_t next_field_offset = cls_.next_field_offset();
|
||||
intptr_t next_field_offset = cls_.host_next_field_offset();
|
||||
|
||||
intptr_t type_argument_field_offset = cls_.type_arguments_field_offset();
|
||||
intptr_t type_argument_field_offset =
|
||||
cls_.host_type_arguments_field_offset();
|
||||
ASSERT(next_field_offset > 0);
|
||||
// Instance::NextFieldOffset() returns the offset of the first field in
|
||||
// a Dart object.
|
||||
bool read_as_reference = RawObject::IsCanonical(tags) ? false : true;
|
||||
intptr_t offset = Instance::NextFieldOffset();
|
||||
intptr_t result_cid = result->GetClassId();
|
||||
|
||||
const auto unboxed_fields =
|
||||
isolate()->shared_class_table()->GetUnboxedFieldsMapAt(result_cid);
|
||||
|
||||
while (offset < next_field_offset) {
|
||||
pobj_ = ReadObjectImpl(read_as_reference);
|
||||
result->SetFieldAtOffset(offset, pobj_);
|
||||
if ((offset != type_argument_field_offset) &&
|
||||
(kind_ == Snapshot::kMessage) && isolate()->use_field_guards()) {
|
||||
// TODO(fschneider): Consider hoisting these lookups out of the loop.
|
||||
// This would involve creating a handle, since cls_ can't be reused
|
||||
// across the call to ReadObjectImpl.
|
||||
cls_ = isolate()->class_table()->At(result_cid);
|
||||
array_ = cls_.OffsetToFieldMap();
|
||||
field_ ^= array_.At(offset >> kWordSizeLog2);
|
||||
ASSERT(!field_.IsNull());
|
||||
ASSERT(field_.Offset() == offset);
|
||||
obj_ = pobj_.raw();
|
||||
field_.RecordStore(obj_);
|
||||
if (unboxed_fields.Get(offset / kWordSize)) {
|
||||
uword* p = reinterpret_cast<uword*>(result->raw_value() -
|
||||
kHeapObjectTag + offset);
|
||||
// Reads 32 bits of the unboxed value at a time
|
||||
*p = ReadWordWith32BitReads();
|
||||
} else {
|
||||
pobj_ = ReadObjectImpl(read_as_reference);
|
||||
result->SetFieldAtOffset(offset, pobj_);
|
||||
if ((offset != type_argument_field_offset) &&
|
||||
(kind_ == Snapshot::kMessage) && isolate()->use_field_guards()) {
|
||||
// TODO(fschneider): Consider hoisting these lookups out of the loop.
|
||||
// This would involve creating a handle, since cls_ can't be reused
|
||||
// across the call to ReadObjectImpl.
|
||||
cls_ = isolate()->class_table()->At(result_cid);
|
||||
array_ = cls_.OffsetToFieldMap();
|
||||
field_ ^= array_.At(offset >> kWordSizeLog2);
|
||||
ASSERT(!field_.IsNull());
|
||||
ASSERT(field_.HostOffset() == offset);
|
||||
obj_ = pobj_.raw();
|
||||
field_.RecordStore(obj_);
|
||||
}
|
||||
// TODO(fschneider): Verify the guarded cid and length for other kinds
|
||||
// of snapshot (kFull, kScript) with asserts.
|
||||
}
|
||||
// TODO(fschneider): Verify the guarded cid and length for other kinds of
|
||||
// snapshot (kFull, kScript) with asserts.
|
||||
offset += kWordSize;
|
||||
}
|
||||
if (RawObject::IsCanonical(tags)) {
|
||||
@@ -1439,7 +1451,7 @@ void SnapshotWriter::WriteInstance(RawObject* raw,
|
||||
// Write out the class information for this object.
|
||||
WriteObjectImpl(cls, kAsInlinedObject);
|
||||
} else {
|
||||
intptr_t next_field_offset = cls->ptr()->next_field_offset_in_words_
|
||||
intptr_t next_field_offset = Class::host_next_field_offset_in_words(cls)
|
||||
<< kWordSizeLog2;
|
||||
ASSERT(next_field_offset > 0);
|
||||
|
||||
@@ -1455,15 +1467,26 @@ void SnapshotWriter::WriteInstance(RawObject* raw,
|
||||
// Write out the class information for this object.
|
||||
WriteObjectImpl(cls, kAsInlinedObject);
|
||||
|
||||
const auto unboxed_fields =
|
||||
isolate()->shared_class_table()->GetUnboxedFieldsMapAt(cls->ptr()->id_);
|
||||
|
||||
// Write out all the fields for the object.
|
||||
// Instance::NextFieldOffset() returns the offset of the first field in
|
||||
// a Dart object.
|
||||
bool write_as_reference = RawObject::IsCanonical(tags) ? false : true;
|
||||
|
||||
intptr_t offset = Instance::NextFieldOffset();
|
||||
while (offset < next_field_offset) {
|
||||
RawObject* raw_obj = *reinterpret_cast<RawObject**>(
|
||||
reinterpret_cast<uword>(raw->ptr()) + offset);
|
||||
WriteObjectImpl(raw_obj, write_as_reference);
|
||||
if (unboxed_fields.Get(offset / kWordSize)) {
|
||||
// Writes 32 bits of the unboxed value at a time
|
||||
const uword value = *reinterpret_cast<uword*>(
|
||||
reinterpret_cast<uword>(raw->ptr()) + offset);
|
||||
WriteWordWith32BitWrites(value);
|
||||
} else {
|
||||
RawObject* raw_obj = *reinterpret_cast<RawObject**>(
|
||||
reinterpret_cast<uword>(raw->ptr()) + offset);
|
||||
WriteObjectImpl(raw_obj, write_as_reference);
|
||||
}
|
||||
offset += kWordSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,6 +272,8 @@ class BaseReader {
|
||||
return SerializedHeaderData::decode(value);
|
||||
}
|
||||
|
||||
uword ReadWordWith32BitReads() { return stream_.ReadWordWith32BitReads(); }
|
||||
|
||||
private:
|
||||
ReadStream stream_; // input stream.
|
||||
};
|
||||
@@ -529,6 +531,10 @@ class BaseWriter : public StackResource {
|
||||
stream_.WriteBytes(reinterpret_cast<const uint8_t*>(&value), sizeof(value));
|
||||
}
|
||||
|
||||
void WriteWordWith32BitWrites(uword value) {
|
||||
stream_.WriteWordWith32BitWrites(value);
|
||||
}
|
||||
|
||||
protected:
|
||||
BaseWriter(ReAlloc alloc, DeAlloc dealloc, intptr_t initial_size)
|
||||
: StackResource(Thread::Current()),
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// 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.
|
||||
|
||||
#include "vm/visitor.h"
|
||||
|
||||
#include "vm/isolate.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
ObjectPointerVisitor::ObjectPointerVisitor(Isolate* isolate)
|
||||
: isolate_(isolate),
|
||||
gc_root_type_("unknown"),
|
||||
shared_class_table_(isolate->shared_class_table()) {}
|
||||
|
||||
} // namespace dart
|
||||
@@ -6,6 +6,7 @@
|
||||
#define RUNTIME_VM_VISITOR_H_
|
||||
|
||||
#include "vm/allocation.h"
|
||||
#include "vm/class_table.h"
|
||||
#include "vm/globals.h"
|
||||
#include "vm/growable_array.h"
|
||||
|
||||
@@ -20,8 +21,7 @@ class RawTypedDataView;
|
||||
// An object pointer visitor interface.
|
||||
class ObjectPointerVisitor {
|
||||
public:
|
||||
explicit ObjectPointerVisitor(Isolate* isolate)
|
||||
: isolate_(isolate), gc_root_type_("unknown") {}
|
||||
explicit ObjectPointerVisitor(Isolate* isolate);
|
||||
virtual ~ObjectPointerVisitor() {}
|
||||
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
@@ -54,9 +54,14 @@ class ObjectPointerVisitor {
|
||||
|
||||
virtual bool visit_weak_persistent_handles() const { return false; }
|
||||
|
||||
const SharedClassTable* shared_class_table() const {
|
||||
return shared_class_table_;
|
||||
}
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
const char* gc_root_type_;
|
||||
SharedClassTable* shared_class_table_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(ObjectPointerVisitor);
|
||||
};
|
||||
|
||||
@@ -357,6 +357,7 @@ vm_sources = [
|
||||
"virtual_memory_fuchsia.cc",
|
||||
"virtual_memory_posix.cc",
|
||||
"virtual_memory_win.cc",
|
||||
"visitor.cc",
|
||||
"visitor.h",
|
||||
"zone.cc",
|
||||
"zone.h",
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// 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:async';
|
||||
import 'dart:isolate';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
double getDoubleWithHeapObjectTag() {
|
||||
final bd = ByteData(8);
|
||||
bd.setUint64(0, 0x8000000000000001, Endian.host);
|
||||
final double v = bd.getFloat64(0, Endian.host);
|
||||
return v;
|
||||
}
|
||||
|
||||
class Foo {
|
||||
final double x = getDoubleWithHeapObjectTag();
|
||||
final String name = "Foo Class";
|
||||
Foo();
|
||||
}
|
||||
|
||||
main(args) async {
|
||||
final receivePort = new ReceivePort();
|
||||
|
||||
receivePort.sendPort.send(Foo());
|
||||
final it = StreamIterator(receivePort);
|
||||
Expect.isTrue(await it.moveNext());
|
||||
final Foo receivedFoo = it.current as Foo;
|
||||
Expect.equals(receivedFoo.x, getDoubleWithHeapObjectTag());
|
||||
Expect.equals(receivedFoo.name, "Foo Class");
|
||||
await it.cancel();
|
||||
}
|
||||
Reference in New Issue
Block a user