Skip to content

Commit c94103a

Browse files
alexmarkovCommit Bot
authored and
Commit Bot
committed
[vm] Initial implementation of record instances
TEST=ci Issue: #49719 Change-Id: I82ba571d1935d616fe3d4d6d579e59eb57d65a43 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/256804 Commit-Queue: Alexander Markov <[email protected]> Reviewed-by: Ryan Macnak <[email protected]>
1 parent 9a023ae commit c94103a

31 files changed

+562
-10
lines changed

runtime/lib/object.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ static bool HaveSameRuntimeTypeHelper(Zone* zone,
146146
return left_type.IsEquivalent(right_type, TypeEquality::kSyntactical);
147147
}
148148

149+
if (left_cid == kRecordCid) {
150+
// TODO(dartbug.com/49719)
151+
UNIMPLEMENTED();
152+
}
153+
149154
const Class& cls = Class::Handle(zone, left.clazz());
150155
if (!cls.IsGeneric()) {
151156
return true;

runtime/vm/app_snapshot.cc

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4976,6 +4976,94 @@ class GrowableObjectArrayDeserializationCluster
49764976
}
49774977
};
49784978

4979+
#if !defined(DART_PRECOMPILED_RUNTIME)
4980+
class RecordSerializationCluster : public SerializationCluster {
4981+
public:
4982+
explicit RecordSerializationCluster(bool is_canonical)
4983+
: SerializationCluster("Record", kRecordCid, kSizeVaries, is_canonical) {}
4984+
~RecordSerializationCluster() {}
4985+
4986+
void Trace(Serializer* s, ObjectPtr object) {
4987+
RecordPtr record = Record::RawCast(object);
4988+
objects_.Add(record);
4989+
4990+
s->Push(record->untag()->field_names());
4991+
const intptr_t num_fields = record->untag()->num_fields_;
4992+
for (intptr_t i = 0; i < num_fields; ++i) {
4993+
s->Push(record->untag()->field(i));
4994+
}
4995+
}
4996+
4997+
void WriteAlloc(Serializer* s) {
4998+
const intptr_t count = objects_.length();
4999+
s->WriteUnsigned(count);
5000+
for (intptr_t i = 0; i < count; ++i) {
5001+
RecordPtr record = objects_[i];
5002+
s->AssignRef(record);
5003+
AutoTraceObject(record);
5004+
const intptr_t num_fields = record->untag()->num_fields_;
5005+
s->WriteUnsigned(num_fields);
5006+
target_memory_size_ += compiler::target::Record::InstanceSize(num_fields);
5007+
}
5008+
}
5009+
5010+
void WriteFill(Serializer* s) {
5011+
const intptr_t count = objects_.length();
5012+
for (intptr_t i = 0; i < count; ++i) {
5013+
RecordPtr record = objects_[i];
5014+
AutoTraceObject(record);
5015+
const intptr_t num_fields = record->untag()->num_fields_;
5016+
s->WriteUnsigned(num_fields);
5017+
WriteField(record, field_names());
5018+
for (intptr_t j = 0; j < num_fields; ++j) {
5019+
s->WriteElementRef(record->untag()->field(j), j);
5020+
}
5021+
}
5022+
}
5023+
5024+
private:
5025+
GrowableArray<RecordPtr> objects_;
5026+
};
5027+
#endif // !DART_PRECOMPILED_RUNTIME
5028+
5029+
class RecordDeserializationCluster
5030+
: public AbstractInstanceDeserializationCluster {
5031+
public:
5032+
explicit RecordDeserializationCluster(bool is_canonical)
5033+
: AbstractInstanceDeserializationCluster("Record", is_canonical) {}
5034+
~RecordDeserializationCluster() {}
5035+
5036+
void ReadAlloc(Deserializer* d) {
5037+
start_index_ = d->next_index();
5038+
PageSpace* old_space = d->heap()->old_space();
5039+
const intptr_t count = d->ReadUnsigned();
5040+
for (intptr_t i = 0; i < count; i++) {
5041+
const intptr_t num_fields = d->ReadUnsigned();
5042+
d->AssignRef(
5043+
old_space->AllocateSnapshot(Record::InstanceSize(num_fields)));
5044+
}
5045+
stop_index_ = d->next_index();
5046+
}
5047+
5048+
void ReadFill(Deserializer* d_, bool primary) {
5049+
Deserializer::Local d(d_);
5050+
5051+
const bool stamp_canonical = primary && is_canonical();
5052+
for (intptr_t id = start_index_, n = stop_index_; id < n; id++) {
5053+
RecordPtr record = static_cast<RecordPtr>(d.Ref(id));
5054+
const intptr_t num_fields = d.ReadUnsigned();
5055+
Deserializer::InitializeHeader(record, kRecordCid,
5056+
Record::InstanceSize(num_fields),
5057+
stamp_canonical);
5058+
record->untag()->num_fields_ = num_fields;
5059+
record->untag()->field_names_ = static_cast<ArrayPtr>(d.ReadRef());
5060+
for (intptr_t j = 0; j < num_fields; ++j) {
5061+
record->untag()->data()[j] = d.ReadRef();
5062+
}
5063+
}
5064+
}
5065+
};
5066+
49795067
#if !defined(DART_PRECOMPILED_RUNTIME)
49805068
class TypedDataSerializationCluster : public SerializationCluster {
49815069
public:
@@ -6998,6 +7086,8 @@ SerializationCluster* Serializer::NewClusterForClass(intptr_t cid,
69987086
return new (Z) DoubleSerializationCluster(is_canonical);
69997087
case kGrowableObjectArrayCid:
70007088
return new (Z) GrowableObjectArraySerializationCluster();
7089+
case kRecordCid:
7090+
return new (Z) RecordSerializationCluster(is_canonical);
70017091
case kStackTraceCid:
70027092
return new (Z) StackTraceSerializationCluster();
70037093
case kRegExpCid:
@@ -8147,6 +8237,8 @@ DeserializationCluster* Deserializer::ReadCluster() {
81478237
case kGrowableObjectArrayCid:
81488238
ASSERT(!is_canonical);
81498239
return new (Z) GrowableObjectArrayDeserializationCluster();
8240+
case kRecordCid:
8241+
return new (Z) RecordDeserializationCluster(is_canonical);
81508242
case kStackTraceCid:
81518243
ASSERT(!is_canonical);
81528244
return new (Z) StackTraceDeserializationCluster();

runtime/vm/class_finalizer.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,11 @@ AbstractTypePtr ClassFinalizer::FinalizeRecordType(
927927
record.SetFieldTypeAt(i, finalized_type);
928928
}
929929
}
930+
// Canonicalize field names so they can be compared with pointer comparison.
931+
// The field names are already sorted in the front-end.
932+
Array& field_names = Array::Handle(zone, record.field_names());
933+
field_names ^= field_names.Canonicalize(Thread::Current());
934+
record.set_field_names(field_names);
930935

931936
if (FLAG_trace_type_finalization) {
932937
THR_Print("Marking record type '%s' as finalized\n",

runtime/vm/class_id.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ typedef uint16_t ClassIdTagType;
8686
V(Float32x4) \
8787
V(Int32x4) \
8888
V(Float64x2) \
89+
V(Record) \
8990
V(TypedDataBase) \
9091
V(TypedData) \
9192
V(ExternalTypedData) \

runtime/vm/compiler/asm_intrinsifier_arm.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,9 @@ void AsmIntrinsifier::ObjectRuntimeType(Assembler* assembler,
10811081
__ CompareImmediate(R1, kClosureCid);
10821082
__ b(normal_ir_body, EQ); // Instance is a closure.
10831083

1084+
__ CompareImmediate(R1, kRecordCid);
1085+
__ b(normal_ir_body, EQ); // Instance is a record.
1086+
10841087
__ CompareImmediate(R1, kNumPredefinedCids);
10851088
__ b(&use_declaration_type, HI);
10861089

@@ -1140,6 +1143,10 @@ static void EquivalentClassIds(Assembler* assembler,
11401143
__ CompareImmediate(cid1, kClosureCid);
11411144
__ b(normal_ir_body, EQ);
11421145

1146+
// Check if left hand side is a record. Records are handled in the runtime.
1147+
__ CompareImmediate(cid1, kRecordCid);
1148+
__ b(normal_ir_body, EQ);
1149+
11431150
// Check whether class ids match. If class ids don't match types may still be
11441151
// considered equivalent (e.g. multiple string implementation classes map to a
11451152
// single String type).

runtime/vm/compiler/asm_intrinsifier_arm64.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,9 @@ void AsmIntrinsifier::ObjectRuntimeType(Assembler* assembler,
12431243
__ CompareImmediate(R1, kClosureCid);
12441244
__ b(normal_ir_body, EQ); // Instance is a closure.
12451245

1246+
__ CompareImmediate(R1, kRecordCid);
1247+
__ b(normal_ir_body, EQ); // Instance is a record.
1248+
12461249
__ CompareImmediate(R1, kNumPredefinedCids);
12471250
__ b(&use_declaration_type, HI);
12481251

@@ -1305,6 +1308,10 @@ static void EquivalentClassIds(Assembler* assembler,
13051308
__ CompareImmediate(cid1, kClosureCid);
13061309
__ b(normal_ir_body, EQ);
13071310

1311+
// Check if left hand side is a record. Records are handled in the runtime.
1312+
__ CompareImmediate(cid1, kRecordCid);
1313+
__ b(normal_ir_body, EQ);
1314+
13081315
// Check whether class ids match. If class ids don't match types may still be
13091316
// considered equivalent (e.g. multiple string implementation classes map to a
13101317
// single String type).

runtime/vm/compiler/asm_intrinsifier_ia32.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,9 @@ void AsmIntrinsifier::ObjectRuntimeType(Assembler* assembler,
11861186
__ cmpl(EDI, Immediate(kClosureCid));
11871187
__ j(EQUAL, normal_ir_body); // Instance is a closure.
11881188

1189+
__ cmpl(EDI, Immediate(kRecordCid));
1190+
__ j(EQUAL, normal_ir_body); // Instance is a record.
1191+
11891192
__ cmpl(EDI, Immediate(kNumPredefinedCids));
11901193
__ j(ABOVE, &use_declaration_type);
11911194

@@ -1262,6 +1265,10 @@ static void EquivalentClassIds(Assembler* assembler,
12621265
__ cmpl(cid1, Immediate(kClosureCid));
12631266
__ j(EQUAL, normal_ir_body);
12641267

1268+
// Check if left hand side is a record. Records are handled in the runtime.
1269+
__ cmpl(cid1, Immediate(kRecordCid));
1270+
__ j(EQUAL, normal_ir_body);
1271+
12651272
// Check whether class ids match. If class ids don't match types may still be
12661273
// considered equivalent (e.g. multiple string implementation classes map to a
12671274
// single String type).

runtime/vm/compiler/asm_intrinsifier_riscv.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,9 @@ void AsmIntrinsifier::ObjectRuntimeType(Assembler* assembler,
12621262
__ CompareImmediate(A1, kClosureCid);
12631263
__ BranchIf(EQ, normal_ir_body); // Instance is a closure.
12641264

1265+
__ CompareImmediate(A1, kRecordCid);
1266+
__ BranchIf(EQ, normal_ir_body); // Instance is a record.
1267+
12651268
__ CompareImmediate(A1, kNumPredefinedCids);
12661269
__ BranchIf(HI, &use_declaration_type, Assembler::kNearJump);
12671270

@@ -1320,6 +1323,10 @@ static void EquivalentClassIds(Assembler* assembler,
13201323
__ CompareImmediate(cid1, kClosureCid);
13211324
__ BranchIf(EQ, normal_ir_body);
13221325

1326+
// Check if left hand side is a record. Records are handled in the runtime.
1327+
__ CompareImmediate(cid1, kRecordCid);
1328+
__ BranchIf(EQ, normal_ir_body);
1329+
13231330
// Check whether class ids match. If class ids don't match types may still be
13241331
// considered equivalent (e.g. multiple string implementation classes map to a
13251332
// single String type).

runtime/vm/compiler/asm_intrinsifier_x64.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,9 @@ void AsmIntrinsifier::ObjectRuntimeType(Assembler* assembler,
10901090
__ cmpq(RCX, Immediate(kClosureCid));
10911091
__ j(EQUAL, normal_ir_body); // Instance is a closure.
10921092

1093+
__ cmpq(RCX, Immediate(kRecordCid));
1094+
__ j(EQUAL, normal_ir_body); // Instance is a record.
1095+
10931096
__ cmpl(RCX, Immediate(kNumPredefinedCids));
10941097
__ j(ABOVE, &use_declaration_type);
10951098

@@ -1167,6 +1170,10 @@ static void EquivalentClassIds(Assembler* assembler,
11671170
__ cmpq(cid1, Immediate(kClosureCid));
11681171
__ j(EQUAL, normal_ir_body);
11691172

1173+
// Check if left hand side is a record. Records are handled in the runtime.
1174+
__ cmpq(cid1, Immediate(kRecordCid));
1175+
__ j(EQUAL, normal_ir_body);
1176+
11701177
// Check whether class ids match. If class ids don't match types may still be
11711178
// considered equivalent (e.g. multiple string implementation classes map to a
11721179
// single String type).

runtime/vm/compiler/backend/flow_graph_compiler.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2805,6 +2805,12 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
28052805
__ BranchIf(EQUAL, is_instance_lbl);
28062806
return true;
28072807
}
2808+
if (type.IsDartRecordType()) {
2809+
// Check if instance is a record.
2810+
__ CompareImmediate(kScratchReg, kRecordCid);
2811+
__ BranchIf(EQUAL, is_instance_lbl);
2812+
return true;
2813+
}
28082814

28092815
// Fast case for cid-range based checks.
28102816
// Warning: This code destroys the contents of [kScratchReg], so this should

runtime/vm/compiler/backend/il_serializer.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,6 +1598,11 @@ void FlowGraphSerializer::WriteObjectImpl(const Object& x,
15981598
stream_->WriteBytes(latin1, length);
15991599
break;
16001600
}
1601+
case kRecordCid: {
1602+
// TODO(dartbug.com/49719)
1603+
UNIMPLEMENTED();
1604+
break;
1605+
}
16011606
case kRecordTypeCid: {
16021607
// TODO(dartbug.com/49719)
16031608
UNIMPLEMENTED();
@@ -1863,6 +1868,11 @@ const Object& FlowGraphDeserializer::ReadObjectImpl(intptr_t cid,
18631868
return String::ZoneHandle(Z,
18641869
Symbols::FromLatin1(thread(), latin1, length));
18651870
}
1871+
case kRecordCid: {
1872+
// TODO(dartbug.com/49719)
1873+
UNIMPLEMENTED();
1874+
break;
1875+
}
18661876
case kRecordTypeCid: {
18671877
// TODO(dartbug.com/49719)
18681878
UNIMPLEMENTED();

runtime/vm/compiler/backend/inliner.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4216,7 +4216,8 @@ bool FlowGraphInliner::TryInlineRecognizedMethod(
42164216
type = Type::IntType();
42174217
} else if (IsTypeClassId(receiver_cid)) {
42184218
type = Type::DartTypeType();
4219-
} else if (receiver_cid != kClosureCid) {
4219+
} else if ((receiver_cid != kClosureCid) &&
4220+
(receiver_cid != kRecordCid)) {
42204221
const Class& cls = Class::Handle(
42214222
Z, flow_graph->isolate_group()->class_table()->At(receiver_cid));
42224223
if (!cls.IsGeneric()) {

runtime/vm/compiler/backend/type_propagator.cc

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -773,10 +773,8 @@ intptr_t CompileType::ToNullableCid() {
773773
cid_ = kSentinelCid;
774774
} else if (type_->IsFunctionType() || type_->IsDartFunctionType()) {
775775
cid_ = kClosureCid;
776-
} else if (type_->IsRecordType()) {
777-
// TODO(dartbug.com/49719)
778-
// cid_ = kRecordCid;
779-
UNIMPLEMENTED();
776+
} else if (type_->IsRecordType() || type_->IsDartRecordType()) {
777+
cid_ = kRecordCid;
780778
} else if (type_->type_class_id() != kIllegalCid) {
781779
const Class& type_class = Class::Handle(type_->type_class());
782780
intptr_t implementation_cid = kIllegalCid;

runtime/vm/compiler/runtime_api.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,16 @@ class GrowableObjectArray : public AllStatic {
589589
FINAL_CLASS();
590590
};
591591

592+
class Record : public AllStatic {
593+
public:
594+
static word num_fields_offset();
595+
static word field_names_offset();
596+
static word field_offset(intptr_t index);
597+
static word InstanceSize(intptr_t length);
598+
static word InstanceSize();
599+
FINAL_CLASS();
600+
};
601+
592602
class PointerBase : public AllStatic {
593603
public:
594604
static word data_offset();

0 commit comments

Comments
 (0)