| Index: runtime/vm/intermediate_language_x64.cc
|
| diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
|
| index 06c52785fa222ee67cb0778b8e4a566a4e36b87a..c2b436811a0a87931569f4923858defa3bcac04b 100644
|
| --- a/runtime/vm/intermediate_language_x64.cc
|
| +++ b/runtime/vm/intermediate_language_x64.cc
|
| @@ -13,6 +13,7 @@
|
| #include "vm/locations.h"
|
| #include "vm/object_store.h"
|
| #include "vm/parser.h"
|
| +#include "vm/stack_frame.h"
|
| #include "vm/stub_code.h"
|
| #include "vm/symbols.h"
|
|
|
| @@ -1332,21 +1333,293 @@ void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| }
|
|
|
|
|
| +LocationSummary* GuardFieldInstr::MakeLocationSummary() const {
|
| + const intptr_t kNumInputs = 1;
|
| + LocationSummary* summary =
|
| + new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
|
| + summary->set_in(0, Location::RequiresRegister());
|
| + if (value()->Type()->ToCid() == kDynamicCid) {
|
| + summary->AddTemp(Location::RequiresRegister());
|
| + }
|
| + if (field().guarded_cid() == kIllegalCid) {
|
| + summary->AddTemp(Location::RequiresRegister());
|
| + }
|
| + return summary;
|
| +}
|
| +
|
| +
|
| +static void PushCid(FlowGraphCompiler* compiler, const Immediate& imm) {
|
| + __ pushq(Immediate(Smi::RawValue(imm.value())));
|
| +}
|
| +
|
| +
|
| +static void PushCid(FlowGraphCompiler* compiler, Register reg) {
|
| + __ SmiTag(reg);
|
| + __ pushq(reg);
|
| +}
|
| +
|
| +
|
| +template<typename ValueCidOperandType>
|
| +static void EmitCidGuardInit(FlowGraphCompiler* compiler,
|
| + ValueCidOperandType value_cid,
|
| + const Immediate& field_cid,
|
| + const Immediate& nullability,
|
| + Label* deopt,
|
| + Label* ok) {
|
| + // nothing to do.
|
| +}
|
| +
|
| +
|
| +template<typename ValueCidOperandType>
|
| +static void EmitCidGuardInit(FlowGraphCompiler* compiler,
|
| + ValueCidOperandType value_cid,
|
| + const FieldAddress& field_cid,
|
| + const FieldAddress& nullability,
|
| + Label* deopt,
|
| + Label* ok) {
|
| + // Check if field is initialized for the first time.
|
| + Label fail;
|
| + __ cmpq(field_cid, Immediate(kIllegalCid));
|
| + __ j(NOT_EQUAL, (deopt != NULL) ? deopt : &fail);
|
| + __ movq(field_cid, value_cid);
|
| + __ movq(nullability, value_cid);
|
| + __ jmp(ok);
|
| + if (deopt == NULL) {
|
| + __ Bind(&fail);
|
| + }
|
| +}
|
| +
|
| +
|
| +static void CompareJump(FlowGraphCompiler* compiler,
|
| + Condition cond,
|
| + const Immediate& left,
|
| + const Immediate& right,
|
| + Label* target) {
|
| + if ((left.value() == right.value()) && (cond == EQUAL)) {
|
| + __ jmp(target);
|
| + } else if ((left.value() != right.value()) && cond == NOT_EQUAL) {
|
| + __ jmp(target);
|
| + }
|
| +}
|
| +
|
| +
|
| +static void CompareJump(FlowGraphCompiler* compiler,
|
| + Condition cond,
|
| + Immediate left,
|
| + Register right,
|
| + Label* target) {
|
| + ASSERT((cond == EQUAL) || (cond == NOT_EQUAL));
|
| + __ cmpq(right, left);
|
| + __ j(cond, target);
|
| +}
|
| +
|
| +
|
| +template<typename LeftT, typename RightT>
|
| +static void CompareJump(FlowGraphCompiler* compiler,
|
| + Condition cond,
|
| + LeftT left,
|
| + RightT right,
|
| + Label* target) {
|
| + __ cmpq(left, right);
|
| + __ j(cond, target);
|
| +}
|
| +
|
| +
|
| +template<typename ValueCidOperandType,
|
| + typename FieldCidOperandType,
|
| + typename FieldNullabilityOperandType>
|
| +static void EmitCidGuard(FlowGraphCompiler* compiler,
|
| + const Field& field,
|
| + ValueCidOperandType value_cid,
|
| + FieldCidOperandType field_cid,
|
| + FieldNullabilityOperandType nullability,
|
| + Label* deopt) {
|
| + Label ok, update;
|
| + CompareJump(compiler, EQUAL, field_cid, value_cid, &ok);
|
| + if ((deopt != NULL) && (field.guarded_cid() != kIllegalCid)) {
|
| + CompareJump(compiler, NOT_EQUAL, nullability, value_cid, deopt);
|
| + } else {
|
| + CompareJump(compiler, EQUAL, nullability, value_cid, &ok);
|
| + }
|
| +
|
| + EmitCidGuardInit(compiler, value_cid, field_cid, nullability, deopt, &ok);
|
| +
|
| + if (deopt == NULL) {
|
| + // Switch field's cid to dynamic and notify runtime.
|
| + CompareJump(compiler, EQUAL, field_cid, Immediate(kDynamicCid), &ok);
|
| + __ PushObject(field);
|
| + PushCid(compiler, value_cid);
|
| + __ CallRuntime(kUpdateFieldCidRuntimeEntry);
|
| + __ Drop(2);
|
| + }
|
| +
|
| + __ Bind(&ok);
|
| +}
|
| +
|
| +
|
| +template<typename FieldCidOperandType, typename FieldNullabilityOperandType>
|
| +static void EmitCidGuard(FlowGraphCompiler* compiler,
|
| + const Field& field,
|
| + intptr_t value_cid,
|
| + Register value_cid_reg,
|
| + FieldCidOperandType field_cid,
|
| + FieldNullabilityOperandType nullability,
|
| + Label* deopt) {
|
| + if (value_cid == kDynamicCid) {
|
| + EmitCidGuard(compiler, field, value_cid_reg, field_cid, nullability, deopt);
|
| + } else {
|
| + EmitCidGuard(compiler,
|
| + field,
|
| + Immediate(value_cid),
|
| + field_cid,
|
| + nullability,
|
| + deopt);
|
| + }
|
| +}
|
| +
|
| +
|
| +static void EmitFieldGuard(FlowGraphCompiler* compiler,
|
| + Register value_reg,
|
| + const Field& field,
|
| + intptr_t value_cid,
|
| + Register value_cid_reg,
|
| + intptr_t field_cid,
|
| + intptr_t nullability,
|
| + Register field_reg,
|
| + Label* deopt) {
|
| + if (value_cid == kDynamicCid) {
|
| + Label not_smi, cid_loaded;
|
| + __ testq(value_reg, Immediate(kSmiTagMask));
|
| + __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump);
|
| + __ movq(value_cid_reg, Immediate(kSmiCid));
|
| + __ jmp(&cid_loaded);
|
| + __ Bind(¬_smi);
|
| + __ LoadClassId(value_cid_reg, value_reg);
|
| + __ Bind(&cid_loaded);
|
| + }
|
| +
|
| + if (field_cid == kIllegalCid) {
|
| + __ LoadObject(field_reg, Field::ZoneHandle(field.raw()));
|
| + EmitCidGuard(compiler,
|
| + field,
|
| + value_cid,
|
| + value_cid_reg,
|
| + FieldAddress(field_reg, Field::guarded_cid_offset()),
|
| + FieldAddress(field_reg, Field::is_nullable_offset()),
|
| + deopt);
|
| + } else {
|
| + EmitCidGuard(compiler,
|
| + field,
|
| + value_cid,
|
| + value_cid_reg,
|
| + Immediate(field_cid),
|
| + Immediate(nullability),
|
| + deopt);
|
| + }
|
| +}
|
| +
|
| +
|
| +void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| + const intptr_t value_cid = value()->Type()->ToCid();
|
| + const intptr_t field_cid = field().guarded_cid();
|
| + const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
|
| +
|
| + Register value_reg = locs()->in(0).reg();
|
| +
|
| + Register value_cid_reg = (value_cid == kDynamicCid) ?
|
| + locs()->temp(0).reg() : kNoRegister;
|
| +
|
| + Label* deopt = compiler->is_optimizing() && CanDeoptimize() ?
|
| + compiler->AddDeoptStub(deopt_id(), kDeoptStoreInstanceField) : NULL;
|
| +
|
| + if ((deopt != NULL) && (field_cid != kIllegalCid)) {
|
| + if (value_cid != kDynamicCid) {
|
| + ASSERT(field_cid != value_cid);
|
| + __ jmp(deopt);
|
| + return;
|
| + }
|
| +
|
| + if (field_cid == kSmiCid) {
|
| + __ testq(value_reg, Immediate(kSmiTagMask));
|
| + } else {
|
| + ASSERT(value_cid_reg != kNoRegister);
|
| + __ testq(value_reg, Immediate(kSmiTagMask));
|
| + __ j(ZERO, deopt);
|
| + __ LoadClassId(value_cid_reg, value_reg);
|
| + __ cmpq(value_cid_reg, Immediate(field_cid));
|
| + }
|
| +
|
| + if (field().is_nullable()) {
|
| + Label ok;
|
| + __ j(EQUAL, &ok);
|
| + const Immediate& raw_null =
|
| + Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
| + __ cmpq(value_reg, raw_null);
|
| + __ j(NOT_EQUAL, deopt);
|
| + __ Bind(&ok);
|
| + } else {
|
| + __ j(NOT_EQUAL, deopt);
|
| + }
|
| +
|
| + return;
|
| + }
|
| +
|
| + Register field_reg = (field_cid == kIllegalCid) ?
|
| + locs()->temp(1).reg() : kNoRegister;
|
| +
|
| + EmitFieldGuard(compiler,
|
| + value_reg,
|
| + field(),
|
| + value_cid, value_cid_reg,
|
| + field_cid, nullability, field_reg,
|
| + deopt);
|
| +}
|
| +
|
| +
|
| LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const {
|
| const intptr_t kNumInputs = 2;
|
| const intptr_t num_temps = 0;
|
| LocationSummary* summary =
|
| new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall);
|
| summary->set_in(0, Location::RequiresRegister());
|
| - summary->set_in(1, ShouldEmitStoreBarrier()
|
| + summary->set_in(1, (ShouldEmitStoreBarrier() || should_emit_field_guard())
|
| ? Location::WritableRegister()
|
| : Location::RegisterOrConstant(value()));
|
| +
|
| + if (should_emit_field_guard()) {
|
| + summary->AddTemp(Location::RequiresRegister());
|
| + summary->AddTemp(Location::RequiresRegister());
|
| + }
|
| +
|
| return summary;
|
| }
|
|
|
|
|
| void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| Register instance_reg = locs()->in(0).reg();
|
| +
|
| +
|
| + if (should_emit_field_guard()) {
|
| + ASSERT(!compiler->is_optimizing());
|
| + Register value_reg = locs()->in(1).reg();
|
| + Register value_cid_reg = locs()->temp(0).reg();
|
| + Register field_reg = locs()->temp(1).reg();
|
| +
|
| + __ pushq(instance_reg);
|
| + __ pushq(value_reg);
|
| + EmitFieldGuard(compiler,
|
| + value_reg,
|
| + field(),
|
| + kDynamicCid,
|
| + value_cid_reg,
|
| + kIllegalCid,
|
| + kIllegalCid,
|
| + field_reg,
|
| + NULL);
|
| + __ popq(value_reg);
|
| + __ popq(instance_reg);
|
| + }
|
| +
|
| if (ShouldEmitStoreBarrier()) {
|
| Register value_reg = locs()->in(1).reg();
|
| __ StoreIntoObject(instance_reg,
|
| @@ -2680,16 +2953,28 @@ void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
| LocationSummary* CheckClassInstr::MakeLocationSummary() const {
|
| const intptr_t kNumInputs = 1;
|
| - const intptr_t kNumTemps = 1;
|
| + const intptr_t kNumTemps = 0;
|
| LocationSummary* summary =
|
| new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| summary->set_in(0, Location::RequiresRegister());
|
| - summary->set_temp(0, Location::RequiresRegister());
|
| + if (!null_check()) {
|
| + summary->AddTemp(Location::RequiresRegister());
|
| + }
|
| return summary;
|
| }
|
|
|
|
|
| void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| + if (null_check()) {
|
| + Label* deopt = compiler->AddDeoptStub(deopt_id(),
|
| + kDeoptCheckClass);
|
| + const Immediate& raw_null =
|
| + Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
| + __ cmpq(locs()->in(0).reg(), raw_null);
|
| + __ j(EQUAL, deopt);
|
| + return;
|
| + }
|
| +
|
| ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) ||
|
| (unary_checks().NumberOfChecks() > 1));
|
| Register value = locs()->in(0).reg();
|
|
|