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