| Index: runtime/vm/intermediate_language_x64.cc
|
| ===================================================================
|
| --- runtime/vm/intermediate_language_x64.cc (revision 8699)
|
| +++ runtime/vm/intermediate_language_x64.cc (working copy)
|
| @@ -199,7 +199,7 @@
|
|
|
| LocationSummary* EqualityCompareComp::MakeLocationSummary() const {
|
| const intptr_t kNumInputs = 2;
|
| - if (operands_class_id() == kSmi) {
|
| + if ((NumTargets() == 1) && (ClassIdAt(0) == kSmi)) {
|
| const intptr_t kNumTemps = 1;
|
| LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps);
|
| locs->set_in(0, Location::RequiresRegister());
|
| @@ -210,18 +210,25 @@
|
| }
|
| return locs;
|
| }
|
| - if (operands_class_id() == kObject) {
|
| - const intptr_t kNumTemps = 0;
|
| + if (NumTargets() > 0) {
|
| + const intptr_t kNumTemps = 1;
|
| LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps);
|
| locs->set_in(0, Location::RequiresRegister());
|
| locs->set_in(1, Location::RequiresRegister());
|
| + locs->set_temp(0, Location::RequiresRegister());
|
| if (!is_fused_with_branch()) {
|
| locs->set_out(Location::RegisterLocation(RAX));
|
| }
|
| return locs;
|
| }
|
| - UNREACHABLE();
|
| - return NULL;
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps);
|
| + locs->set_in(0, Location::RequiresRegister());
|
| + locs->set_in(1, Location::RequiresRegister());
|
| + if (!is_fused_with_branch()) {
|
| + locs->set_out(Location::RegisterLocation(RAX));
|
| + }
|
| + return locs;
|
| }
|
|
|
|
|
| @@ -257,6 +264,109 @@
|
| }
|
|
|
|
|
| +static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
|
| + EqualityCompareComp* comp) {
|
| + compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
|
| + comp->cid(),
|
| + comp->token_index(),
|
| + comp->try_index());
|
| + const String& operator_name = String::ZoneHandle(String::NewSymbol("=="));
|
| + const int kNumberOfArguments = 2;
|
| + const Array& kNoArgumentNames = Array::Handle();
|
| + const int kNumArgumentsChecked = 2;
|
| +
|
| + compiler->GenerateInstanceCall(comp->cid(),
|
| + comp->token_index(),
|
| + comp->try_index(),
|
| + operator_name,
|
| + kNumberOfArguments,
|
| + kNoArgumentNames,
|
| + kNumArgumentsChecked);
|
| + ASSERT(comp->is_fused_with_branch() || (comp->locs()->out().reg() == RAX));
|
| +
|
| + if (comp->is_fused_with_branch()) {
|
| + __ CompareObject(RAX, compiler->bool_true());
|
| + comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
|
| + }
|
| +}
|
| +
|
| +
|
| +static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler,
|
| + EqualityCompareComp* comp,
|
| + Register left,
|
| + Register right) {
|
| + ASSERT(comp->NumTargets() > 0);
|
| + Label* deopt = compiler->AddDeoptStub(comp->cid(),
|
| + comp->token_index(),
|
| + comp->try_index(),
|
| + kDeoptEquality);
|
| + __ testq(left, Immediate(kSmiTagMask));
|
| + Register temp = comp->locs()->temp(0).reg();
|
| + if (comp->ClassIdAt(0) == kSmi) {
|
| + Label done, load_class_id;
|
| + __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump);
|
| + __ movq(temp, Immediate(kSmi));
|
| + __ jmp(&done, Assembler::kNearJump);
|
| + __ Bind(&load_class_id);
|
| + __ LoadClassId(temp, left);
|
| + __ Bind(&done);
|
| + } else {
|
| + __ j(ZERO, deopt); // Smi deopts.
|
| + __ LoadClassId(temp, left);
|
| + }
|
| + Label done;
|
| + for (intptr_t i = 0; i < comp->NumTargets(); i++) {
|
| + ASSERT((comp->ClassIdAt(i) != kSmi) || (i == 0));
|
| + Label next_test;
|
| + __ cmpq(temp, Immediate(comp->ClassIdAt(i)));
|
| + __ j(NOT_EQUAL, &next_test, Assembler::kNearJump);
|
| + const Function& target = *comp->TargetAt(i);
|
| + ObjectStore* object_store = Isolate::Current()->object_store();
|
| + if (target.owner() == object_store->object_class()) {
|
| + // Object.== is same as ===.
|
| + __ Drop(2);
|
| + __ cmpq(left, right);
|
| + if (comp->is_fused_with_branch()) {
|
| + comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
|
| + } else {
|
| + // This case should be rare.
|
| + Register result = comp->locs()->out().reg();
|
| + Label load_true;
|
| + __ j(EQUAL, &load_true, Assembler::kNearJump);
|
| + __ LoadObject(result, compiler->bool_false());
|
| + __ jmp(&done);
|
| + __ Bind(&load_true);
|
| + __ LoadObject(result, compiler->bool_true());
|
| + }
|
| + } else {
|
| + const int kNumberOfArguments = 2;
|
| + const Array& kNoArgumentNames = Array::Handle();
|
| + compiler->GenerateStaticCall(comp->cid(),
|
| + comp->token_index(),
|
| + comp->try_index(),
|
| + target,
|
| + kNumberOfArguments,
|
| + kNoArgumentNames);
|
| + ASSERT(comp->is_fused_with_branch() ||
|
| + (comp->locs()->out().reg() == RAX));
|
| + if (comp->is_fused_with_branch()) {
|
| + __ CompareObject(RAX, compiler->bool_true());
|
| + comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
|
| + }
|
| + }
|
| + __ jmp(&done);
|
| + __ Bind(&next_test);
|
| + }
|
| + // Fall through leads to deoptimization
|
| + __ jmp(deopt);
|
| + __ Bind(&done);
|
| +}
|
| +
|
| +
|
| +
|
| +// First test if receiver is NULL, in which case === is applied.
|
| +// If type feedback was provided (lists of <class-id, target>), do a
|
| +// type by type check (either === or static call to the operator.
|
| static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler,
|
| EqualityCompareComp* comp) {
|
| const Immediate raw_null =
|
| @@ -275,51 +385,30 @@
|
| Label load_true;
|
| __ j(EQUAL, &load_true, Assembler::kNearJump);
|
| __ LoadObject(result, compiler->bool_false());
|
| - __ jmp(&done, Assembler::kNearJump);
|
| + __ jmp(&done);
|
| __ Bind(&load_true);
|
| __ LoadObject(result, compiler->bool_true());
|
| }
|
| __ jmp(&done);
|
|
|
| - __ Bind(&non_null_compare);
|
| + __ Bind(&non_null_compare); // Receiver is not null.
|
| __ pushq(left);
|
| __ pushq(right);
|
| - compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
|
| - comp->cid(),
|
| - comp->token_index(),
|
| - comp->try_index());
|
| - const String& operator_name = String::ZoneHandle(String::NewSymbol("=="));
|
| - const int kNumberOfArguments = 2;
|
| - const Array& kNoArgumentNames = Array::Handle();
|
| - const int kNumArgumentsChecked = 2;
|
| -
|
| - compiler->GenerateInstanceCall(comp->cid(),
|
| - comp->token_index(),
|
| - comp->try_index(),
|
| - operator_name,
|
| - kNumberOfArguments,
|
| - kNoArgumentNames,
|
| - kNumArgumentsChecked);
|
| - ASSERT(comp->is_fused_with_branch() || (comp->locs()->out().reg() == RAX));
|
| -
|
| - if (comp->is_fused_with_branch()) {
|
| - __ CompareObject(RAX, compiler->bool_true());
|
| - comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
|
| + if (comp->NumTargets() > 0) {
|
| + EmitEqualityAsPolymorphicCall(compiler, comp, left, right);
|
| + } else {
|
| + EmitEqualityAsInstanceCall(compiler, comp);
|
| }
|
| __ Bind(&done);
|
| }
|
|
|
|
|
| void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - if (operands_class_id() == kSmi) {
|
| + if ((NumTargets() == 1) && (ClassIdAt(0) == kSmi)) {
|
| EmitSmiEqualityCompare(compiler, this);
|
| return;
|
| }
|
| - if (operands_class_id() == kObject) {
|
| - EmitGenericEqualityCompare(compiler, this);
|
| - return;
|
| - }
|
| - UNREACHABLE();
|
| + EmitGenericEqualityCompare(compiler, this);
|
| }
|
|
|
|
|
|
|