| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 // We should never return here. | 185 // We should never return here. |
| 186 __ int3(); | 186 __ int3(); |
| 187 | 187 |
| 188 __ Bind(&done); | 188 __ Bind(&done); |
| 189 ASSERT(obj == result); | 189 ASSERT(obj == result); |
| 190 } | 190 } |
| 191 | 191 |
| 192 | 192 |
| 193 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { | 193 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { |
| 194 const intptr_t kNumInputs = 2; | 194 const intptr_t kNumInputs = 2; |
| 195 if (HasICData() && | 195 if (receiver_class_id() != kObject) { |
| 196 (ic_data()->NumberOfChecks() == 1) && | 196 ASSERT((receiver_class_id() == kSmi) || (receiver_class_id() == kDouble)); |
| 197 (ic_data()->GetReceiverClassIdAt(0) == kSmi)) { | |
| 198 const intptr_t kNumTemps = 1; | 197 const intptr_t kNumTemps = 1; |
| 199 LocationSummary* locs = new LocationSummary(kNumInputs, | 198 LocationSummary* locs = new LocationSummary(kNumInputs, |
| 200 kNumTemps, | 199 kNumTemps, |
| 201 LocationSummary::kNoCall); | 200 LocationSummary::kNoCall); |
| 202 locs->set_in(0, Location::RequiresRegister()); | 201 locs->set_in(0, Location::RequiresRegister()); |
| 203 locs->set_in(1, Location::RequiresRegister()); | 202 locs->set_in(1, Location::RequiresRegister()); |
| 204 locs->set_temp(0, Location::RequiresRegister()); | 203 locs->set_temp(0, Location::RequiresRegister()); |
| 205 if (!is_fused_with_branch()) { | 204 if (!is_fused_with_branch()) { |
| 206 locs->set_out(Location::RequiresRegister()); | 205 locs->set_out(Location::RequiresRegister()); |
| 207 } | 206 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 226 LocationSummary::kCall); | 225 LocationSummary::kCall); |
| 227 locs->set_in(0, Location::RequiresRegister()); | 226 locs->set_in(0, Location::RequiresRegister()); |
| 228 locs->set_in(1, Location::RequiresRegister()); | 227 locs->set_in(1, Location::RequiresRegister()); |
| 229 if (!is_fused_with_branch()) { | 228 if (!is_fused_with_branch()) { |
| 230 locs->set_out(Location::RegisterLocation(EAX)); | 229 locs->set_out(Location::RegisterLocation(EAX)); |
| 231 } | 230 } |
| 232 return locs; | 231 return locs; |
| 233 } | 232 } |
| 234 | 233 |
| 235 | 234 |
| 235 // Optional integer arguments can often be null. Null is not collected |
| 236 // by IC data. TODO(srdjan): Shall we collect null classes in ICData as well? |
| 236 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, | 237 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, |
| 237 EqualityCompareComp* comp) { | 238 EqualityCompareComp* comp) { |
| 238 Register left = comp->locs()->in(0).reg(); | 239 Register left = comp->locs()->in(0).reg(); |
| 239 Register right = comp->locs()->in(1).reg(); | 240 Register right = comp->locs()->in(1).reg(); |
| 240 Register temp = comp->locs()->temp(0).reg(); | 241 Register temp = comp->locs()->temp(0).reg(); |
| 241 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 242 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 242 comp->token_pos(), | 243 comp->token_pos(), |
| 243 comp->try_index(), | 244 comp->try_index(), |
| 244 kDeoptSmiCompareSmis, | 245 kDeoptSmiCompareSmi, |
| 245 left, | 246 left, |
| 246 right); | 247 right); |
| 247 // TODO(srdjan): Should we always include NULL test (common case)? | |
| 248 __ movl(temp, left); | 248 __ movl(temp, left); |
| 249 __ orl(temp, right); | 249 __ orl(temp, right); |
| 250 __ testl(temp, Immediate(kSmiTagMask)); | 250 __ testl(temp, Immediate(kSmiTagMask)); |
| 251 __ j(NOT_ZERO, deopt); | 251 __ j(NOT_ZERO, deopt); |
| 252 __ cmpl(left, right); | 252 __ cmpl(left, right); |
| 253 if (comp->is_fused_with_branch()) { | 253 if (comp->is_fused_with_branch()) { |
| 254 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | 254 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); |
| 255 } else { | 255 } else { |
| 256 Register result = comp->locs()->out().reg(); | 256 Register result = comp->locs()->out().reg(); |
| 257 Label load_true, done; | 257 Label load_true, done; |
| 258 __ j(EQUAL, &load_true, Assembler::kNearJump); | 258 __ j(EQUAL, &load_true, Assembler::kNearJump); |
| 259 __ LoadObject(result, compiler->bool_false()); | 259 __ LoadObject(result, compiler->bool_false()); |
| 260 __ jmp(&done, Assembler::kNearJump); | 260 __ jmp(&done, Assembler::kNearJump); |
| 261 __ Bind(&load_true); | 261 __ Bind(&load_true); |
| 262 __ LoadObject(result, compiler->bool_true()); | 262 __ LoadObject(result, compiler->bool_true()); |
| 263 __ Bind(&done); | 263 __ Bind(&done); |
| 264 } | 264 } |
| 265 } | 265 } |
| 266 | 266 |
| 267 | 267 |
| 268 // TODO(srdjan): Add support for mixed Smi/Double equality |
| 269 // (see LoadDoubleOrSmiToXmm). |
| 270 static void EmitDoubleEqualityCompare(FlowGraphCompiler* compiler, |
| 271 EqualityCompareComp* comp) { |
| 272 Register left = comp->locs()->in(0).reg(); |
| 273 Register right = comp->locs()->in(1).reg(); |
| 274 Register temp = comp->locs()->temp(0).reg(); |
| 275 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 276 comp->token_pos(), |
| 277 comp->try_index(), |
| 278 kDeoptDoubleCompareDouble, |
| 279 left, |
| 280 right); |
| 281 Label done, is_false, is_true; |
| 282 __ CompareClassId(left, kDouble, temp); |
| 283 __ j(NOT_EQUAL, deopt); |
| 284 __ CompareClassId(right, kDouble, temp); |
| 285 __ j(NOT_EQUAL, deopt); |
| 286 __ movsd(XMM0, FieldAddress(left, Double::value_offset())); |
| 287 __ movsd(XMM1, FieldAddress(right, Double::value_offset())); |
| 288 if (comp->is_fused_with_branch()) { |
| 289 compiler->EmitDoubleCompareBranch( |
| 290 EQUAL, XMM0, XMM1, comp->fused_with_branch()); |
| 291 } else { |
| 292 compiler->EmitDoubleCompareBool( |
| 293 EQUAL, XMM0, XMM1, comp->locs()->out().reg()); |
| 294 } |
| 295 } |
| 296 |
| 297 |
| 268 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, | 298 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, |
| 269 EqualityCompareComp* comp) { | 299 EqualityCompareComp* comp) { |
| 270 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 300 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 271 comp->cid(), | 301 comp->cid(), |
| 272 comp->token_pos(), | 302 comp->token_pos(), |
| 273 comp->try_index()); | 303 comp->try_index()); |
| 274 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); | 304 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); |
| 275 const int kNumberOfArguments = 2; | 305 const int kNumberOfArguments = 2; |
| 276 const Array& kNoArgumentNames = Array::Handle(); | 306 const Array& kNoArgumentNames = Array::Handle(); |
| 277 const int kNumArgumentsChecked = 2; | 307 const int kNumArgumentsChecked = 2; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 290 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | 320 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); |
| 291 } | 321 } |
| 292 } | 322 } |
| 293 | 323 |
| 294 | 324 |
| 295 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, | 325 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, |
| 296 EqualityCompareComp* comp, | 326 EqualityCompareComp* comp, |
| 297 Register left, | 327 Register left, |
| 298 Register right) { | 328 Register right) { |
| 299 ASSERT(comp->HasICData()); | 329 ASSERT(comp->HasICData()); |
| 300 const ICData& ic_data = *comp->ic_data(); | 330 const ICData& ic_data = ICData::Handle(comp->ic_data()->AsUnaryClassChecks()); |
| 301 ASSERT(ic_data.NumberOfChecks() > 0); | 331 ASSERT(ic_data.NumberOfChecks() > 0); |
| 302 ASSERT(ic_data.num_args_tested() == 1); | 332 ASSERT(ic_data.num_args_tested() == 1); |
| 303 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 333 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 304 comp->token_pos(), | 334 comp->token_pos(), |
| 305 comp->try_index(), | 335 comp->try_index(), |
| 306 kDeoptEquality); | 336 kDeoptEquality); |
| 307 __ testl(left, Immediate(kSmiTagMask)); | 337 __ testl(left, Immediate(kSmiTagMask)); |
| 308 Register temp = comp->locs()->temp(0).reg(); | 338 Register temp = comp->locs()->temp(0).reg(); |
| 309 if (ic_data.GetReceiverClassIdAt(0) == kSmi) { | 339 if (ic_data.GetReceiverClassIdAt(0) == kSmi) { |
| 310 Label done, load_class_id; | 340 Label done, load_class_id; |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { | 430 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { |
| 401 EmitEqualityAsPolymorphicCall(compiler, comp, left, right); | 431 EmitEqualityAsPolymorphicCall(compiler, comp, left, right); |
| 402 } else { | 432 } else { |
| 403 EmitEqualityAsInstanceCall(compiler, comp); | 433 EmitEqualityAsInstanceCall(compiler, comp); |
| 404 } | 434 } |
| 405 __ Bind(&done); | 435 __ Bind(&done); |
| 406 } | 436 } |
| 407 | 437 |
| 408 | 438 |
| 409 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 439 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 410 if (HasICData() && | 440 if (receiver_class_id() == kSmi) { |
| 411 (ic_data()->NumberOfChecks() == 1) && | |
| 412 (ic_data()->GetReceiverClassIdAt(0) == kSmi)) { | |
| 413 EmitSmiEqualityCompare(compiler, this); | 441 EmitSmiEqualityCompare(compiler, this); |
| 414 return; | 442 return; |
| 415 } | 443 } |
| 444 if (receiver_class_id() == kDouble) { |
| 445 EmitDoubleEqualityCompare(compiler, this); |
| 446 return; |
| 447 } |
| 416 EmitGenericEqualityCompare(compiler, this); | 448 EmitGenericEqualityCompare(compiler, this); |
| 417 } | 449 } |
| 418 | 450 |
| 419 | 451 |
| 420 LocationSummary* RelationalOpComp::MakeLocationSummary() const { | 452 LocationSummary* RelationalOpComp::MakeLocationSummary() const { |
| 421 if ((operands_class_id() == kSmi) || (operands_class_id() == kDouble)) { | 453 if ((operands_class_id() == kSmi) || (operands_class_id() == kDouble)) { |
| 422 const intptr_t kNumInputs = 2; | 454 const intptr_t kNumInputs = 2; |
| 423 const intptr_t kNumTemps = 1; | 455 const intptr_t kNumTemps = 1; |
| 424 LocationSummary* summary = new LocationSummary(kNumInputs, | 456 LocationSummary* summary = new LocationSummary(kNumInputs, |
| 425 kNumTemps, | 457 kNumTemps, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 454 | 486 |
| 455 | 487 |
| 456 static void EmitSmiRelationalOp(FlowGraphCompiler* compiler, | 488 static void EmitSmiRelationalOp(FlowGraphCompiler* compiler, |
| 457 RelationalOpComp* comp) { | 489 RelationalOpComp* comp) { |
| 458 Register left = comp->locs()->in(0).reg(); | 490 Register left = comp->locs()->in(0).reg(); |
| 459 Register right = comp->locs()->in(1).reg(); | 491 Register right = comp->locs()->in(1).reg(); |
| 460 Register temp = comp->locs()->temp(0).reg(); | 492 Register temp = comp->locs()->temp(0).reg(); |
| 461 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 493 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 462 comp->token_pos(), | 494 comp->token_pos(), |
| 463 comp->try_index(), | 495 comp->try_index(), |
| 464 kDeoptSmiCompareSmis, | 496 kDeoptSmiCompareSmi, |
| 465 left, | 497 left, |
| 466 right); | 498 right); |
| 467 __ movl(temp, left); | 499 __ movl(temp, left); |
| 468 __ orl(temp, right); | 500 __ orl(temp, right); |
| 469 __ testl(temp, Immediate(kSmiTagMask)); | 501 __ testl(temp, Immediate(kSmiTagMask)); |
| 470 __ j(NOT_ZERO, deopt); | 502 __ j(NOT_ZERO, deopt); |
| 471 | 503 |
| 472 Condition true_condition = TokenKindToSmiCondition(comp->kind()); | 504 Condition true_condition = TokenKindToSmiCondition(comp->kind()); |
| 473 __ cmpl(left, right); | 505 __ cmpl(left, right); |
| 474 | 506 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 542 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 511 comp->token_pos(), | 543 comp->token_pos(), |
| 512 comp->try_index(), | 544 comp->try_index(), |
| 513 kDeoptDoubleComparison, | 545 kDeoptDoubleComparison, |
| 514 left, | 546 left, |
| 515 right); | 547 right); |
| 516 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); | 548 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); |
| 517 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); | 549 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); |
| 518 | 550 |
| 519 Condition true_condition = TokenKindToDoubleCondition(comp->kind()); | 551 Condition true_condition = TokenKindToDoubleCondition(comp->kind()); |
| 520 __ comisd(XMM0, XMM1); | |
| 521 | |
| 522 if (comp->is_fused_with_branch()) { | 552 if (comp->is_fused_with_branch()) { |
| 523 BranchInstr* branch = comp->fused_with_branch(); | 553 compiler->EmitDoubleCompareBranch( |
| 524 BlockEntryInstr* nan_result = branch->is_negated() ? | 554 true_condition, XMM0, XMM1, comp->fused_with_branch()); |
| 525 branch->true_successor() : branch->false_successor(); | |
| 526 __ j(PARITY_EVEN, compiler->GetBlockLabel(nan_result)); | |
| 527 branch->EmitBranchOnCondition(compiler, true_condition); | |
| 528 } else { | 555 } else { |
| 529 Register result = comp->locs()->out().reg(); | 556 compiler->EmitDoubleCompareBool( |
| 530 Label is_false, is_true, done; | 557 true_condition, XMM0, XMM1, comp->locs()->out().reg()); |
| 531 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; | |
| 532 __ j(true_condition, &is_true, Assembler::kNearJump); | |
| 533 __ Bind(&is_false); | |
| 534 __ LoadObject(result, compiler->bool_false()); | |
| 535 __ jmp(&done); | |
| 536 __ Bind(&is_true); | |
| 537 __ LoadObject(result, compiler->bool_true()); | |
| 538 __ Bind(&done); | |
| 539 } | 558 } |
| 540 } | 559 } |
| 541 | 560 |
| 542 | 561 |
| 543 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 562 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 544 if (operands_class_id() == kSmi) { | 563 if (operands_class_id() == kSmi) { |
| 545 EmitSmiRelationalOp(compiler, this); | 564 EmitSmiRelationalOp(compiler, this); |
| 546 return; | 565 return; |
| 547 } | 566 } |
| 548 if (operands_class_id() == kDouble) { | 567 if (operands_class_id() == kDouble) { |
| (...skipping 1405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1954 instance_call()->argument_names()); | 1973 instance_call()->argument_names()); |
| 1955 } | 1974 } |
| 1956 __ Bind(&done); | 1975 __ Bind(&done); |
| 1957 } | 1976 } |
| 1958 | 1977 |
| 1959 } // namespace dart | 1978 } // namespace dart |
| 1960 | 1979 |
| 1961 #undef __ | 1980 #undef __ |
| 1962 | 1981 |
| 1963 #endif // defined TARGET_ARCH_X64 | 1982 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |