| 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_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 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 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 // No temporary register needed for double comparison. | 207 // No temporary register needed for double comparison. |
| 208 const intptr_t kNumTemps = (receiver_class_id() == kSmi) ? 1 : 0; | 208 const intptr_t kNumTemps = (receiver_class_id() == kSmi) ? 1 : 0; |
| 209 LocationSummary* locs = new LocationSummary(kNumInputs, | 209 LocationSummary* locs = new LocationSummary(kNumInputs, |
| 210 kNumTemps, | 210 kNumTemps, |
| 211 LocationSummary::kNoCall); | 211 LocationSummary::kNoCall); |
| 212 locs->set_in(0, Location::RequiresRegister()); | 212 locs->set_in(0, Location::RequiresRegister()); |
| 213 locs->set_in(1, Location::RequiresRegister()); | 213 locs->set_in(1, Location::RequiresRegister()); |
| 214 if (receiver_class_id() == kSmi) { | 214 if (receiver_class_id() == kSmi) { |
| 215 locs->set_temp(0, Location::RequiresRegister()); | 215 locs->set_temp(0, Location::RequiresRegister()); |
| 216 } | 216 } |
| 217 if (!is_fused_with_branch()) { | 217 locs->set_out(Location::RequiresRegister()); |
| 218 locs->set_out(Location::RequiresRegister()); | |
| 219 } | |
| 220 return locs; | 218 return locs; |
| 221 } | 219 } |
| 222 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 220 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 223 const intptr_t kNumTemps = 1; | 221 const intptr_t kNumTemps = 1; |
| 224 LocationSummary* locs = new LocationSummary(kNumInputs, | 222 LocationSummary* locs = new LocationSummary(kNumInputs, |
| 225 kNumTemps, | 223 kNumTemps, |
| 226 LocationSummary::kCall); | 224 LocationSummary::kCall); |
| 227 locs->set_in(0, Location::RequiresRegister()); | 225 locs->set_in(0, Location::RequiresRegister()); |
| 228 locs->set_in(1, Location::RequiresRegister()); | 226 locs->set_in(1, Location::RequiresRegister()); |
| 229 locs->set_temp(0, Location::RequiresRegister()); | 227 locs->set_temp(0, Location::RequiresRegister()); |
| 230 if (!is_fused_with_branch()) { | 228 locs->set_out(Location::RegisterLocation(RAX)); |
| 231 locs->set_out(Location::RegisterLocation(RAX)); | |
| 232 } | |
| 233 return locs; | 229 return locs; |
| 234 } | 230 } |
| 235 const intptr_t kNumTemps = 0; | 231 const intptr_t kNumTemps = 0; |
| 236 LocationSummary* locs = new LocationSummary(kNumInputs, | 232 LocationSummary* locs = new LocationSummary(kNumInputs, |
| 237 kNumTemps, | 233 kNumTemps, |
| 238 LocationSummary::kCall); | 234 LocationSummary::kCall); |
| 239 locs->set_in(0, Location::RequiresRegister()); | 235 locs->set_in(0, Location::RequiresRegister()); |
| 240 locs->set_in(1, Location::RequiresRegister()); | 236 locs->set_in(1, Location::RequiresRegister()); |
| 241 if (!is_fused_with_branch()) { | 237 locs->set_out(Location::RegisterLocation(RAX)); |
| 242 locs->set_out(Location::RegisterLocation(RAX)); | |
| 243 } | |
| 244 return locs; | 238 return locs; |
| 245 } | 239 } |
| 246 | 240 |
| 247 | 241 |
| 248 // Optional integer arguments can often be null. Null is not collected | 242 // Optional integer arguments can often be null. Null is not collected |
| 249 // by IC data. TODO(srdjan): Shall we collect null classes in ICData as well? | 243 // by IC data. TODO(srdjan): Shall we collect null classes in ICData as well? |
| 250 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, | 244 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, |
| 251 EqualityCompareComp* comp) { | 245 EqualityCompareComp* comp) { |
| 252 Register left = comp->locs()->in(0).reg(); | 246 Register left = comp->locs()->in(0).reg(); |
| 253 Register right = comp->locs()->in(1).reg(); | 247 Register right = comp->locs()->in(1).reg(); |
| 254 Register temp = comp->locs()->temp(0).reg(); | 248 Register temp = comp->locs()->temp(0).reg(); |
| 255 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 249 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 256 comp->token_pos(), | 250 comp->token_pos(), |
| 257 comp->try_index(), | 251 comp->try_index(), |
| 258 kDeoptSmiCompareSmi, | 252 kDeoptSmiCompareSmi, |
| 259 left, | 253 left, |
| 260 right); | 254 right); |
| 261 __ movq(temp, left); | 255 __ movq(temp, left); |
| 262 __ orq(temp, right); | 256 __ orq(temp, right); |
| 263 __ testq(temp, Immediate(kSmiTagMask)); | 257 __ testq(temp, Immediate(kSmiTagMask)); |
| 264 __ j(NOT_ZERO, deopt); | 258 __ j(NOT_ZERO, deopt); |
| 265 __ cmpq(left, right); | 259 __ cmpq(left, right); |
| 266 if (comp->is_fused_with_branch()) { | 260 Register result = comp->locs()->out().reg(); |
| 267 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | 261 Label load_true, done; |
| 268 } else { | 262 __ j(EQUAL, &load_true, Assembler::kNearJump); |
| 269 Register result = comp->locs()->out().reg(); | 263 __ LoadObject(result, compiler->bool_false()); |
| 270 Label load_true, done; | 264 __ jmp(&done, Assembler::kNearJump); |
| 271 __ j(EQUAL, &load_true, Assembler::kNearJump); | 265 __ Bind(&load_true); |
| 272 __ LoadObject(result, compiler->bool_false()); | 266 __ LoadObject(result, compiler->bool_true()); |
| 273 __ jmp(&done, Assembler::kNearJump); | 267 __ Bind(&done); |
| 274 __ Bind(&load_true); | |
| 275 __ LoadObject(result, compiler->bool_true()); | |
| 276 __ Bind(&done); | |
| 277 } | |
| 278 } | 268 } |
| 279 | 269 |
| 280 | 270 |
| 281 // TODO(srdjan): Add support for mixed Smi/Double equality | 271 // TODO(srdjan): Add support for mixed Smi/Double equality |
| 282 // (see LoadDoubleOrSmiToXmm). | 272 // (see LoadDoubleOrSmiToXmm). |
| 283 static void EmitDoubleEqualityCompare(FlowGraphCompiler* compiler, | 273 static void EmitDoubleEqualityCompare(FlowGraphCompiler* compiler, |
| 284 EqualityCompareComp* comp) { | 274 EqualityCompareComp* comp) { |
| 285 Register left = comp->locs()->in(0).reg(); | 275 Register left = comp->locs()->in(0).reg(); |
| 286 Register right = comp->locs()->in(1).reg(); | 276 Register right = comp->locs()->in(1).reg(); |
| 287 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 277 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 288 comp->token_pos(), | 278 comp->token_pos(), |
| 289 comp->try_index(), | 279 comp->try_index(), |
| 290 kDeoptDoubleCompareDouble, | 280 kDeoptDoubleCompareDouble, |
| 291 left, | 281 left, |
| 292 right); | 282 right); |
| 293 __ CompareClassId(left, kDouble); | 283 __ CompareClassId(left, kDouble); |
| 294 __ j(NOT_EQUAL, deopt); | 284 __ j(NOT_EQUAL, deopt); |
| 295 __ CompareClassId(right, kDouble); | 285 __ CompareClassId(right, kDouble); |
| 296 __ j(NOT_EQUAL, deopt); | 286 __ j(NOT_EQUAL, deopt); |
| 297 __ movsd(XMM0, FieldAddress(left, Double::value_offset())); | 287 __ movsd(XMM0, FieldAddress(left, Double::value_offset())); |
| 298 __ movsd(XMM1, FieldAddress(right, Double::value_offset())); | 288 __ movsd(XMM1, FieldAddress(right, Double::value_offset())); |
| 299 if (comp->is_fused_with_branch()) { | 289 compiler->EmitDoubleCompareBool( |
| 300 compiler->EmitDoubleCompareBranch( | 290 EQUAL, XMM0, XMM1, comp->locs()->out().reg()); |
| 301 EQUAL, XMM0, XMM1, comp->fused_with_branch()); | |
| 302 } else { | |
| 303 compiler->EmitDoubleCompareBool( | |
| 304 EQUAL, XMM0, XMM1, comp->locs()->out().reg()); | |
| 305 } | |
| 306 } | 291 } |
| 307 | 292 |
| 308 | 293 |
| 309 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, | 294 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, |
| 310 EqualityCompareComp* comp) { | 295 EqualityCompareComp* comp) { |
| 311 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 296 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 312 comp->cid(), | 297 comp->cid(), |
| 313 comp->token_pos(), | 298 comp->token_pos(), |
| 314 comp->try_index()); | 299 comp->try_index()); |
| 315 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); | 300 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); |
| 316 const int kNumberOfArguments = 2; | 301 const int kNumberOfArguments = 2; |
| 317 const Array& kNoArgumentNames = Array::Handle(); | 302 const Array& kNoArgumentNames = Array::Handle(); |
| 318 const int kNumArgumentsChecked = 2; | 303 const int kNumArgumentsChecked = 2; |
| 319 | 304 |
| 320 compiler->GenerateInstanceCall(comp->cid(), | 305 compiler->GenerateInstanceCall(comp->cid(), |
| 321 comp->token_pos(), | 306 comp->token_pos(), |
| 322 comp->try_index(), | 307 comp->try_index(), |
| 323 operator_name, | 308 operator_name, |
| 324 kNumberOfArguments, | 309 kNumberOfArguments, |
| 325 kNoArgumentNames, | 310 kNoArgumentNames, |
| 326 kNumArgumentsChecked); | 311 kNumArgumentsChecked); |
| 327 ASSERT(comp->is_fused_with_branch() || (comp->locs()->out().reg() == RAX)); | 312 ASSERT(comp->locs()->out().reg() == RAX); |
| 328 | |
| 329 if (comp->is_fused_with_branch()) { | |
| 330 __ CompareObject(RAX, compiler->bool_true()); | |
| 331 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | |
| 332 } | |
| 333 } | 313 } |
| 334 | 314 |
| 335 | 315 |
| 336 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, | 316 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, |
| 337 EqualityCompareComp* comp, | 317 const ICData& orig_ic_data, |
| 338 Register left, | 318 const LocationSummary& locs, |
| 339 Register right) { | 319 BranchInstr* branch, |
| 340 ASSERT(comp->HasICData()); | 320 Token::Kind kind, |
| 341 const ICData& ic_data = ICData::Handle(comp->ic_data()->AsUnaryClassChecks()); | 321 intptr_t cid, |
| 322 intptr_t token_pos, |
| 323 intptr_t try_index) { |
| 324 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks()); |
| 342 ASSERT(ic_data.NumberOfChecks() > 0); | 325 ASSERT(ic_data.NumberOfChecks() > 0); |
| 343 ASSERT(ic_data.num_args_tested() == 1); | 326 ASSERT(ic_data.num_args_tested() == 1); |
| 344 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 327 Label* deopt = compiler->AddDeoptStub(cid, |
| 345 comp->token_pos(), | 328 token_pos, |
| 346 comp->try_index(), | 329 try_index, |
| 347 kDeoptEquality); | 330 kDeoptEquality); |
| 331 Register left = locs.in(0).reg(); |
| 332 Register right = locs.in(1).reg(); |
| 348 __ testq(left, Immediate(kSmiTagMask)); | 333 __ testq(left, Immediate(kSmiTagMask)); |
| 349 Register temp = comp->locs()->temp(0).reg(); | 334 Register temp = locs.temp(0).reg(); |
| 350 if (ic_data.GetReceiverClassIdAt(0) == kSmi) { | 335 if (ic_data.GetReceiverClassIdAt(0) == kSmi) { |
| 351 Label done, load_class_id; | 336 Label done, load_class_id; |
| 352 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump); | 337 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump); |
| 353 __ movq(temp, Immediate(kSmi)); | 338 __ movq(temp, Immediate(kSmi)); |
| 354 __ jmp(&done, Assembler::kNearJump); | 339 __ jmp(&done, Assembler::kNearJump); |
| 355 __ Bind(&load_class_id); | 340 __ Bind(&load_class_id); |
| 356 __ LoadClassId(temp, left); | 341 __ LoadClassId(temp, left); |
| 357 __ Bind(&done); | 342 __ Bind(&done); |
| 358 } else { | 343 } else { |
| 359 __ j(ZERO, deopt); // Smi deopts. | 344 __ j(ZERO, deopt); // Smi deopts. |
| 360 __ LoadClassId(temp, left); | 345 __ LoadClassId(temp, left); |
| 361 } | 346 } |
| 347 Condition cond = (kind == Token::kEQ) ? EQUAL : NOT_EQUAL; |
| 362 Label done; | 348 Label done; |
| 363 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 349 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 364 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmi) || (i == 0)); | 350 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmi) || (i == 0)); |
| 365 Label next_test; | 351 Label next_test; |
| 366 __ cmpq(temp, Immediate(ic_data.GetReceiverClassIdAt(i))); | 352 __ cmpq(temp, Immediate(ic_data.GetReceiverClassIdAt(i))); |
| 367 __ j(NOT_EQUAL, &next_test, Assembler::kNearJump); | 353 __ j(NOT_EQUAL, &next_test, Assembler::kNearJump); |
| 368 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); | 354 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); |
| 369 ObjectStore* object_store = Isolate::Current()->object_store(); | 355 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 370 if (target.owner() == object_store->object_class()) { | 356 if (target.owner() == object_store->object_class()) { |
| 371 // Object.== is same as ===. | 357 // Object.== is same as ===. |
| 372 __ Drop(2); | 358 __ Drop(2); |
| 373 __ cmpq(left, right); | 359 __ cmpq(left, right); |
| 374 if (comp->is_fused_with_branch()) { | 360 if (branch != NULL) { |
| 375 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | 361 branch->EmitBranchOnCondition(compiler, cond); |
| 376 } else { | 362 } else { |
| 377 // This case should be rare. | 363 // This case should be rare. |
| 378 Register result = comp->locs()->out().reg(); | 364 Register result = locs.out().reg(); |
| 379 Label load_true; | 365 Label load_true; |
| 380 __ j(EQUAL, &load_true, Assembler::kNearJump); | 366 __ j(cond, &load_true, Assembler::kNearJump); |
| 381 __ LoadObject(result, compiler->bool_false()); | 367 __ LoadObject(result, compiler->bool_false()); |
| 382 __ jmp(&done); | 368 __ jmp(&done); |
| 383 __ Bind(&load_true); | 369 __ Bind(&load_true); |
| 384 __ LoadObject(result, compiler->bool_true()); | 370 __ LoadObject(result, compiler->bool_true()); |
| 385 } | 371 } |
| 386 } else { | 372 } else { |
| 387 const int kNumberOfArguments = 2; | 373 const int kNumberOfArguments = 2; |
| 388 const Array& kNoArgumentNames = Array::Handle(); | 374 const Array& kNoArgumentNames = Array::Handle(); |
| 389 compiler->GenerateStaticCall(comp->cid(), | 375 compiler->GenerateStaticCall(cid, |
| 390 comp->token_pos(), | 376 token_pos, |
| 391 comp->try_index(), | 377 try_index, |
| 392 target, | 378 target, |
| 393 kNumberOfArguments, | 379 kNumberOfArguments, |
| 394 kNoArgumentNames); | 380 kNoArgumentNames); |
| 395 ASSERT(comp->is_fused_with_branch() || | 381 if (branch != NULL) { |
| 396 (comp->locs()->out().reg() == RAX)); | |
| 397 if (comp->is_fused_with_branch()) { | |
| 398 __ CompareObject(RAX, compiler->bool_true()); | 382 __ CompareObject(RAX, compiler->bool_true()); |
| 399 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | 383 branch->EmitBranchOnCondition(compiler, cond); |
| 400 } | 384 } |
| 401 } | 385 } |
| 402 __ jmp(&done); | 386 __ jmp(&done); |
| 403 __ Bind(&next_test); | 387 __ Bind(&next_test); |
| 404 } | 388 } |
| 405 // Fall through leads to deoptimization | 389 // Fall through leads to deoptimization |
| 406 __ jmp(deopt); | 390 __ jmp(deopt); |
| 407 __ Bind(&done); | 391 __ Bind(&done); |
| 408 } | 392 } |
| 409 | 393 |
| 410 | 394 |
| 411 // First test if receiver is NULL, in which case === is applied. | 395 // First test if receiver is NULL, in which case === is applied. |
| 412 // If type feedback was provided (lists of <class-id, target>), do a | 396 // If type feedback was provided (lists of <class-id, target>), do a |
| 413 // type by type check (either === or static call to the operator. | 397 // type by type check (either === or static call to the operator. |
| 414 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, | 398 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, |
| 415 EqualityCompareComp* comp) { | 399 const LocationSummary& locs, |
| 416 Register left = comp->locs()->in(0).reg(); | 400 Token::Kind kind, |
| 417 Register right = comp->locs()->in(1).reg(); | 401 BranchInstr* branch, |
| 402 const ICData& ic_data, |
| 403 intptr_t cid, |
| 404 intptr_t token_pos, |
| 405 intptr_t try_index) { |
| 406 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); |
| 407 Register left = locs.in(0).reg(); |
| 408 Register right = locs.in(1).reg(); |
| 418 const Immediate raw_null = | 409 const Immediate raw_null = |
| 419 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 410 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 420 Label done, non_null_compare; | 411 Label done, non_null_compare; |
| 421 __ cmpq(left, raw_null); | 412 __ cmpq(left, raw_null); |
| 422 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); | 413 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); |
| 423 // Comparison with NULL is "===". | 414 // Comparison with NULL is "===". |
| 424 __ cmpq(left, right); | 415 __ cmpq(left, right); |
| 425 if (comp->is_fused_with_branch()) { | 416 Condition cond = (kind == Token::kEQ) ? EQUAL : NOT_EQUAL; |
| 426 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | 417 if (branch != NULL) { |
| 418 branch->EmitBranchOnCondition(compiler, cond); |
| 427 } else { | 419 } else { |
| 428 Register result = comp->locs()->out().reg(); | 420 Register result = locs.out().reg(); |
| 429 Label load_true; | 421 Label load_true; |
| 430 __ j(EQUAL, &load_true, Assembler::kNearJump); | 422 __ j(cond, &load_true, Assembler::kNearJump); |
| 431 __ LoadObject(result, compiler->bool_false()); | 423 __ LoadObject(result, compiler->bool_false()); |
| 432 __ jmp(&done); | 424 __ jmp(&done); |
| 433 __ Bind(&load_true); | 425 __ Bind(&load_true); |
| 434 __ LoadObject(result, compiler->bool_true()); | 426 __ LoadObject(result, compiler->bool_true()); |
| 435 } | 427 } |
| 436 __ jmp(&done); | 428 __ jmp(&done); |
| 437 | |
| 438 __ Bind(&non_null_compare); // Receiver is not null. | 429 __ Bind(&non_null_compare); // Receiver is not null. |
| 439 __ pushq(left); | 430 __ pushq(left); |
| 440 __ pushq(right); | 431 __ pushq(right); |
| 441 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { | 432 EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind, |
| 442 EmitEqualityAsPolymorphicCall(compiler, comp, left, right); | 433 cid, token_pos, try_index); |
| 443 } else { | |
| 444 EmitEqualityAsInstanceCall(compiler, comp); | |
| 445 } | |
| 446 __ Bind(&done); | 434 __ Bind(&done); |
| 447 } | 435 } |
| 448 | 436 |
| 449 | 437 |
| 450 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 438 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 451 if (receiver_class_id() == kSmi) { | 439 if (receiver_class_id() == kSmi) { |
| 452 EmitSmiEqualityCompare(compiler, this); | 440 EmitSmiEqualityCompare(compiler, this); |
| 453 return; | 441 return; |
| 454 } | 442 } |
| 455 if (receiver_class_id() == kDouble) { | 443 if (receiver_class_id() == kDouble) { |
| 456 EmitDoubleEqualityCompare(compiler, this); | 444 EmitDoubleEqualityCompare(compiler, this); |
| 457 return; | 445 return; |
| 458 } | 446 } |
| 459 EmitGenericEqualityCompare(compiler, this); | 447 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 448 EmitGenericEqualityCompare(compiler, *locs(), Token::kEQ, NULL, |
| 449 *ic_data(), cid(), token_pos(), try_index()); |
| 450 } else { |
| 451 Register left = locs()->in(0).reg(); |
| 452 Register right = locs()->in(1).reg(); |
| 453 __ pushq(left); |
| 454 __ pushq(right); |
| 455 EmitEqualityAsInstanceCall(compiler, this); |
| 456 } |
| 460 } | 457 } |
| 461 | 458 |
| 462 | 459 |
| 463 LocationSummary* RelationalOpComp::MakeLocationSummary() const { | 460 LocationSummary* RelationalOpComp::MakeLocationSummary() const { |
| 464 if (operands_class_id() == kSmi || operands_class_id() == kDouble) { | 461 if (operands_class_id() == kSmi || operands_class_id() == kDouble) { |
| 465 const intptr_t kNumInputs = 2; | 462 const intptr_t kNumInputs = 2; |
| 466 const intptr_t kNumTemps = 1; | 463 const intptr_t kNumTemps = 1; |
| 467 LocationSummary* summary = new LocationSummary(kNumInputs, | 464 LocationSummary* summary = new LocationSummary(kNumInputs, |
| 468 kNumTemps, | 465 kNumTemps, |
| 469 LocationSummary::kCall); | 466 LocationSummary::kCall); |
| 470 summary->set_in(0, Location::RequiresRegister()); | 467 summary->set_in(0, Location::RequiresRegister()); |
| 471 summary->set_in(1, Location::RequiresRegister()); | 468 summary->set_in(1, Location::RequiresRegister()); |
| 472 if (!is_fused_with_branch()) { | 469 summary->set_out(Location::RequiresRegister()); |
| 473 summary->set_out(Location::RequiresRegister()); | |
| 474 } | |
| 475 summary->set_temp(0, Location::RequiresRegister()); | 470 summary->set_temp(0, Location::RequiresRegister()); |
| 476 return summary; | 471 return summary; |
| 477 } | 472 } |
| 478 ASSERT(!is_fused_with_branch()); | |
| 479 ASSERT(operands_class_id() == kObject); | 473 ASSERT(operands_class_id() == kObject); |
| 480 return MakeCallSummary(); | 474 return MakeCallSummary(); |
| 481 } | 475 } |
| 482 | 476 |
| 483 | 477 |
| 484 static Condition TokenKindToSmiCondition(Token::Kind kind) { | 478 static Condition TokenKindToSmiCondition(Token::Kind kind) { |
| 485 switch (kind) { | 479 switch (kind) { |
| 486 case Token::kEQ: return EQUAL; | 480 case Token::kEQ: return EQUAL; |
| 487 case Token::kNE: return NOT_EQUAL; | 481 case Token::kNE: return NOT_EQUAL; |
| 488 case Token::kLT: return LESS; | 482 case Token::kLT: return LESS; |
| 489 case Token::kGT: return GREATER; | 483 case Token::kGT: return GREATER; |
| 490 case Token::kLTE: return LESS_EQUAL; | 484 case Token::kLTE: return LESS_EQUAL; |
| 491 case Token::kGTE: return GREATER_EQUAL; | 485 case Token::kGTE: return GREATER_EQUAL; |
| 492 default: | 486 default: |
| 493 UNREACHABLE(); | 487 UNREACHABLE(); |
| 494 return OVERFLOW; | 488 return OVERFLOW; |
| 495 } | 489 } |
| 496 } | 490 } |
| 497 | 491 |
| 498 | 492 |
| 499 static void EmitSmiRelationalOp(FlowGraphCompiler* compiler, | 493 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler, |
| 500 RelationalOpComp* comp) { | 494 const LocationSummary& locs, |
| 501 Register left = comp->locs()->in(0).reg(); | 495 Token::Kind kind, |
| 502 Register right = comp->locs()->in(1).reg(); | 496 BranchInstr* branch, |
| 503 Register temp = comp->locs()->temp(0).reg(); | 497 intptr_t cid, |
| 504 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 498 intptr_t token_pos, |
| 505 comp->token_pos(), | 499 intptr_t try_index) { |
| 506 comp->try_index(), | 500 Register left = locs.in(0).reg(); |
| 501 Register right = locs.in(1).reg(); |
| 502 Register temp = locs.temp(0).reg(); |
| 503 Label* deopt = compiler->AddDeoptStub(cid, |
| 504 token_pos, |
| 505 try_index, |
| 507 kDeoptSmiCompareSmi, | 506 kDeoptSmiCompareSmi, |
| 508 left, | 507 left, |
| 509 right); | 508 right); |
| 510 __ movq(temp, left); | 509 __ movq(temp, left); |
| 511 __ orq(temp, right); | 510 __ orq(temp, right); |
| 512 __ testq(temp, Immediate(kSmiTagMask)); | 511 __ testq(temp, Immediate(kSmiTagMask)); |
| 513 __ j(NOT_ZERO, deopt); | 512 __ j(NOT_ZERO, deopt); |
| 514 | 513 |
| 515 Condition true_condition = TokenKindToSmiCondition(comp->kind()); | 514 Condition true_condition = TokenKindToSmiCondition(kind); |
| 516 __ cmpq(left, right); | 515 __ cmpq(left, right); |
| 517 | 516 |
| 518 if (comp->is_fused_with_branch()) { | 517 if (branch != NULL) { |
| 519 comp->fused_with_branch()->EmitBranchOnCondition(compiler, true_condition); | 518 branch->EmitBranchOnCondition(compiler, true_condition); |
| 520 } else { | 519 } else { |
| 521 Register result = comp->locs()->out().reg(); | 520 Register result = locs.out().reg(); |
| 522 Label done, is_true; | 521 Label done, is_true; |
| 523 __ j(true_condition, &is_true); | 522 __ j(true_condition, &is_true); |
| 524 __ LoadObject(result, compiler->bool_false()); | 523 __ LoadObject(result, compiler->bool_false()); |
| 525 __ jmp(&done); | 524 __ jmp(&done); |
| 526 __ Bind(&is_true); | 525 __ Bind(&is_true); |
| 527 __ LoadObject(result, compiler->bool_true()); | 526 __ LoadObject(result, compiler->bool_true()); |
| 528 __ Bind(&done); | 527 __ Bind(&done); |
| 529 } | 528 } |
| 530 } | 529 } |
| 531 | 530 |
| 532 | 531 |
| 533 static Condition TokenKindToDoubleCondition(Token::Kind kind) { | 532 static Condition TokenKindToDoubleCondition(Token::Kind kind) { |
| 534 switch (kind) { | 533 switch (kind) { |
| 535 case Token::kEQ: return EQUAL; | 534 case Token::kEQ: return EQUAL; |
| 535 case Token::kNE: return NOT_EQUAL; |
| 536 case Token::kLT: return BELOW; | 536 case Token::kLT: return BELOW; |
| 537 case Token::kGT: return ABOVE; | 537 case Token::kGT: return ABOVE; |
| 538 case Token::kLTE: return BELOW_EQUAL; | 538 case Token::kLTE: return BELOW_EQUAL; |
| 539 case Token::kGTE: return ABOVE_EQUAL; | 539 case Token::kGTE: return ABOVE_EQUAL; |
| 540 default: | 540 default: |
| 541 UNREACHABLE(); | 541 UNREACHABLE(); |
| 542 return OVERFLOW; | 542 return OVERFLOW; |
| 543 } | 543 } |
| 544 } | 544 } |
| 545 | 545 |
| 546 | 546 |
| 547 static void EmitDoubleRelationalOp(FlowGraphCompiler* compiler, | 547 static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler, |
| 548 RelationalOpComp* comp) { | 548 const LocationSummary& locs, |
| 549 Register left = comp->locs()->in(0).reg(); | 549 Token::Kind kind, |
| 550 Register right = comp->locs()->in(1).reg(); | 550 BranchInstr* branch, |
| 551 intptr_t cid, |
| 552 intptr_t token_pos, |
| 553 intptr_t try_index) { |
| 554 Register left = locs.in(0).reg(); |
| 555 Register right = locs.in(1).reg(); |
| 551 // TODO(srdjan): temp is only needed if a conversion Smi->Double occurs. | 556 // TODO(srdjan): temp is only needed if a conversion Smi->Double occurs. |
| 552 Register temp = comp->locs()->temp(0).reg(); | 557 Register temp = locs.temp(0).reg(); |
| 553 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 558 Label* deopt = compiler->AddDeoptStub(cid, |
| 554 comp->token_pos(), | 559 token_pos, |
| 555 comp->try_index(), | 560 try_index, |
| 556 kDeoptDoubleComparison, | 561 kDeoptDoubleComparison, |
| 557 left, | 562 left, |
| 558 right); | 563 right); |
| 559 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); | 564 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); |
| 560 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); | 565 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); |
| 561 | 566 |
| 562 Condition true_condition = TokenKindToDoubleCondition(comp->kind()); | 567 Condition true_condition = TokenKindToDoubleCondition(kind); |
| 563 if (comp->is_fused_with_branch()) { | 568 if (branch != NULL) { |
| 564 compiler->EmitDoubleCompareBranch( | 569 compiler->EmitDoubleCompareBranch( |
| 565 true_condition, XMM0, XMM1, comp->fused_with_branch()); | 570 true_condition, XMM0, XMM1, branch); |
| 566 } else { | 571 } else { |
| 567 compiler->EmitDoubleCompareBool( | 572 compiler->EmitDoubleCompareBool( |
| 568 true_condition, XMM0, XMM1, comp->locs()->out().reg()); | 573 true_condition, XMM0, XMM1, locs.out().reg()); |
| 569 } | 574 } |
| 570 } | 575 } |
| 571 | 576 |
| 572 | 577 |
| 573 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 578 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 574 if (operands_class_id() == kSmi) { | 579 if (operands_class_id() == kSmi) { |
| 575 EmitSmiRelationalOp(compiler, this); | 580 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, |
| 581 cid(), token_pos(), try_index()); |
| 576 return; | 582 return; |
| 577 } | 583 } |
| 578 if (operands_class_id() == kDouble) { | 584 if (operands_class_id() == kDouble) { |
| 579 EmitDoubleRelationalOp(compiler, this); | 585 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, |
| 586 cid(), token_pos(), try_index()); |
| 580 return; | 587 return; |
| 581 } | 588 } |
| 582 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 589 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 583 Label* deopt = compiler->AddDeoptStub(cid(), | 590 Label* deopt = compiler->AddDeoptStub(cid(), |
| 584 token_pos(), | 591 token_pos(), |
| 585 try_index(), | 592 try_index(), |
| 586 kDeoptRelationalOp); | 593 kDeoptRelationalOp); |
| 587 // Load receiver into RAX, class into RDI. | 594 // Load receiver into RAX, class into RDI. |
| 588 Label done; | 595 Label done; |
| 589 const intptr_t kNumArguments = 2; | 596 const intptr_t kNumArguments = 2; |
| (...skipping 1437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2027 instance_call()->token_pos(), | 2034 instance_call()->token_pos(), |
| 2028 instance_call()->try_index(), | 2035 instance_call()->try_index(), |
| 2029 target, | 2036 target, |
| 2030 instance_call()->ArgumentCount(), | 2037 instance_call()->ArgumentCount(), |
| 2031 instance_call()->argument_names()); | 2038 instance_call()->argument_names()); |
| 2032 } | 2039 } |
| 2033 __ Bind(&done); | 2040 __ Bind(&done); |
| 2034 } | 2041 } |
| 2035 | 2042 |
| 2036 | 2043 |
| 2044 // TODO(srdjan): Move to shared. |
| 2045 static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) { |
| 2046 if (ic_data.num_args_tested() != 2) return false; |
| 2047 if (ic_data.NumberOfChecks() != 1) return false; |
| 2048 Function& target = Function::Handle(); |
| 2049 GrowableArray<intptr_t> class_ids; |
| 2050 ic_data.GetCheckAt(0, &class_ids, &target); |
| 2051 return (class_ids[0] == class_id) && (class_ids[1] == class_id); |
| 2052 } |
| 2053 |
| 2054 |
| 2055 LocationSummary* BranchInstr::MakeLocationSummary() const { |
| 2056 if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) { |
| 2057 const int kNumInputs = 2; |
| 2058 const int kNumTemps = 0; |
| 2059 LocationSummary* locs = new LocationSummary(kNumInputs, |
| 2060 kNumTemps, |
| 2061 LocationSummary::kNoCall); |
| 2062 locs->set_in(0, Location::RequiresRegister()); |
| 2063 locs->set_in(1, Location::RequiresRegister()); |
| 2064 return locs; |
| 2065 } |
| 2066 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 2067 if (ICDataWithBothClassIds(*ic_data(), kSmi) || |
| 2068 ICDataWithBothClassIds(*ic_data(), kDouble)) { |
| 2069 const intptr_t kNumInputs = 2; |
| 2070 const intptr_t kNumTemps = 1; |
| 2071 LocationSummary* summary = new LocationSummary(kNumInputs, |
| 2072 kNumTemps, |
| 2073 LocationSummary::kNoCall); |
| 2074 summary->set_in(0, Location::RequiresRegister()); |
| 2075 summary->set_in(1, Location::RequiresRegister()); |
| 2076 summary->set_temp(0, Location::RequiresRegister()); |
| 2077 return summary; |
| 2078 } |
| 2079 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { |
| 2080 const intptr_t kNumInputs = 2; |
| 2081 const intptr_t kNumTemps = 1; |
| 2082 LocationSummary* locs = new LocationSummary(kNumInputs, |
| 2083 kNumTemps, |
| 2084 LocationSummary::kCall); |
| 2085 locs->set_in(0, Location::RequiresRegister()); |
| 2086 locs->set_in(1, Location::RequiresRegister()); |
| 2087 locs->set_temp(0, Location::RequiresRegister()); |
| 2088 return locs; |
| 2089 } |
| 2090 // Otherwise polymorphic dispatch. |
| 2091 } |
| 2092 // Call. |
| 2093 LocationSummary* result = new LocationSummary(0, 0, LocationSummary::kCall); |
| 2094 result->set_out(Location::RegisterLocation(RAX)); |
| 2095 return result; |
| 2096 } |
| 2097 |
| 2098 |
| 2099 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2100 if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) { |
| 2101 Register left = locs()->in(0).reg(); |
| 2102 Register right = locs()->in(1).reg(); |
| 2103 __ cmpq(left, right); |
| 2104 Condition cond = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL; |
| 2105 EmitBranchOnCondition(compiler, cond); |
| 2106 return; |
| 2107 } |
| 2108 // Relational or equality. |
| 2109 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 2110 if (ICDataWithBothClassIds(*ic_data(), kSmi)) { |
| 2111 EmitSmiComparisonOp(compiler, *locs(), kind(), this, |
| 2112 cid(), token_pos(), try_index()); |
| 2113 return; |
| 2114 } |
| 2115 if (ICDataWithBothClassIds(*ic_data(), kDouble)) { |
| 2116 EmitDoubleComparisonOp(compiler, *locs(), kind(), this, |
| 2117 cid(), token_pos(), try_index()); |
| 2118 return; |
| 2119 } |
| 2120 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons. |
| 2121 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { |
| 2122 EmitGenericEqualityCompare(compiler, *locs(), kind(), this, *ic_data(), |
| 2123 cid(), token_pos(), try_index()); |
| 2124 return; |
| 2125 } |
| 2126 // Otherwise polymorphic dispatch? |
| 2127 } |
| 2128 // Not equal is always split into '==' and negate, |
| 2129 Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL; |
| 2130 Token::Kind call_kind = (kind() == Token::kNE) ? Token::kEQ : kind(); |
| 2131 const String& function_name = |
| 2132 String::ZoneHandle(String::NewSymbol(Token::Str(call_kind))); |
| 2133 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 2134 cid(), |
| 2135 token_pos(), |
| 2136 try_index()); |
| 2137 const intptr_t kNumArguments = 2; |
| 2138 const intptr_t kNumArgsChecked = 2; // Type-feedback. |
| 2139 compiler->GenerateInstanceCall(cid(), |
| 2140 token_pos(), |
| 2141 try_index(), |
| 2142 function_name, |
| 2143 kNumArguments, |
| 2144 Array::ZoneHandle(), // No optional arguments. |
| 2145 kNumArgsChecked); |
| 2146 ASSERT(locs()->out().reg() == RAX); |
| 2147 __ CompareObject(locs()->out().reg(), compiler->bool_true()); |
| 2148 EmitBranchOnCondition(compiler, branch_condition); |
| 2149 } |
| 2150 |
| 2037 } // namespace dart | 2151 } // namespace dart |
| 2038 | 2152 |
| 2039 #undef __ | 2153 #undef __ |
| 2040 | 2154 |
| 2041 #endif // defined TARGET_ARCH_X64 | 2155 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |