mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 04:17:30 +00:00
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:
parent
416f9863e9
commit
5aa02dce31
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue