Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1131)

Unified Diff: runtime/vm/intermediate_language_mips.cc

Issue 22851003: Initial support for length guards on final fields. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/vm/intermediate_language_mips.cc
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index e84f41817bbca3ea3c821c76cd6b3b4226975bf0..f857d19102f79bd8cd85cc6f7d30a758f190467f 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1573,11 +1573,16 @@ LocationSummary* GuardFieldInstr::MakeLocationSummary() const {
LocationSummary* summary =
new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
- if ((value()->Type()->ToCid() == kDynamicCid) &&
- (field().guarded_cid() != kSmiCid)) {
+ const bool field_has_length = field().needs_length_check();
+ const bool need_value_temp_reg =
+ (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
+ (field().guarded_cid() != kSmiCid)));
+ if (need_value_temp_reg) {
summary->AddTemp(Location::RequiresRegister());
}
- if (field().guarded_cid() == kIllegalCid) {
+ const bool need_field_temp_reg =
+ field_has_length || (field().guarded_cid() == kIllegalCid);
+ if (need_field_temp_reg) {
summary->AddTemp(Location::RequiresRegister());
}
return summary;
@@ -1588,6 +1593,17 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ TraceSimMsg("GuardFieldInstr");
const intptr_t field_cid = field().guarded_cid();
const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
+ const intptr_t field_length = field().guarded_list_length();
+ const bool field_has_length = field().needs_length_check();
+ const bool needs_value_temp_reg =
+ (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
+ (field().guarded_cid() != kSmiCid)));
+ const bool needs_field_temp_reg =
+ field_has_length || (field().guarded_cid() == kIllegalCid);
+ if (field_has_length) {
+ // Currently, we should only see final fields that remember length.
+ ASSERT(field().is_final());
+ }
if (field_cid == kDynamicCid) {
ASSERT(!compiler->is_optimizing());
@@ -1598,10 +1614,10 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register value_reg = locs()->in(0).reg();
- Register value_cid_reg = ((value_cid == kDynamicCid) &&
- (field_cid != kSmiCid)) ? locs()->temp(0).reg() : kNoRegister;
+ Register value_cid_reg = needs_value_temp_reg ?
+ locs()->temp(0).reg() : kNoRegister;
- Register field_reg = (field_cid == kIllegalCid) ?
+ Register field_reg = needs_field_temp_reg ?
locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
Label ok, fail_label;
@@ -1614,7 +1630,7 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const bool ok_is_fall_through = (deopt != NULL);
if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) {
- if (!compiler->is_optimizing()) {
+ if (!compiler->is_optimizing() && (field_reg == kNoRegister)) {
// Currently we can't have different location summaries for optimized
// and non-optimized code. So instead we manually pick up a register
// that is known to be free because we know how non-optimizing compiler
@@ -1628,6 +1644,8 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(
field_reg, Field::is_nullable_offset());
+ FieldAddress field_length_operand(
+ field_reg, Field::guarded_list_length_offset());
if (value_cid == kDynamicCid) {
if (value_cid_reg == kNoRegister) {
@@ -1638,8 +1656,33 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
LoadValueCid(compiler, value_cid_reg, value_reg);
+ Label skip_length_check;
+
__ lw(CMPRES1, field_cid_operand);
- __ beq(value_cid_reg, CMPRES1, &ok);
+ __ bne(value_cid_reg, CMPRES1, &skip_length_check);
+ if (field_has_length) {
+ // Field guard may have remembered list length, check it.
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ __ Push(value_cid_reg);
regis 2013/08/20 21:24:04 Same comment as for ARM.
zra 2013/08/20 21:40:51 Should just be able to use TMP to save/restore val
Cutch 2013/08/20 22:48:51 Done.
Cutch 2013/08/20 22:48:51 Done.
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ LoadImmediate(CMPRES1, field_length);
+ __ subu(CMPRES1, value_cid_reg, CMPRES1);
+ __ Pop(value_cid_reg);
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ __ Push(value_cid_reg);
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ LoadImmediate(CMPRES1, field_length);
+ __ subu(CMPRES1, value_cid_reg, CMPRES1);
+ __ Pop(value_cid_reg);
+ } else {
+ ASSERT(field_cid == kIllegalCid);
+ __ LoadImmediate(CMPRES1, 0x1);
+ }
+ __ bne(CMPRES1, ZR, fail);
+ }
+ __ Bind(&skip_length_check);
__ lw(TMP1, field_nullability_operand);
__ subu(CMPRES, value_cid_reg, TMP1);
} else if (value_cid == kNullCid) {
@@ -1648,10 +1691,40 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ LoadImmediate(CMPRES, value_cid);
__ subu(CMPRES, TMP1, CMPRES);
} else {
+ Label skip_length_check;
// TODO(regis): TMP1 may conflict. Revisit.
__ lw(TMP1, field_cid_operand);
__ LoadImmediate(CMPRES, value_cid);
__ subu(CMPRES, TMP1, CMPRES);
+ __ bne(CMPRES, ZR, &skip_length_check);
+ // Insert length check.
+ if (field_has_length) {
+ if (value_cid_reg == kNoRegister) {
+ ASSERT(!compiler->is_optimizing());
+ value_cid_reg = A1;
+ ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
+ }
+ ASSERT(value_cid_reg != kNoRegister);
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ __ Push(value_cid_reg);
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ LoadImmediate(CMPRES, field_length);
+ __ subu(CMPRES, value_cid_reg, CMPRES);
+ __ Pop(value_cid_reg);
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ __ Push(value_cid_reg);
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ LoadImmediate(CMPRES, field_length);
+ __ subu(CMPRES, value_cid_reg, CMPRES);
+ __ Pop(value_cid_reg);
+ } else {
+ ASSERT(field_cid == kIllegalCid);
+ __ LoadImmediate(CMPRES, 0x1);
+ }
+ }
+ __ Bind(&skip_length_check);
}
__ beq(CMPRES, ZR, &ok);
@@ -1661,16 +1734,72 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (value_cid == kDynamicCid) {
__ sw(value_cid_reg, field_cid_operand);
__ sw(value_cid_reg, field_nullability_operand);
+ if (field_has_length) {
+ Label check_array, local_exit, local_fail;
+ __ BranchEqual(value_cid_reg, kNullCid, &local_fail);
+ // Check for typed data array.
+ __ BranchSignedGreater(value_cid_reg, kTypedDataFloat32x4ArrayCid,
+ &local_fail);
+ __ BranchSignedLess(value_cid_reg, kTypedDataInt8ArrayCid,
+ &check_array);
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ sw(value_cid_reg, field_length_operand);
+ __ b(&local_exit); // Updated field length typed data array.
+ // Check for regular array.
+ __ Bind(&check_array);
+ __ BranchSignedGreater(value_cid_reg, kImmutableArrayCid,
+ &local_fail);
+ __ BranchSignedLess(value_cid_reg, kArrayCid, &local_fail);
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ sw(value_cid_reg, field_length_operand);
+ __ b(&local_exit); // Updated field length from regular array.
+
+ __ Bind(&local_fail);
+ // TODO(regis): TMP1 may conflict. Revisit.
+ __ LoadImmediate(TMP1, Field::kNoFixedLength);
+ __ sw(TMP1, field_length_operand);
+
+ __ Bind(&local_exit);
+ }
} else {
+ if (value_cid_reg == kNoRegister) {
+ ASSERT(!compiler->is_optimizing());
+ value_cid_reg = A1;
+ ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
+ }
+ ASSERT(value_cid_reg != kNoRegister);
+ ASSERT(field_reg != kNoRegister);
__ LoadImmediate(TMP1, value_cid);
__ sw(TMP1, field_cid_operand);
__ sw(TMP1, field_nullability_operand);
+ if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ __ sw(value_cid_reg, field_length_operand);
+ } else if (RawObject::IsTypedDataClassId(value_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ __ sw(value_cid_reg, field_length_operand);
+ } else {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ LoadImmediate(value_cid_reg, Field::kNoFixedLength);
+ __ sw(value_cid_reg, field_length_operand);
+ }
}
if (!ok_is_fall_through) {
__ b(&ok);
}
} else {
+ if (field_reg != kNoRegister) {
+ __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ }
if (value_cid == kDynamicCid) {
// Field's guarded class id is fixed by value's class id is not known.
__ andi(CMPRES, value_reg, Immediate(kSmiTagMask));
@@ -1682,6 +1811,27 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ subu(CMPRES, value_cid_reg, TMP1);
}
+ if (field_has_length) {
+ // Jump when Value CID != Field guard CID
+ __ bne(CMPRES, ZR, fail);
+ // Classes are same, perform guarded list length check.
+ ASSERT(field_reg != kNoRegister);
+ ASSERT(value_cid_reg != kNoRegister);
+ FieldAddress field_length_operand(
+ field_reg, Field::guarded_list_length_offset());
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ }
+ __ lw(TMP1, field_length_operand);
+ __ subu(CMPRES, value_cid_reg, TMP1);
+ }
+
if (field().is_nullable() && (field_cid != kNullCid)) {
__ beq(CMPRES, ZR, &ok);
__ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
@@ -1699,6 +1849,22 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (ok_is_fall_through) {
__ b(fail);
}
+ } else if (field_has_length && (value_cid == field_cid)) {
+ ASSERT(value_cid_reg != kNoRegister);
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, Array::length_offset()));
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ lw(value_cid_reg,
+ FieldAddress(value_reg, TypedData::length_offset()));
+ }
+ __ LoadImmediate(TMP1, field_length);
+ __ subu(CMPRES, value_cid_reg, TMP1);
+ if (ok_is_fall_through) {
+ __ bne(CMPRES, ZR, fail);
+ }
} else {
// Nothing to emit.
ASSERT(!compiler->is_optimizing());

Powered by Google App Engine
This is Rietveld 408576698