Small cleanup and more test coverage for guarded fields.

Some cases of field guards for guarded length  were not covered by our tests.

Otherwise I removed redundant conditions that are either impossible
or always true from the code generator for GuardFieldInstr.

R=johnmccutchan@google.com

Review URL: https://codereview.chromium.org//104583002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@30887 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
fschneider@google.com 2013-12-05 11:17:06 +00:00
parent 416f9863e9
commit 5aa02dce31
5 changed files with 109 additions and 119 deletions

View file

@ -1488,7 +1488,25 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (!ok_is_fall_through) {
__ b(&ok);
}
if (deopt == NULL) {
ASSERT(!compiler->is_optimizing());
__ Bind(fail);
__ ldr(IP, FieldAddress(field_reg, Field::guarded_cid_offset()));
__ CompareImmediate(IP, kDynamicCid);
__ b(&ok, EQ);
__ Push(field_reg);
__ Push(value_reg);
__ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
__ Drop(2); // Drop the field and the value.
}
} else {
ASSERT(compiler->is_optimizing());
ASSERT(deopt != NULL);
ASSERT(ok_is_fall_through);
// Field guard class has been initialized and is known.
if (field_reg != kNoRegister) {
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
}
@ -1527,18 +1545,11 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ CompareImmediate(value_reg,
reinterpret_cast<intptr_t>(Object::null()));
}
if (ok_is_fall_through) {
__ b(fail, NE);
} else {
__ b(&ok, EQ);
}
__ b(fail, NE);
} else {
// Both value's and field's class id is known.
if ((value_cid != field_cid) && (value_cid != nullability)) {
if (ok_is_fall_through) {
__ b(fail);
}
__ b(fail);
} else if (field_has_length && (value_cid == field_cid)) {
ASSERT(value_cid_reg != kNoRegister);
if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
@ -1551,31 +1562,12 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
FieldAddress(value_reg, TypedData::length_offset()));
}
__ CompareImmediate(value_cid_reg, field_length);
if (ok_is_fall_through) {
__ b(fail, NE);
}
__ b(fail, NE);
} else {
// Nothing to emit.
ASSERT(!compiler->is_optimizing());
return;
UNREACHABLE();
}
}
}
if (deopt == NULL) {
ASSERT(!compiler->is_optimizing());
__ Bind(fail);
__ ldr(IP, FieldAddress(field_reg, Field::guarded_cid_offset()));
__ CompareImmediate(IP, kDynamicCid);
__ b(&ok, EQ);
__ Push(field_reg);
__ Push(value_reg);
__ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
__ Drop(2); // Drop the field and the value.
}
__ Bind(&ok);
}

View file

@ -1494,7 +1494,24 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (!ok_is_fall_through) {
__ jmp(&ok);
}
if (deopt == NULL) {
ASSERT(!compiler->is_optimizing());
__ Bind(fail);
__ cmpl(FieldAddress(field_reg, Field::guarded_cid_offset()),
Immediate(kDynamicCid));
__ j(EQUAL, &ok);
__ pushl(field_reg);
__ pushl(value_reg);
__ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
__ Drop(2); // Drop the field and the value.
}
} else {
ASSERT(compiler->is_optimizing());
ASSERT(deopt != NULL);
ASSERT(ok_is_fall_through);
// Field guard class has been initialized and is known.
if (field_reg != kNoRegister) {
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
@ -1537,18 +1554,11 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ cmpl(value_reg, raw_null);
}
if (ok_is_fall_through) {
__ j(NOT_EQUAL, fail);
} else {
__ j(EQUAL, &ok);
}
__ j(NOT_EQUAL, fail);
} else {
// Both value's and field's class id is known.
if ((value_cid != field_cid) && (value_cid != nullability)) {
if (ok_is_fall_through) {
__ jmp(fail);
}
__ jmp(fail);
} else if (field_has_length && (value_cid == field_cid)) {
ASSERT(value_cid_reg != kNoRegister);
if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
@ -1561,31 +1571,12 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
FieldAddress(value_reg, TypedData::length_offset()));
}
__ cmpl(value_cid_reg, Immediate(Smi::RawValue(field_length)));
if (ok_is_fall_through) {
__ j(NOT_EQUAL, fail);
}
__ j(NOT_EQUAL, fail);
} else {
// Nothing to emit.
ASSERT(!compiler->is_optimizing());
return;
UNREACHABLE();
}
}
}
if (deopt == NULL) {
ASSERT(!compiler->is_optimizing());
__ Bind(fail);
__ cmpl(FieldAddress(field_reg, Field::guarded_cid_offset()),
Immediate(kDynamicCid));
__ j(EQUAL, &ok);
__ pushl(field_reg);
__ pushl(value_reg);
__ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
__ Drop(2); // Drop the field and the value.
}
__ Bind(&ok);
}

View file

@ -1552,7 +1552,25 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (!ok_is_fall_through) {
__ b(&ok);
}
if (deopt == NULL) {
ASSERT(!compiler->is_optimizing());
__ Bind(fail);
__ lw(CMPRES1, FieldAddress(field_reg, Field::guarded_cid_offset()));
__ BranchEqual(CMPRES1, kDynamicCid, &ok);
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(field_reg, Address(SP, 1 * kWordSize));
__ sw(value_reg, Address(SP, 0 * kWordSize));
__ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
__ Drop(2); // Drop the field and the value.
}
} else {
ASSERT(compiler->is_optimizing());
ASSERT(deopt != NULL);
ASSERT(ok_is_fall_through);
// Field guard class has been initialized and is known.
if (field_reg != kNoRegister) {
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
}
@ -1594,17 +1612,11 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ subu(CMPRES1, value_reg, TMP);
}
if (ok_is_fall_through) {
__ bne(CMPRES1, ZR, fail);
} else {
__ beq(CMPRES1, ZR, &ok);
}
__ bne(CMPRES1, ZR, fail);
} else {
// Both value's and field's class id is known.
if ((value_cid != field_cid) && (value_cid != nullability)) {
if (ok_is_fall_through) {
__ b(fail);
}
__ b(fail);
} else if (field_has_length && (value_cid == field_cid)) {
ASSERT(value_cid_reg != kNoRegister);
if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
@ -1618,31 +1630,12 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
}
__ LoadImmediate(TMP, Smi::RawValue(field_length));
__ subu(CMPRES1, value_cid_reg, TMP);
if (ok_is_fall_through) {
__ bne(CMPRES1, ZR, fail);
}
__ bne(CMPRES1, ZR, fail);
} else {
// Nothing to emit.
ASSERT(!compiler->is_optimizing());
return;
UNREACHABLE();
}
}
}
if (deopt == NULL) {
ASSERT(!compiler->is_optimizing());
__ Bind(fail);
__ lw(CMPRES1, FieldAddress(field_reg, Field::guarded_cid_offset()));
__ BranchEqual(CMPRES1, kDynamicCid, &ok);
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(field_reg, Address(SP, 1 * kWordSize));
__ sw(value_reg, Address(SP, 0 * kWordSize));
__ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
__ Drop(2); // Drop the field and the value.
}
__ Bind(&ok);
}

View file

@ -1390,7 +1390,25 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (!ok_is_fall_through) {
__ jmp(&ok);
}
if (deopt == NULL) {
ASSERT(!compiler->is_optimizing());
__ Bind(fail);
__ CompareImmediate(FieldAddress(field_reg, Field::guarded_cid_offset()),
Immediate(kDynamicCid), PP);
__ j(EQUAL, &ok);
__ pushq(field_reg);
__ pushq(value_reg);
__ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
__ Drop(2); // Drop the field and the value.
}
} else {
ASSERT(compiler->is_optimizing());
ASSERT(deopt != NULL);
ASSERT(ok_is_fall_through);
// Field guard class has been initialized and is known.
if (field_reg != kNoRegister) {
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP);
}
@ -1430,18 +1448,11 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ j(EQUAL, &ok);
__ CompareObject(value_reg, Object::null_object(), PP);
}
if (ok_is_fall_through) {
__ j(NOT_EQUAL, fail);
} else {
__ j(EQUAL, &ok);
}
__ j(NOT_EQUAL, fail);
} else {
// Both value's and field's class id is known.
if ((value_cid != field_cid) && (value_cid != nullability)) {
if (ok_is_fall_through) {
__ jmp(fail);
}
__ jmp(fail);
} else if (field_has_length && (value_cid == field_cid)) {
ASSERT(value_cid_reg != kNoRegister);
if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
@ -1455,31 +1466,12 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
}
__ CompareImmediate(
value_cid_reg, Immediate(Smi::RawValue(field_length)), PP);
if (ok_is_fall_through) {
__ j(NOT_EQUAL, fail);
}
__ j(NOT_EQUAL, fail);
} else {
// Nothing to emit.
ASSERT(!compiler->is_optimizing());
return;
UNREACHABLE();
}
}
}
if (deopt == NULL) {
ASSERT(!compiler->is_optimizing());
__ Bind(fail);
__ CompareImmediate(FieldAddress(field_reg, Field::guarded_cid_offset()),
Immediate(kDynamicCid), PP);
__ j(EQUAL, &ok);
__ pushq(field_reg);
__ pushq(value_reg);
__ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
__ Drop(2); // Drop the field and the value.
}
__ Bind(&ok);
}

View file

@ -6,6 +6,7 @@
// VMOptions=--optimization_counter_threshold=10
import "package:expect/expect.dart";
import "dart:typed_data";
class A {
var foo;
@ -52,6 +53,24 @@ test_stacktrace() {
}
class D {
final List f;
final Uint8List g;
D(this.f, this.g);
D.named(this.f, this.g);
}
test_guarded_length() {
var a = new D(new List(5), new Uint8List(5));
var b = new D.named(new List(5), new Uint8List(5));
Expect.equals(5, a.f.length);
Expect.equals(5, b.f.length);
Expect.equals(5, a.g.length);
Expect.equals(5, b.g.length);
}
main() {
var a = new A();
var b = new B();
@ -76,4 +95,7 @@ main() {
// Regression test for fields initialized in native code (Error._stackTrace).
test_stacktrace();
// Test guarded list length.
for (var i = 0; i < 20; i++) test_guarded_length();
}