| 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 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 __ Bind(¬_yet_hot); | 81 __ Bind(¬_yet_hot); |
| 82 __ Bind(&already_optimized); | 82 __ Bind(&already_optimized); |
| 83 } | 83 } |
| 84 } | 84 } |
| 85 if (FLAG_trace_functions) { | 85 if (FLAG_trace_functions) { |
| 86 const Function& function = | 86 const Function& function = |
| 87 Function::ZoneHandle(compiler->parsed_function().function().raw()); | 87 Function::ZoneHandle(compiler->parsed_function().function().raw()); |
| 88 __ LoadObject(temp, function); | 88 __ LoadObject(temp, function); |
| 89 __ pushq(result); // Preserve result. | 89 __ pushq(result); // Preserve result. |
| 90 __ pushq(temp); | 90 __ pushq(temp); |
| 91 compiler->GenerateCallRuntime(AstNode::kNoId, | 91 compiler->GenerateCallRuntime(Isolate::kNoDeoptId, |
| 92 0, | 92 0, |
| 93 CatchClauseNode::kInvalidTryIndex, | 93 CatchClauseNode::kInvalidTryIndex, |
| 94 kTraceFunctionExitRuntimeEntry); | 94 kTraceFunctionExitRuntimeEntry); |
| 95 __ popq(temp); // Remove argument. | 95 __ popq(temp); // Remove argument. |
| 96 __ popq(result); // Restore result. | 96 __ popq(result); // Restore result. |
| 97 } | 97 } |
| 98 __ LeaveFrame(); | 98 __ LeaveFrame(); |
| 99 __ ret(); | 99 __ ret(); |
| 100 | 100 |
| 101 // Generate 8 bytes of NOPs so that the debugger can patch the | 101 // Generate 8 bytes of NOPs so that the debugger can patch the |
| 102 // return pattern with a call to the debug stub. | 102 // return pattern with a call to the debug stub. |
| 103 // Note that the nop(8) byte pattern is not recognized by the debugger. | 103 // Note that the nop(8) byte pattern is not recognized by the debugger. |
| 104 __ nop(1); | 104 __ nop(1); |
| 105 __ nop(1); | 105 __ nop(1); |
| 106 __ nop(1); | 106 __ nop(1); |
| 107 __ nop(1); | 107 __ nop(1); |
| 108 __ nop(1); | 108 __ nop(1); |
| 109 __ nop(1); | 109 __ nop(1); |
| 110 __ nop(1); | 110 __ nop(1); |
| 111 __ nop(1); | 111 __ nop(1); |
| 112 compiler->AddCurrentDescriptor(PcDescriptors::kReturn, | 112 compiler->AddCurrentDescriptor(PcDescriptors::kReturn, |
| 113 cid(), | 113 deopt_id(), |
| 114 token_pos(), | 114 token_pos(), |
| 115 CatchClauseNode::kInvalidTryIndex); | 115 CatchClauseNode::kInvalidTryIndex); |
| 116 } | 116 } |
| 117 | 117 |
| 118 | 118 |
| 119 LocationSummary* ClosureCallComp::MakeLocationSummary() const { | 119 LocationSummary* ClosureCallComp::MakeLocationSummary() const { |
| 120 const intptr_t kNumInputs = 0; | 120 const intptr_t kNumInputs = 0; |
| 121 const intptr_t kNumTemps = 1; | 121 const intptr_t kNumTemps = 1; |
| 122 LocationSummary* result = | 122 LocationSummary* result = |
| 123 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 123 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 | 198 |
| 199 // Check that the type of the value is allowed in conditional context. | 199 // Check that the type of the value is allowed in conditional context. |
| 200 // Call the runtime if the object is not bool::true or bool::false. | 200 // Call the runtime if the object is not bool::true or bool::false. |
| 201 Label done; | 201 Label done; |
| 202 __ CompareObject(obj, compiler->bool_true()); | 202 __ CompareObject(obj, compiler->bool_true()); |
| 203 __ j(EQUAL, &done, Assembler::kNearJump); | 203 __ j(EQUAL, &done, Assembler::kNearJump); |
| 204 __ CompareObject(obj, compiler->bool_false()); | 204 __ CompareObject(obj, compiler->bool_false()); |
| 205 __ j(EQUAL, &done, Assembler::kNearJump); | 205 __ j(EQUAL, &done, Assembler::kNearJump); |
| 206 | 206 |
| 207 __ pushq(obj); // Push the source object. | 207 __ pushq(obj); // Push the source object. |
| 208 compiler->GenerateCallRuntime(cid(), | 208 compiler->GenerateCallRuntime(deopt_id(), |
| 209 token_pos(), | 209 token_pos(), |
| 210 try_index(), | 210 try_index(), |
| 211 kConditionTypeErrorRuntimeEntry); | 211 kConditionTypeErrorRuntimeEntry); |
| 212 // We should never return here. | 212 // We should never return here. |
| 213 __ int3(); | 213 __ int3(); |
| 214 | 214 |
| 215 __ Bind(&done); | 215 __ Bind(&done); |
| 216 ASSERT(obj == result); | 216 ASSERT(obj == result); |
| 217 } | 217 } |
| 218 | 218 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 } | 268 } |
| 269 | 269 |
| 270 | 270 |
| 271 // Optional integer arguments can often be null. Null is not collected | 271 // Optional integer arguments can often be null. Null is not collected |
| 272 // by IC data. TODO(srdjan): Shall we collect null classes in ICData as well? | 272 // by IC data. TODO(srdjan): Shall we collect null classes in ICData as well? |
| 273 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, | 273 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, |
| 274 EqualityCompareComp* comp) { | 274 EqualityCompareComp* comp) { |
| 275 Register left = comp->locs()->in(0).reg(); | 275 Register left = comp->locs()->in(0).reg(); |
| 276 Register right = comp->locs()->in(1).reg(); | 276 Register right = comp->locs()->in(1).reg(); |
| 277 Register temp = comp->locs()->temp(0).reg(); | 277 Register temp = comp->locs()->temp(0).reg(); |
| 278 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 278 Label* deopt = compiler->AddDeoptStub(comp->deopt_id(), |
| 279 comp->token_pos(), | 279 comp->token_pos(), |
| 280 comp->try_index(), | 280 comp->try_index(), |
| 281 kDeoptSmiCompareSmi, | 281 kDeoptSmiCompareSmi, |
| 282 left, | 282 left, |
| 283 right); | 283 right); |
| 284 __ movq(temp, left); | 284 __ movq(temp, left); |
| 285 __ orq(temp, right); | 285 __ orq(temp, right); |
| 286 __ testq(temp, Immediate(kSmiTagMask)); | 286 __ testq(temp, Immediate(kSmiTagMask)); |
| 287 __ j(NOT_ZERO, deopt); | 287 __ j(NOT_ZERO, deopt); |
| 288 __ cmpq(left, right); | 288 __ cmpq(left, right); |
| 289 Register result = comp->locs()->out().reg(); | 289 Register result = comp->locs()->out().reg(); |
| 290 Label load_true, done; | 290 Label load_true, done; |
| 291 __ j(TokenKindToSmiCondition(comp->kind()), &load_true, Assembler::kNearJump); | 291 __ j(TokenKindToSmiCondition(comp->kind()), &load_true, Assembler::kNearJump); |
| 292 __ LoadObject(result, compiler->bool_false()); | 292 __ LoadObject(result, compiler->bool_false()); |
| 293 __ jmp(&done, Assembler::kNearJump); | 293 __ jmp(&done, Assembler::kNearJump); |
| 294 __ Bind(&load_true); | 294 __ Bind(&load_true); |
| 295 __ LoadObject(result, compiler->bool_true()); | 295 __ LoadObject(result, compiler->bool_true()); |
| 296 __ Bind(&done); | 296 __ Bind(&done); |
| 297 } | 297 } |
| 298 | 298 |
| 299 | 299 |
| 300 // TODO(srdjan): Add support for mixed Smi/Double equality | 300 // TODO(srdjan): Add support for mixed Smi/Double equality |
| 301 // (see LoadDoubleOrSmiToXmm). | 301 // (see LoadDoubleOrSmiToXmm). |
| 302 static void EmitDoubleEqualityCompare(FlowGraphCompiler* compiler, | 302 static void EmitDoubleEqualityCompare(FlowGraphCompiler* compiler, |
| 303 EqualityCompareComp* comp) { | 303 EqualityCompareComp* comp) { |
| 304 Register left = comp->locs()->in(0).reg(); | 304 Register left = comp->locs()->in(0).reg(); |
| 305 Register right = comp->locs()->in(1).reg(); | 305 Register right = comp->locs()->in(1).reg(); |
| 306 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 306 Label* deopt = compiler->AddDeoptStub(comp->deopt_id(), |
| 307 comp->token_pos(), | 307 comp->token_pos(), |
| 308 comp->try_index(), | 308 comp->try_index(), |
| 309 kDeoptDoubleCompareDouble, | 309 kDeoptDoubleCompareDouble, |
| 310 left, | 310 left, |
| 311 right); | 311 right); |
| 312 __ CompareClassId(left, kDouble); | 312 __ CompareClassId(left, kDouble); |
| 313 __ j(NOT_EQUAL, deopt); | 313 __ j(NOT_EQUAL, deopt); |
| 314 __ CompareClassId(right, kDouble); | 314 __ CompareClassId(right, kDouble); |
| 315 __ j(NOT_EQUAL, deopt); | 315 __ j(NOT_EQUAL, deopt); |
| 316 __ movsd(XMM0, FieldAddress(left, Double::value_offset())); | 316 __ movsd(XMM0, FieldAddress(left, Double::value_offset())); |
| 317 __ movsd(XMM1, FieldAddress(right, Double::value_offset())); | 317 __ movsd(XMM1, FieldAddress(right, Double::value_offset())); |
| 318 compiler->EmitDoubleCompareBool(TokenKindToSmiCondition(comp->kind()), | 318 compiler->EmitDoubleCompareBool(TokenKindToSmiCondition(comp->kind()), |
| 319 XMM0, XMM1, | 319 XMM0, XMM1, |
| 320 comp->locs()->out().reg()); | 320 comp->locs()->out().reg()); |
| 321 } | 321 } |
| 322 | 322 |
| 323 | 323 |
| 324 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, | 324 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, |
| 325 EqualityCompareComp* comp) { | 325 EqualityCompareComp* comp) { |
| 326 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 326 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 327 comp->cid(), | 327 comp->deopt_id(), |
| 328 comp->token_pos(), | 328 comp->token_pos(), |
| 329 comp->try_index()); | 329 comp->try_index()); |
| 330 const String& operator_name = String::ZoneHandle(Symbols::New("==")); | 330 const String& operator_name = String::ZoneHandle(Symbols::New("==")); |
| 331 const int kNumberOfArguments = 2; | 331 const int kNumberOfArguments = 2; |
| 332 const Array& kNoArgumentNames = Array::Handle(); | 332 const Array& kNoArgumentNames = Array::Handle(); |
| 333 const int kNumArgumentsChecked = 2; | 333 const int kNumArgumentsChecked = 2; |
| 334 | 334 |
| 335 compiler->GenerateInstanceCall(comp->cid(), | 335 compiler->GenerateInstanceCall(comp->deopt_id(), |
| 336 comp->token_pos(), | 336 comp->token_pos(), |
| 337 comp->try_index(), | 337 comp->try_index(), |
| 338 operator_name, | 338 operator_name, |
| 339 kNumberOfArguments, | 339 kNumberOfArguments, |
| 340 kNoArgumentNames, | 340 kNoArgumentNames, |
| 341 kNumArgumentsChecked); | 341 kNumArgumentsChecked); |
| 342 ASSERT(comp->locs()->out().reg() == RAX); | 342 ASSERT(comp->locs()->out().reg() == RAX); |
| 343 if (comp->kind() == Token::kNE) { | 343 if (comp->kind() == Token::kNE) { |
| 344 Label done, false_label; | 344 Label done, false_label; |
| 345 __ CompareObject(RAX, compiler->bool_true()); | 345 __ CompareObject(RAX, compiler->bool_true()); |
| 346 __ j(EQUAL, &false_label, Assembler::kNearJump); | 346 __ j(EQUAL, &false_label, Assembler::kNearJump); |
| 347 __ LoadObject(RAX, compiler->bool_true()); | 347 __ LoadObject(RAX, compiler->bool_true()); |
| 348 __ jmp(&done, Assembler::kNearJump); | 348 __ jmp(&done, Assembler::kNearJump); |
| 349 __ Bind(&false_label); | 349 __ Bind(&false_label); |
| 350 __ LoadObject(RAX, compiler->bool_false()); | 350 __ LoadObject(RAX, compiler->bool_false()); |
| 351 __ Bind(&done); | 351 __ Bind(&done); |
| 352 } | 352 } |
| 353 } | 353 } |
| 354 | 354 |
| 355 | 355 |
| 356 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, | 356 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, |
| 357 const ICData& orig_ic_data, | 357 const ICData& orig_ic_data, |
| 358 const LocationSummary& locs, | 358 const LocationSummary& locs, |
| 359 BranchInstr* branch, | 359 BranchInstr* branch, |
| 360 Token::Kind kind, | 360 Token::Kind kind, |
| 361 intptr_t cid, | 361 intptr_t deopt_id, |
| 362 intptr_t token_pos, | 362 intptr_t token_pos, |
| 363 intptr_t try_index) { | 363 intptr_t try_index) { |
| 364 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | 364 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); |
| 365 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks()); | 365 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks()); |
| 366 ASSERT(ic_data.NumberOfChecks() > 0); | 366 ASSERT(ic_data.NumberOfChecks() > 0); |
| 367 ASSERT(ic_data.num_args_tested() == 1); | 367 ASSERT(ic_data.num_args_tested() == 1); |
| 368 Label* deopt = compiler->AddDeoptStub(cid, | 368 Label* deopt = compiler->AddDeoptStub(deopt_id, |
| 369 token_pos, | 369 token_pos, |
| 370 try_index, | 370 try_index, |
| 371 kDeoptEquality); | 371 kDeoptEquality); |
| 372 Register left = locs.in(0).reg(); | 372 Register left = locs.in(0).reg(); |
| 373 Register right = locs.in(1).reg(); | 373 Register right = locs.in(1).reg(); |
| 374 __ testq(left, Immediate(kSmiTagMask)); | 374 __ testq(left, Immediate(kSmiTagMask)); |
| 375 Register temp = locs.temp(0).reg(); | 375 Register temp = locs.temp(0).reg(); |
| 376 if (ic_data.GetReceiverClassIdAt(0) == kSmi) { | 376 if (ic_data.GetReceiverClassIdAt(0) == kSmi) { |
| 377 Label done, load_class_id; | 377 Label done, load_class_id; |
| 378 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump); | 378 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 406 Label load_true; | 406 Label load_true; |
| 407 __ j(cond, &load_true, Assembler::kNearJump); | 407 __ j(cond, &load_true, Assembler::kNearJump); |
| 408 __ LoadObject(result, compiler->bool_false()); | 408 __ LoadObject(result, compiler->bool_false()); |
| 409 __ jmp(&done); | 409 __ jmp(&done); |
| 410 __ Bind(&load_true); | 410 __ Bind(&load_true); |
| 411 __ LoadObject(result, compiler->bool_true()); | 411 __ LoadObject(result, compiler->bool_true()); |
| 412 } | 412 } |
| 413 } else { | 413 } else { |
| 414 const int kNumberOfArguments = 2; | 414 const int kNumberOfArguments = 2; |
| 415 const Array& kNoArgumentNames = Array::Handle(); | 415 const Array& kNoArgumentNames = Array::Handle(); |
| 416 compiler->GenerateStaticCall(cid, | 416 compiler->GenerateStaticCall(deopt_id, |
| 417 token_pos, | 417 token_pos, |
| 418 try_index, | 418 try_index, |
| 419 target, | 419 target, |
| 420 kNumberOfArguments, | 420 kNumberOfArguments, |
| 421 kNoArgumentNames); | 421 kNoArgumentNames); |
| 422 if (branch == NULL) { | 422 if (branch == NULL) { |
| 423 if (kind == Token::kNE) { | 423 if (kind == Token::kNE) { |
| 424 Label false_label; | 424 Label false_label; |
| 425 __ CompareObject(RAX, compiler->bool_true()); | 425 __ CompareObject(RAX, compiler->bool_true()); |
| 426 __ j(EQUAL, &false_label, Assembler::kNearJump); | 426 __ j(EQUAL, &false_label, Assembler::kNearJump); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 445 | 445 |
| 446 | 446 |
| 447 // First test if receiver is NULL, in which case === is applied. | 447 // First test if receiver is NULL, in which case === is applied. |
| 448 // If type feedback was provided (lists of <class-id, target>), do a | 448 // If type feedback was provided (lists of <class-id, target>), do a |
| 449 // type by type check (either === or static call to the operator. | 449 // type by type check (either === or static call to the operator. |
| 450 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, | 450 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, |
| 451 const LocationSummary& locs, | 451 const LocationSummary& locs, |
| 452 Token::Kind kind, | 452 Token::Kind kind, |
| 453 BranchInstr* branch, | 453 BranchInstr* branch, |
| 454 const ICData& ic_data, | 454 const ICData& ic_data, |
| 455 intptr_t cid, | 455 intptr_t deopt_id, |
| 456 intptr_t token_pos, | 456 intptr_t token_pos, |
| 457 intptr_t try_index) { | 457 intptr_t try_index) { |
| 458 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | 458 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); |
| 459 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); | 459 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); |
| 460 Register left = locs.in(0).reg(); | 460 Register left = locs.in(0).reg(); |
| 461 Register right = locs.in(1).reg(); | 461 Register right = locs.in(1).reg(); |
| 462 const Immediate raw_null = | 462 const Immediate raw_null = |
| 463 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 463 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 464 Label done, non_null_compare; | 464 Label done, non_null_compare; |
| 465 __ cmpq(left, raw_null); | 465 __ cmpq(left, raw_null); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 476 __ LoadObject(result, compiler->bool_false()); | 476 __ LoadObject(result, compiler->bool_false()); |
| 477 __ jmp(&done); | 477 __ jmp(&done); |
| 478 __ Bind(&load_true); | 478 __ Bind(&load_true); |
| 479 __ LoadObject(result, compiler->bool_true()); | 479 __ LoadObject(result, compiler->bool_true()); |
| 480 } | 480 } |
| 481 __ jmp(&done); | 481 __ jmp(&done); |
| 482 __ Bind(&non_null_compare); // Receiver is not null. | 482 __ Bind(&non_null_compare); // Receiver is not null. |
| 483 __ pushq(left); | 483 __ pushq(left); |
| 484 __ pushq(right); | 484 __ pushq(right); |
| 485 EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind, | 485 EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind, |
| 486 cid, token_pos, try_index); | 486 deopt_id, token_pos, try_index); |
| 487 __ Bind(&done); | 487 __ Bind(&done); |
| 488 } | 488 } |
| 489 | 489 |
| 490 | 490 |
| 491 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 491 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 492 if (receiver_class_id() == kSmi) { | 492 if (receiver_class_id() == kSmi) { |
| 493 EmitSmiEqualityCompare(compiler, this); | 493 EmitSmiEqualityCompare(compiler, this); |
| 494 return; | 494 return; |
| 495 } | 495 } |
| 496 if (receiver_class_id() == kDouble) { | 496 if (receiver_class_id() == kDouble) { |
| 497 EmitDoubleEqualityCompare(compiler, this); | 497 EmitDoubleEqualityCompare(compiler, this); |
| 498 return; | 498 return; |
| 499 } | 499 } |
| 500 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 500 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 501 EmitGenericEqualityCompare(compiler, *locs(), kind(), NULL, | 501 EmitGenericEqualityCompare(compiler, *locs(), kind(), NULL, *ic_data(), |
| 502 *ic_data(), cid(), token_pos(), try_index()); | 502 deopt_id(), token_pos(), try_index()); |
| 503 } else { | 503 } else { |
| 504 Register left = locs()->in(0).reg(); | 504 Register left = locs()->in(0).reg(); |
| 505 Register right = locs()->in(1).reg(); | 505 Register right = locs()->in(1).reg(); |
| 506 __ pushq(left); | 506 __ pushq(left); |
| 507 __ pushq(right); | 507 __ pushq(right); |
| 508 EmitEqualityAsInstanceCall(compiler, this); | 508 EmitEqualityAsInstanceCall(compiler, this); |
| 509 } | 509 } |
| 510 } | 510 } |
| 511 | 511 |
| 512 | 512 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 524 } | 524 } |
| 525 ASSERT(operands_class_id() == kObject); | 525 ASSERT(operands_class_id() == kObject); |
| 526 return MakeCallSummary(); | 526 return MakeCallSummary(); |
| 527 } | 527 } |
| 528 | 528 |
| 529 | 529 |
| 530 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler, | 530 static void EmitSmiComparisonOp(FlowGraphCompiler* compiler, |
| 531 const LocationSummary& locs, | 531 const LocationSummary& locs, |
| 532 Token::Kind kind, | 532 Token::Kind kind, |
| 533 BranchInstr* branch, | 533 BranchInstr* branch, |
| 534 intptr_t cid, | 534 intptr_t deopt_id, |
| 535 intptr_t token_pos, | 535 intptr_t token_pos, |
| 536 intptr_t try_index) { | 536 intptr_t try_index) { |
| 537 Register left = locs.in(0).reg(); | 537 Register left = locs.in(0).reg(); |
| 538 Register right = locs.in(1).reg(); | 538 Register right = locs.in(1).reg(); |
| 539 Register temp = locs.temp(0).reg(); | 539 Register temp = locs.temp(0).reg(); |
| 540 Label* deopt = compiler->AddDeoptStub(cid, | 540 Label* deopt = compiler->AddDeoptStub(deopt_id, |
| 541 token_pos, | 541 token_pos, |
| 542 try_index, | 542 try_index, |
| 543 kDeoptSmiCompareSmi, | 543 kDeoptSmiCompareSmi, |
| 544 left, | 544 left, |
| 545 right); | 545 right); |
| 546 __ movq(temp, left); | 546 __ movq(temp, left); |
| 547 __ orq(temp, right); | 547 __ orq(temp, right); |
| 548 __ testq(temp, Immediate(kSmiTagMask)); | 548 __ testq(temp, Immediate(kSmiTagMask)); |
| 549 __ j(NOT_ZERO, deopt); | 549 __ j(NOT_ZERO, deopt); |
| 550 | 550 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 578 UNREACHABLE(); | 578 UNREACHABLE(); |
| 579 return OVERFLOW; | 579 return OVERFLOW; |
| 580 } | 580 } |
| 581 } | 581 } |
| 582 | 582 |
| 583 | 583 |
| 584 static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler, | 584 static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler, |
| 585 const LocationSummary& locs, | 585 const LocationSummary& locs, |
| 586 Token::Kind kind, | 586 Token::Kind kind, |
| 587 BranchInstr* branch, | 587 BranchInstr* branch, |
| 588 intptr_t cid, | 588 intptr_t deopt_id, |
| 589 intptr_t token_pos, | 589 intptr_t token_pos, |
| 590 intptr_t try_index) { | 590 intptr_t try_index) { |
| 591 Register left = locs.in(0).reg(); | 591 Register left = locs.in(0).reg(); |
| 592 Register right = locs.in(1).reg(); | 592 Register right = locs.in(1).reg(); |
| 593 // TODO(srdjan): temp is only needed if a conversion Smi->Double occurs. | 593 // TODO(srdjan): temp is only needed if a conversion Smi->Double occurs. |
| 594 Register temp = locs.temp(0).reg(); | 594 Register temp = locs.temp(0).reg(); |
| 595 Label* deopt = compiler->AddDeoptStub(cid, | 595 Label* deopt = compiler->AddDeoptStub(deopt_id, |
| 596 token_pos, | 596 token_pos, |
| 597 try_index, | 597 try_index, |
| 598 kDeoptDoubleComparison, | 598 kDeoptDoubleComparison, |
| 599 left, | 599 left, |
| 600 right); | 600 right); |
| 601 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); | 601 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); |
| 602 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); | 602 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); |
| 603 | 603 |
| 604 Condition true_condition = TokenKindToDoubleCondition(kind); | 604 Condition true_condition = TokenKindToDoubleCondition(kind); |
| 605 if (branch != NULL) { | 605 if (branch != NULL) { |
| 606 compiler->EmitDoubleCompareBranch( | 606 compiler->EmitDoubleCompareBranch( |
| 607 true_condition, XMM0, XMM1, branch); | 607 true_condition, XMM0, XMM1, branch); |
| 608 } else { | 608 } else { |
| 609 compiler->EmitDoubleCompareBool( | 609 compiler->EmitDoubleCompareBool( |
| 610 true_condition, XMM0, XMM1, locs.out().reg()); | 610 true_condition, XMM0, XMM1, locs.out().reg()); |
| 611 } | 611 } |
| 612 } | 612 } |
| 613 | 613 |
| 614 | 614 |
| 615 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 615 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 616 if (operands_class_id() == kSmi) { | 616 if (operands_class_id() == kSmi) { |
| 617 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, | 617 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, |
| 618 cid(), token_pos(), try_index()); | 618 deopt_id(), token_pos(), try_index()); |
| 619 return; | 619 return; |
| 620 } | 620 } |
| 621 if (operands_class_id() == kDouble) { | 621 if (operands_class_id() == kDouble) { |
| 622 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, | 622 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, |
| 623 cid(), token_pos(), try_index()); | 623 deopt_id(), token_pos(), try_index()); |
| 624 return; | 624 return; |
| 625 } | 625 } |
| 626 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 626 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 627 Label* deopt = compiler->AddDeoptStub(cid(), | 627 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
| 628 token_pos(), | 628 token_pos(), |
| 629 try_index(), | 629 try_index(), |
| 630 kDeoptRelationalOp); | 630 kDeoptRelationalOp); |
| 631 // Load receiver into RAX, class into RDI. | 631 // Load receiver into RAX, class into RDI. |
| 632 Label done; | 632 Label done; |
| 633 const intptr_t kNumArguments = 2; | 633 const intptr_t kNumArguments = 2; |
| 634 __ movq(RDI, Immediate(kSmi)); | 634 __ movq(RDI, Immediate(kSmi)); |
| 635 __ movq(RAX, Address(RSP, (kNumArguments - 1) * kWordSize)); | 635 __ movq(RAX, Address(RSP, (kNumArguments - 1) * kWordSize)); |
| 636 __ testq(RAX, Immediate(kSmiTagMask)); | 636 __ testq(RAX, Immediate(kSmiTagMask)); |
| 637 __ j(ZERO, &done); | 637 __ j(ZERO, &done); |
| 638 __ LoadClassId(RDI, RAX); | 638 __ LoadClassId(RDI, RAX); |
| 639 __ Bind(&done); | 639 __ Bind(&done); |
| 640 compiler->EmitTestAndCall(ICData::Handle(ic_data()->AsUnaryClassChecks()), | 640 compiler->EmitTestAndCall(ICData::Handle(ic_data()->AsUnaryClassChecks()), |
| 641 RDI, // Class id register. | 641 RDI, // Class id register. |
| 642 kNumArguments, | 642 kNumArguments, |
| 643 Array::Handle(), // No named arguments. | 643 Array::Handle(), // No named arguments. |
| 644 deopt, // Deoptimize target. | 644 deopt, // Deoptimize target. |
| 645 NULL, // Fallthrough when done. | 645 NULL, // Fallthrough when done. |
| 646 cid(), | 646 deopt_id(), |
| 647 token_pos(), | 647 token_pos(), |
| 648 try_index()); | 648 try_index()); |
| 649 return; | 649 return; |
| 650 } | 650 } |
| 651 const String& function_name = | 651 const String& function_name = |
| 652 String::ZoneHandle(Symbols::New(Token::Str(kind()))); | 652 String::ZoneHandle(Symbols::New(Token::Str(kind()))); |
| 653 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 653 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 654 cid(), | 654 deopt_id(), |
| 655 token_pos(), | 655 token_pos(), |
| 656 try_index()); | 656 try_index()); |
| 657 const intptr_t kNumArguments = 2; | 657 const intptr_t kNumArguments = 2; |
| 658 const intptr_t kNumArgsChecked = 2; // Type-feedback. | 658 const intptr_t kNumArgsChecked = 2; // Type-feedback. |
| 659 compiler->GenerateInstanceCall(cid(), | 659 compiler->GenerateInstanceCall(deopt_id(), |
| 660 token_pos(), | 660 token_pos(), |
| 661 try_index(), | 661 try_index(), |
| 662 function_name, | 662 function_name, |
| 663 kNumArguments, | 663 kNumArguments, |
| 664 Array::ZoneHandle(), // No optional arguments. | 664 Array::ZoneHandle(), // No optional arguments. |
| 665 kNumArgsChecked); | 665 kNumArgsChecked); |
| 666 ASSERT(locs()->out().reg() == RAX); | 666 ASSERT(locs()->out().reg() == RAX); |
| 667 } | 667 } |
| 668 | 668 |
| 669 | 669 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 727 LocationSummary::kNoCall); | 727 LocationSummary::kNoCall); |
| 728 } else { | 728 } else { |
| 729 ASSERT(receiver_type() == kIllegalObjectKind); | 729 ASSERT(receiver_type() == kIllegalObjectKind); |
| 730 return MakeCallSummary(); | 730 return MakeCallSummary(); |
| 731 } | 731 } |
| 732 } | 732 } |
| 733 | 733 |
| 734 | 734 |
| 735 static void EmitLoadIndexedPolymorphic(FlowGraphCompiler* compiler, | 735 static void EmitLoadIndexedPolymorphic(FlowGraphCompiler* compiler, |
| 736 LoadIndexedComp* comp) { | 736 LoadIndexedComp* comp) { |
| 737 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 737 Label* deopt = compiler->AddDeoptStub(comp->deopt_id(), |
| 738 comp->token_pos(), | 738 comp->token_pos(), |
| 739 comp->try_index(), | 739 comp->try_index(), |
| 740 kDeoptLoadIndexedPolymorphic); | 740 kDeoptLoadIndexedPolymorphic); |
| 741 ASSERT(comp->ic_data()->NumberOfChecks() > 0); | 741 ASSERT(comp->ic_data()->NumberOfChecks() > 0); |
| 742 ASSERT(comp->HasICData()); | 742 ASSERT(comp->HasICData()); |
| 743 const ICData& ic_data = *comp->ic_data(); | 743 const ICData& ic_data = *comp->ic_data(); |
| 744 ASSERT(ic_data.num_args_tested() == 1); | 744 ASSERT(ic_data.num_args_tested() == 1); |
| 745 // No indexed access on Smi. | 745 // No indexed access on Smi. |
| 746 ASSERT(ic_data.GetReceiverClassIdAt(0) != kSmi); | 746 ASSERT(ic_data.GetReceiverClassIdAt(0) != kSmi); |
| 747 // Load receiver into RAX. | 747 // Load receiver into RAX. |
| 748 const intptr_t kNumArguments = 2; | 748 const intptr_t kNumArguments = 2; |
| 749 __ movq(RAX, Address(RSP, (kNumArguments - 1) * kWordSize)); | 749 __ movq(RAX, Address(RSP, (kNumArguments - 1) * kWordSize)); |
| 750 __ testq(RAX, Immediate(kSmiTagMask)); | 750 __ testq(RAX, Immediate(kSmiTagMask)); |
| 751 __ j(ZERO, deopt); | 751 __ j(ZERO, deopt); |
| 752 __ LoadClassId(RDI, RAX); | 752 __ LoadClassId(RDI, RAX); |
| 753 compiler->EmitTestAndCall(ic_data, | 753 compiler->EmitTestAndCall(ic_data, |
| 754 RDI, // Class id register. | 754 RDI, // Class id register. |
| 755 kNumArguments, | 755 kNumArguments, |
| 756 Array::Handle(), // No named arguments. | 756 Array::Handle(), // No named arguments. |
| 757 deopt, // Deoptimize target. | 757 deopt, // Deoptimize target. |
| 758 NULL, // Fallthrough when done. | 758 NULL, // Fallthrough when done. |
| 759 comp->cid(), | 759 comp->deopt_id(), |
| 760 comp->token_pos(), | 760 comp->token_pos(), |
| 761 comp->try_index()); | 761 comp->try_index()); |
| 762 } | 762 } |
| 763 | 763 |
| 764 | 764 |
| 765 void LoadIndexedComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 765 void LoadIndexedComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 766 if (receiver_type() == kIllegalObjectKind) { | 766 if (receiver_type() == kIllegalObjectKind) { |
| 767 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 767 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 768 EmitLoadIndexedPolymorphic(compiler, this); | 768 EmitLoadIndexedPolymorphic(compiler, this); |
| 769 } else { | 769 } else { |
| 770 compiler->EmitLoadIndexedGeneric(this); | 770 compiler->EmitLoadIndexedGeneric(this); |
| 771 } | 771 } |
| 772 ASSERT(locs()->out().reg() == RAX); | 772 ASSERT(locs()->out().reg() == RAX); |
| 773 return; | 773 return; |
| 774 } | 774 } |
| 775 | 775 |
| 776 Register receiver = locs()->in(0).reg(); | 776 Register receiver = locs()->in(0).reg(); |
| 777 Register index = locs()->in(1).reg(); | 777 Register index = locs()->in(1).reg(); |
| 778 Register result = locs()->out().reg(); | 778 Register result = locs()->out().reg(); |
| 779 | 779 |
| 780 const DeoptReasonId deopt_reason = (receiver_type() == kGrowableObjectArray) ? | 780 const DeoptReasonId deopt_reason = (receiver_type() == kGrowableObjectArray) ? |
| 781 kDeoptLoadIndexedGrowableArray : kDeoptLoadIndexedFixedArray; | 781 kDeoptLoadIndexedGrowableArray : kDeoptLoadIndexedFixedArray; |
| 782 | 782 |
| 783 Label* deopt = compiler->AddDeoptStub(cid(), | 783 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
| 784 token_pos(), | 784 token_pos(), |
| 785 try_index(), | 785 try_index(), |
| 786 deopt_reason, | 786 deopt_reason, |
| 787 receiver, | 787 receiver, |
| 788 index); | 788 index); |
| 789 | 789 |
| 790 __ testq(receiver, Immediate(kSmiTagMask)); // Deoptimize if Smi. | 790 __ testq(receiver, Immediate(kSmiTagMask)); // Deoptimize if Smi. |
| 791 __ j(ZERO, deopt); | 791 __ j(ZERO, deopt); |
| 792 __ CompareClassId(receiver, receiver_type()); | 792 __ CompareClassId(receiver, receiver_type()); |
| 793 __ j(NOT_EQUAL, deopt); | 793 __ j(NOT_EQUAL, deopt); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 847 } | 847 } |
| 848 } | 848 } |
| 849 | 849 |
| 850 | 850 |
| 851 static void EmitStoreIndexedGeneric(FlowGraphCompiler* compiler, | 851 static void EmitStoreIndexedGeneric(FlowGraphCompiler* compiler, |
| 852 StoreIndexedComp* comp) { | 852 StoreIndexedComp* comp) { |
| 853 const String& function_name = | 853 const String& function_name = |
| 854 String::ZoneHandle(Symbols::New(Token::Str(Token::kASSIGN_INDEX))); | 854 String::ZoneHandle(Symbols::New(Token::Str(Token::kASSIGN_INDEX))); |
| 855 | 855 |
| 856 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 856 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 857 comp->cid(), | 857 comp->deopt_id(), |
| 858 comp->token_pos(), | 858 comp->token_pos(), |
| 859 comp->try_index()); | 859 comp->try_index()); |
| 860 | 860 |
| 861 const intptr_t kNumArguments = 3; | 861 const intptr_t kNumArguments = 3; |
| 862 const intptr_t kNumArgsChecked = 1; // Type-feedback. | 862 const intptr_t kNumArgsChecked = 1; // Type-feedback. |
| 863 compiler->GenerateInstanceCall(comp->cid(), | 863 compiler->GenerateInstanceCall(comp->deopt_id(), |
| 864 comp->token_pos(), | 864 comp->token_pos(), |
| 865 comp->try_index(), | 865 comp->try_index(), |
| 866 function_name, | 866 function_name, |
| 867 kNumArguments, | 867 kNumArguments, |
| 868 Array::ZoneHandle(), // No named arguments. | 868 Array::ZoneHandle(), // No named arguments. |
| 869 kNumArgsChecked); | 869 kNumArgsChecked); |
| 870 } | 870 } |
| 871 | 871 |
| 872 | 872 |
| 873 static void EmitStoreIndexedPolymorphic(FlowGraphCompiler* compiler, | 873 static void EmitStoreIndexedPolymorphic(FlowGraphCompiler* compiler, |
| 874 StoreIndexedComp* comp) { | 874 StoreIndexedComp* comp) { |
| 875 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 875 Label* deopt = compiler->AddDeoptStub(comp->deopt_id(), |
| 876 comp->token_pos(), | 876 comp->token_pos(), |
| 877 comp->try_index(), | 877 comp->try_index(), |
| 878 kDeoptStoreIndexedPolymorphic); | 878 kDeoptStoreIndexedPolymorphic); |
| 879 ASSERT(comp->ic_data()->NumberOfChecks() > 0); | 879 ASSERT(comp->ic_data()->NumberOfChecks() > 0); |
| 880 ASSERT(comp->HasICData()); | 880 ASSERT(comp->HasICData()); |
| 881 const ICData& ic_data = *comp->ic_data(); | 881 const ICData& ic_data = *comp->ic_data(); |
| 882 ASSERT(ic_data.num_args_tested() == 1); | 882 ASSERT(ic_data.num_args_tested() == 1); |
| 883 // No indexed access on Smi. | 883 // No indexed access on Smi. |
| 884 ASSERT(ic_data.GetReceiverClassIdAt(0) != kSmi); | 884 ASSERT(ic_data.GetReceiverClassIdAt(0) != kSmi); |
| 885 // Load receiver into RAX. | 885 // Load receiver into RAX. |
| 886 const intptr_t kNumArguments = 3; | 886 const intptr_t kNumArguments = 3; |
| 887 __ movq(RAX, Address(RSP, (kNumArguments - 1) * kWordSize)); | 887 __ movq(RAX, Address(RSP, (kNumArguments - 1) * kWordSize)); |
| 888 __ testq(RAX, Immediate(kSmiTagMask)); | 888 __ testq(RAX, Immediate(kSmiTagMask)); |
| 889 __ j(ZERO, deopt); | 889 __ j(ZERO, deopt); |
| 890 __ LoadClassId(RDI, RAX); | 890 __ LoadClassId(RDI, RAX); |
| 891 compiler->EmitTestAndCall(ic_data, | 891 compiler->EmitTestAndCall(ic_data, |
| 892 RDI, // Class id register. | 892 RDI, // Class id register. |
| 893 kNumArguments, | 893 kNumArguments, |
| 894 Array::Handle(), // No named arguments. | 894 Array::Handle(), // No named arguments. |
| 895 deopt, // deoptimize label. | 895 deopt, // deoptimize label. |
| 896 NULL, // fallthrough when done. | 896 NULL, // fallthrough when done. |
| 897 comp->cid(), | 897 comp->deopt_id(), |
| 898 comp->token_pos(), | 898 comp->token_pos(), |
| 899 comp->try_index()); | 899 comp->try_index()); |
| 900 } | 900 } |
| 901 | 901 |
| 902 | 902 |
| 903 void StoreIndexedComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 903 void StoreIndexedComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 904 if (receiver_type() == kIllegalObjectKind) { | 904 if (receiver_type() == kIllegalObjectKind) { |
| 905 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 905 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 906 EmitStoreIndexedPolymorphic(compiler, this); | 906 EmitStoreIndexedPolymorphic(compiler, this); |
| 907 } else { | 907 } else { |
| 908 EmitStoreIndexedGeneric(compiler, this); | 908 EmitStoreIndexedGeneric(compiler, this); |
| 909 } | 909 } |
| 910 return; | 910 return; |
| 911 } | 911 } |
| 912 | 912 |
| 913 Register receiver = locs()->in(0).reg(); | 913 Register receiver = locs()->in(0).reg(); |
| 914 Register index = locs()->in(1).reg(); | 914 Register index = locs()->in(1).reg(); |
| 915 Register value = locs()->in(2).reg(); | 915 Register value = locs()->in(2).reg(); |
| 916 | 916 |
| 917 Label* deopt = compiler->AddDeoptStub(cid(), | 917 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
| 918 token_pos(), | 918 token_pos(), |
| 919 try_index(), | 919 try_index(), |
| 920 kDeoptStoreIndexed, | 920 kDeoptStoreIndexed, |
| 921 receiver, | 921 receiver, |
| 922 index, | 922 index, |
| 923 value); | 923 value); |
| 924 | 924 |
| 925 __ testq(receiver, Immediate(kSmiTagMask)); // Deoptimize if Smi. | 925 __ testq(receiver, Immediate(kSmiTagMask)); // Deoptimize if Smi. |
| 926 __ j(ZERO, deopt); | 926 __ j(ZERO, deopt); |
| 927 __ CompareClassId(receiver, receiver_type()); | 927 __ CompareClassId(receiver, receiver_type()); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 973 LocationSummary::kNoCall); | 973 LocationSummary::kNoCall); |
| 974 } | 974 } |
| 975 | 975 |
| 976 | 976 |
| 977 void LoadInstanceFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 977 void LoadInstanceFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 978 Register instance_reg = locs()->in(0).reg(); | 978 Register instance_reg = locs()->in(0).reg(); |
| 979 Register result_reg = locs()->out().reg(); | 979 Register result_reg = locs()->out().reg(); |
| 980 | 980 |
| 981 if (HasICData()) { | 981 if (HasICData()) { |
| 982 ASSERT(original() != NULL); | 982 ASSERT(original() != NULL); |
| 983 Label* deopt = compiler->AddDeoptStub(original()->cid(), | 983 Label* deopt = compiler->AddDeoptStub(original()->deopt_id(), |
| 984 original()->token_pos(), | 984 original()->token_pos(), |
| 985 original()->try_index(), | 985 original()->try_index(), |
| 986 kDeoptInstanceGetterSameTarget, | 986 kDeoptInstanceGetterSameTarget, |
| 987 instance_reg); | 987 instance_reg); |
| 988 // Smis do not have instance fields (Smi class is always first). | 988 // Smis do not have instance fields (Smi class is always first). |
| 989 // Use 'result' as temporary register. | 989 // Use 'result' as temporary register. |
| 990 ASSERT(result_reg != instance_reg); | 990 ASSERT(result_reg != instance_reg); |
| 991 ASSERT(ic_data() != NULL); | 991 ASSERT(ic_data() != NULL); |
| 992 compiler->EmitClassChecksNoSmi(*ic_data(), instance_reg, result_reg, deopt); | 992 compiler->EmitClassChecksNoSmi(*ic_data(), instance_reg, result_reg, deopt); |
| 993 } | 993 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1020 summary->set_out(Location::RegisterLocation(RAX)); | 1020 summary->set_out(Location::RegisterLocation(RAX)); |
| 1021 return summary; | 1021 return summary; |
| 1022 } | 1022 } |
| 1023 | 1023 |
| 1024 | 1024 |
| 1025 void InstanceOfComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 1025 void InstanceOfComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1026 ASSERT(locs()->in(0).reg() == RAX); // Value. | 1026 ASSERT(locs()->in(0).reg() == RAX); // Value. |
| 1027 ASSERT(locs()->in(1).reg() == RCX); // Instantiator. | 1027 ASSERT(locs()->in(1).reg() == RCX); // Instantiator. |
| 1028 ASSERT(locs()->in(2).reg() == RDX); // Instantiator type arguments. | 1028 ASSERT(locs()->in(2).reg() == RDX); // Instantiator type arguments. |
| 1029 | 1029 |
| 1030 compiler->GenerateInstanceOf(cid(), | 1030 compiler->GenerateInstanceOf(deopt_id(), |
| 1031 token_pos(), | 1031 token_pos(), |
| 1032 try_index(), | 1032 try_index(), |
| 1033 type(), | 1033 type(), |
| 1034 negate_result()); | 1034 negate_result()); |
| 1035 ASSERT(locs()->out().reg() == RAX); | 1035 ASSERT(locs()->out().reg() == RAX); |
| 1036 } | 1036 } |
| 1037 | 1037 |
| 1038 | 1038 |
| 1039 LocationSummary* CreateArrayComp::MakeLocationSummary() const { | 1039 LocationSummary* CreateArrayComp::MakeLocationSummary() const { |
| 1040 return MakeCallSummary(); | 1040 return MakeCallSummary(); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1079 const Class& cls = Class::ZoneHandle(constructor().owner()); | 1079 const Class& cls = Class::ZoneHandle(constructor().owner()); |
| 1080 Register type_arguments = locs()->in(0).reg(); | 1080 Register type_arguments = locs()->in(0).reg(); |
| 1081 Register instantiator_type_arguments = locs()->in(1).reg(); | 1081 Register instantiator_type_arguments = locs()->in(1).reg(); |
| 1082 Register result = locs()->out().reg(); | 1082 Register result = locs()->out().reg(); |
| 1083 | 1083 |
| 1084 // Push the result place holder initialized to NULL. | 1084 // Push the result place holder initialized to NULL. |
| 1085 __ PushObject(Object::ZoneHandle()); | 1085 __ PushObject(Object::ZoneHandle()); |
| 1086 __ PushObject(cls); | 1086 __ PushObject(cls); |
| 1087 __ pushq(type_arguments); | 1087 __ pushq(type_arguments); |
| 1088 __ pushq(instantiator_type_arguments); | 1088 __ pushq(instantiator_type_arguments); |
| 1089 compiler->GenerateCallRuntime(cid(), | 1089 compiler->GenerateCallRuntime(deopt_id(), |
| 1090 token_pos(), | 1090 token_pos(), |
| 1091 try_index(), | 1091 try_index(), |
| 1092 kAllocateObjectWithBoundsCheckRuntimeEntry); | 1092 kAllocateObjectWithBoundsCheckRuntimeEntry); |
| 1093 // Pop instantiator type arguments, type arguments, and class. | 1093 // Pop instantiator type arguments, type arguments, and class. |
| 1094 __ Drop(3); | 1094 __ Drop(3); |
| 1095 __ popq(result); // Pop new instance. | 1095 __ popq(result); // Pop new instance. |
| 1096 } | 1096 } |
| 1097 | 1097 |
| 1098 | 1098 |
| 1099 LocationSummary* LoadVMFieldComp::MakeLocationSummary() const { | 1099 LocationSummary* LoadVMFieldComp::MakeLocationSummary() const { |
| 1100 return LocationSummary::Make(1, | 1100 return LocationSummary::Make(1, |
| 1101 Location::RequiresRegister(), | 1101 Location::RequiresRegister(), |
| 1102 LocationSummary::kNoCall); | 1102 LocationSummary::kNoCall); |
| 1103 } | 1103 } |
| 1104 | 1104 |
| 1105 | 1105 |
| 1106 void LoadVMFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 1106 void LoadVMFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1107 Register instance_reg = locs()->in(0).reg(); | 1107 Register instance_reg = locs()->in(0).reg(); |
| 1108 Register result_reg = locs()->out().reg(); | 1108 Register result_reg = locs()->out().reg(); |
| 1109 if (HasICData()) { | 1109 if (HasICData()) { |
| 1110 ASSERT(original() != NULL); | 1110 ASSERT(original() != NULL); |
| 1111 Label* deopt = compiler->AddDeoptStub(original()->cid(), | 1111 Label* deopt = compiler->AddDeoptStub(original()->deopt_id(), |
| 1112 original()->token_pos(), | 1112 original()->token_pos(), |
| 1113 original()->try_index(), | 1113 original()->try_index(), |
| 1114 kDeoptInstanceGetterSameTarget, | 1114 kDeoptInstanceGetterSameTarget, |
| 1115 instance_reg); | 1115 instance_reg); |
| 1116 // Smis do not have instance fields (Smi class is always first). | 1116 // Smis do not have instance fields (Smi class is always first). |
| 1117 // Use 'result' as temporary register. | 1117 // Use 'result' as temporary register. |
| 1118 ASSERT(result_reg != instance_reg); | 1118 ASSERT(result_reg != instance_reg); |
| 1119 ASSERT(ic_data() != NULL); | 1119 ASSERT(ic_data() != NULL); |
| 1120 compiler->EmitClassChecksNoSmi(*ic_data(), instance_reg, result_reg, deopt); | 1120 compiler->EmitClassChecksNoSmi(*ic_data(), instance_reg, result_reg, deopt); |
| 1121 } | 1121 } |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1165 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); | 1165 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); |
| 1166 __ cmpq(FieldAddress(instantiator_reg, TypeArguments::length_offset()), | 1166 __ cmpq(FieldAddress(instantiator_reg, TypeArguments::length_offset()), |
| 1167 Immediate(Smi::RawValue(len))); | 1167 Immediate(Smi::RawValue(len))); |
| 1168 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 1168 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 1169 __ Bind(&type_arguments_uninstantiated); | 1169 __ Bind(&type_arguments_uninstantiated); |
| 1170 } | 1170 } |
| 1171 // A runtime call to instantiate the type arguments is required. | 1171 // A runtime call to instantiate the type arguments is required. |
| 1172 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1172 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1173 __ PushObject(type_arguments()); | 1173 __ PushObject(type_arguments()); |
| 1174 __ pushq(instantiator_reg); // Push instantiator type arguments. | 1174 __ pushq(instantiator_reg); // Push instantiator type arguments. |
| 1175 compiler->GenerateCallRuntime(cid(), | 1175 compiler->GenerateCallRuntime(deopt_id(), |
| 1176 token_pos(), | 1176 token_pos(), |
| 1177 try_index(), | 1177 try_index(), |
| 1178 kInstantiateTypeArgumentsRuntimeEntry); | 1178 kInstantiateTypeArgumentsRuntimeEntry); |
| 1179 __ Drop(2); // Drop instantiator and uninstantiated type arguments. | 1179 __ Drop(2); // Drop instantiator and uninstantiated type arguments. |
| 1180 __ popq(result_reg); // Pop instantiated type arguments. | 1180 __ popq(result_reg); // Pop instantiated type arguments. |
| 1181 __ Bind(&type_arguments_instantiated); | 1181 __ Bind(&type_arguments_instantiated); |
| 1182 ASSERT(instantiator_reg == result_reg); | 1182 ASSERT(instantiator_reg == result_reg); |
| 1183 // 'result_reg': Instantiated type arguments. | 1183 // 'result_reg': Instantiated type arguments. |
| 1184 } | 1184 } |
| 1185 | 1185 |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1341 return locs; | 1341 return locs; |
| 1342 } | 1342 } |
| 1343 | 1343 |
| 1344 | 1344 |
| 1345 void CloneContextComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 1345 void CloneContextComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1346 Register context_value = locs()->in(0).reg(); | 1346 Register context_value = locs()->in(0).reg(); |
| 1347 Register result = locs()->out().reg(); | 1347 Register result = locs()->out().reg(); |
| 1348 | 1348 |
| 1349 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1349 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1350 __ pushq(context_value); | 1350 __ pushq(context_value); |
| 1351 compiler->GenerateCallRuntime(cid(), | 1351 compiler->GenerateCallRuntime(deopt_id(), |
| 1352 token_pos(), | 1352 token_pos(), |
| 1353 try_index(), | 1353 try_index(), |
| 1354 kCloneContextRuntimeEntry); | 1354 kCloneContextRuntimeEntry); |
| 1355 __ popq(result); // Remove argument. | 1355 __ popq(result); // Remove argument. |
| 1356 __ popq(result); // Get result (cloned context). | 1356 __ popq(result); // Get result (cloned context). |
| 1357 } | 1357 } |
| 1358 | 1358 |
| 1359 | 1359 |
| 1360 LocationSummary* CatchEntryComp::MakeLocationSummary() const { | 1360 LocationSummary* CatchEntryComp::MakeLocationSummary() const { |
| 1361 return LocationSummary::Make(0, | 1361 return LocationSummary::Make(0, |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1397 } | 1397 } |
| 1398 | 1398 |
| 1399 | 1399 |
| 1400 void CheckStackOverflowComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 1400 void CheckStackOverflowComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1401 Register temp = locs()->temp(0).reg(); | 1401 Register temp = locs()->temp(0).reg(); |
| 1402 // Generate stack overflow check. | 1402 // Generate stack overflow check. |
| 1403 __ movq(temp, Immediate(Isolate::Current()->stack_limit_address())); | 1403 __ movq(temp, Immediate(Isolate::Current()->stack_limit_address())); |
| 1404 __ cmpq(RSP, Address(temp, 0)); | 1404 __ cmpq(RSP, Address(temp, 0)); |
| 1405 Label no_stack_overflow; | 1405 Label no_stack_overflow; |
| 1406 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump); | 1406 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump); |
| 1407 compiler->GenerateCallRuntime(cid(), | 1407 compiler->GenerateCallRuntime(deopt_id(), |
| 1408 token_pos(), | 1408 token_pos(), |
| 1409 try_index(), | 1409 try_index(), |
| 1410 kStackOverflowRuntimeEntry); | 1410 kStackOverflowRuntimeEntry); |
| 1411 __ Bind(&no_stack_overflow); | 1411 __ Bind(&no_stack_overflow); |
| 1412 } | 1412 } |
| 1413 | 1413 |
| 1414 | 1414 |
| 1415 LocationSummary* BinaryOpComp::MakeLocationSummary() const { | 1415 LocationSummary* BinaryOpComp::MakeLocationSummary() const { |
| 1416 const intptr_t kNumInputs = 2; | 1416 const intptr_t kNumInputs = 2; |
| 1417 | 1417 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1475 } | 1475 } |
| 1476 } | 1476 } |
| 1477 | 1477 |
| 1478 | 1478 |
| 1479 static void EmitSmiBinaryOp(FlowGraphCompiler* compiler, BinaryOpComp* comp) { | 1479 static void EmitSmiBinaryOp(FlowGraphCompiler* compiler, BinaryOpComp* comp) { |
| 1480 Register left = comp->locs()->in(0).reg(); | 1480 Register left = comp->locs()->in(0).reg(); |
| 1481 Register right = comp->locs()->in(1).reg(); | 1481 Register right = comp->locs()->in(1).reg(); |
| 1482 Register result = comp->locs()->out().reg(); | 1482 Register result = comp->locs()->out().reg(); |
| 1483 Register temp = comp->locs()->temp(0).reg(); | 1483 Register temp = comp->locs()->temp(0).reg(); |
| 1484 ASSERT(left == result); | 1484 ASSERT(left == result); |
| 1485 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->cid(), | 1485 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->deopt_id(), |
| 1486 comp->instance_call()->token_pos(), | 1486 comp->instance_call()->token_pos(), |
| 1487 comp->instance_call()->try_index(), | 1487 comp->instance_call()->try_index(), |
| 1488 kDeoptSmiBinaryOp, | 1488 kDeoptSmiBinaryOp, |
| 1489 temp, | 1489 temp, |
| 1490 right); | 1490 right); |
| 1491 // TODO(vegorov): for many binary operations this pattern can be rearranged | 1491 // TODO(vegorov): for many binary operations this pattern can be rearranged |
| 1492 // to save one move. | 1492 // to save one move. |
| 1493 __ movq(temp, left); | 1493 __ movq(temp, left); |
| 1494 __ orq(left, right); | 1494 __ orq(left, right); |
| 1495 __ testq(left, Immediate(kSmiTagMask)); | 1495 __ testq(left, Immediate(kSmiTagMask)); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1586 __ shlq(left, right_temp); | 1586 __ shlq(left, right_temp); |
| 1587 __ jmp(&done); | 1587 __ jmp(&done); |
| 1588 { | 1588 { |
| 1589 __ Bind(&call_method); | 1589 __ Bind(&call_method); |
| 1590 Function& target = Function::ZoneHandle( | 1590 Function& target = Function::ZoneHandle( |
| 1591 comp->ic_data()->GetTargetForReceiverClassId(kSmi)); | 1591 comp->ic_data()->GetTargetForReceiverClassId(kSmi)); |
| 1592 ASSERT(!target.IsNull()); | 1592 ASSERT(!target.IsNull()); |
| 1593 const intptr_t kArgumentCount = 2; | 1593 const intptr_t kArgumentCount = 2; |
| 1594 __ pushq(temp); | 1594 __ pushq(temp); |
| 1595 __ pushq(right); | 1595 __ pushq(right); |
| 1596 compiler->GenerateStaticCall(comp->instance_call()->cid(), | 1596 compiler->GenerateStaticCall(comp->instance_call()->deopt_id(), |
| 1597 comp->instance_call()->token_pos(), | 1597 comp->instance_call()->token_pos(), |
| 1598 comp->instance_call()->try_index(), | 1598 comp->instance_call()->try_index(), |
| 1599 target, | 1599 target, |
| 1600 kArgumentCount, | 1600 kArgumentCount, |
| 1601 Array::Handle()); // No argument names. | 1601 Array::Handle()); // No argument names. |
| 1602 ASSERT(result == RAX); | 1602 ASSERT(result == RAX); |
| 1603 } | 1603 } |
| 1604 __ Bind(&done); | 1604 __ Bind(&done); |
| 1605 break; | 1605 break; |
| 1606 } | 1606 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1632 static void EmitMintBinaryOp(FlowGraphCompiler* compiler, BinaryOpComp* comp) { | 1632 static void EmitMintBinaryOp(FlowGraphCompiler* compiler, BinaryOpComp* comp) { |
| 1633 // TODO(regis): For now, we only support Token::kBIT_AND for a Mint or Smi | 1633 // TODO(regis): For now, we only support Token::kBIT_AND for a Mint or Smi |
| 1634 // receiver and a Mint or Smi argument. We fall back to the run time call if | 1634 // receiver and a Mint or Smi argument. We fall back to the run time call if |
| 1635 // both receiver and argument are Mint or if one of them is Mint and the other | 1635 // both receiver and argument are Mint or if one of them is Mint and the other |
| 1636 // is a negative Smi. | 1636 // is a negative Smi. |
| 1637 Register left = comp->locs()->in(0).reg(); | 1637 Register left = comp->locs()->in(0).reg(); |
| 1638 Register right = comp->locs()->in(1).reg(); | 1638 Register right = comp->locs()->in(1).reg(); |
| 1639 Register result = comp->locs()->out().reg(); | 1639 Register result = comp->locs()->out().reg(); |
| 1640 ASSERT(left == result); | 1640 ASSERT(left == result); |
| 1641 ASSERT(comp->op_kind() == Token::kBIT_AND); | 1641 ASSERT(comp->op_kind() == Token::kBIT_AND); |
| 1642 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->cid(), | 1642 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->deopt_id(), |
| 1643 comp->instance_call()->token_pos(), | 1643 comp->instance_call()->token_pos(), |
| 1644 comp->instance_call()->try_index(), | 1644 comp->instance_call()->try_index(), |
| 1645 kDeoptMintBinaryOp, | 1645 kDeoptMintBinaryOp, |
| 1646 left, | 1646 left, |
| 1647 right); | 1647 right); |
| 1648 Label mint_static_call, smi_static_call, non_smi, smi_smi, done; | 1648 Label mint_static_call, smi_static_call, non_smi, smi_smi, done; |
| 1649 __ testq(left, Immediate(kSmiTagMask)); // Is receiver Smi? | 1649 __ testq(left, Immediate(kSmiTagMask)); // Is receiver Smi? |
| 1650 __ j(NOT_ZERO, &non_smi); | 1650 __ j(NOT_ZERO, &non_smi); |
| 1651 __ testq(right, Immediate(kSmiTagMask)); // Is argument Smi? | 1651 __ testq(right, Immediate(kSmiTagMask)); // Is argument Smi? |
| 1652 __ j(ZERO, &smi_smi); | 1652 __ j(ZERO, &smi_smi); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1680 | 1680 |
| 1681 __ Bind(&smi_static_call); | 1681 __ Bind(&smi_static_call); |
| 1682 { | 1682 { |
| 1683 Function& target = Function::ZoneHandle( | 1683 Function& target = Function::ZoneHandle( |
| 1684 comp->ic_data()->GetTargetForReceiverClassId(kSmi)); | 1684 comp->ic_data()->GetTargetForReceiverClassId(kSmi)); |
| 1685 if (target.IsNull()) { | 1685 if (target.IsNull()) { |
| 1686 __ jmp(deopt); | 1686 __ jmp(deopt); |
| 1687 } else { | 1687 } else { |
| 1688 __ pushq(left); | 1688 __ pushq(left); |
| 1689 __ pushq(right); | 1689 __ pushq(right); |
| 1690 compiler->GenerateStaticCall(comp->instance_call()->cid(), | 1690 compiler->GenerateStaticCall(comp->instance_call()->deopt_id(), |
| 1691 comp->instance_call()->token_pos(), | 1691 comp->instance_call()->token_pos(), |
| 1692 comp->instance_call()->try_index(), | 1692 comp->instance_call()->try_index(), |
| 1693 target, | 1693 target, |
| 1694 comp->instance_call()->ArgumentCount(), | 1694 comp->instance_call()->ArgumentCount(), |
| 1695 comp->instance_call()->argument_names()); | 1695 comp->instance_call()->argument_names()); |
| 1696 ASSERT(result == RAX); | 1696 ASSERT(result == RAX); |
| 1697 __ jmp(&done); | 1697 __ jmp(&done); |
| 1698 } | 1698 } |
| 1699 } | 1699 } |
| 1700 | 1700 |
| 1701 __ Bind(&mint_static_call); | 1701 __ Bind(&mint_static_call); |
| 1702 { | 1702 { |
| 1703 Function& target = Function::ZoneHandle( | 1703 Function& target = Function::ZoneHandle( |
| 1704 comp->ic_data()->GetTargetForReceiverClassId(kMint)); | 1704 comp->ic_data()->GetTargetForReceiverClassId(kMint)); |
| 1705 if (target.IsNull()) { | 1705 if (target.IsNull()) { |
| 1706 __ jmp(deopt); | 1706 __ jmp(deopt); |
| 1707 } else { | 1707 } else { |
| 1708 __ pushq(left); | 1708 __ pushq(left); |
| 1709 __ pushq(right); | 1709 __ pushq(right); |
| 1710 compiler->GenerateStaticCall(comp->instance_call()->cid(), | 1710 compiler->GenerateStaticCall(comp->instance_call()->deopt_id(), |
| 1711 comp->instance_call()->token_pos(), | 1711 comp->instance_call()->token_pos(), |
| 1712 comp->instance_call()->try_index(), | 1712 comp->instance_call()->try_index(), |
| 1713 target, | 1713 target, |
| 1714 comp->instance_call()->ArgumentCount(), | 1714 comp->instance_call()->ArgumentCount(), |
| 1715 comp->instance_call()->argument_names()); | 1715 comp->instance_call()->argument_names()); |
| 1716 ASSERT(result == RAX); | 1716 ASSERT(result == RAX); |
| 1717 } | 1717 } |
| 1718 } | 1718 } |
| 1719 __ Bind(&done); | 1719 __ Bind(&done); |
| 1720 } | 1720 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1753 const ExternalLabel label(double_class.ToCString(), stub.EntryPoint()); | 1753 const ExternalLabel label(double_class.ToCString(), stub.EntryPoint()); |
| 1754 compiler->GenerateCall(instance_call()->token_pos(), | 1754 compiler->GenerateCall(instance_call()->token_pos(), |
| 1755 instance_call()->try_index(), | 1755 instance_call()->try_index(), |
| 1756 &label, | 1756 &label, |
| 1757 PcDescriptors::kOther); | 1757 PcDescriptors::kOther); |
| 1758 // Newly allocated object is now in the result register (RAX). | 1758 // Newly allocated object is now in the result register (RAX). |
| 1759 ASSERT(result == RAX); | 1759 ASSERT(result == RAX); |
| 1760 __ popq(right); | 1760 __ popq(right); |
| 1761 __ popq(left); | 1761 __ popq(left); |
| 1762 | 1762 |
| 1763 Label* deopt = compiler->AddDeoptStub(instance_call()->cid(), | 1763 Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(), |
| 1764 instance_call()->token_pos(), | 1764 instance_call()->token_pos(), |
| 1765 instance_call()->try_index(), | 1765 instance_call()->try_index(), |
| 1766 kDeoptDoubleBinaryOp, | 1766 kDeoptDoubleBinaryOp, |
| 1767 left, | 1767 left, |
| 1768 right); | 1768 right); |
| 1769 | 1769 |
| 1770 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); | 1770 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); |
| 1771 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); | 1771 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); |
| 1772 | 1772 |
| 1773 switch (op_kind()) { | 1773 switch (op_kind()) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1799 ASSERT(ic_data.num_args_tested() == 1); | 1799 ASSERT(ic_data.num_args_tested() == 1); |
| 1800 // TODO(srdjan): Implement for more checks. | 1800 // TODO(srdjan): Implement for more checks. |
| 1801 ASSERT(ic_data.NumberOfChecks() == 1); | 1801 ASSERT(ic_data.NumberOfChecks() == 1); |
| 1802 intptr_t test_class_id; | 1802 intptr_t test_class_id; |
| 1803 Function& target = Function::Handle(); | 1803 Function& target = Function::Handle(); |
| 1804 ic_data.GetOneClassCheckAt(0, &test_class_id, &target); | 1804 ic_data.GetOneClassCheckAt(0, &test_class_id, &target); |
| 1805 | 1805 |
| 1806 Register value = locs()->in(0).reg(); | 1806 Register value = locs()->in(0).reg(); |
| 1807 Register result = locs()->out().reg(); | 1807 Register result = locs()->out().reg(); |
| 1808 ASSERT(value == result); | 1808 ASSERT(value == result); |
| 1809 Label* deopt = compiler->AddDeoptStub(instance_call()->cid(), | 1809 Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(), |
| 1810 instance_call()->token_pos(), | 1810 instance_call()->token_pos(), |
| 1811 instance_call()->try_index(), | 1811 instance_call()->try_index(), |
| 1812 kDeoptUnaryOp, | 1812 kDeoptUnaryOp, |
| 1813 value); | 1813 value); |
| 1814 if (test_class_id == kSmi) { | 1814 if (test_class_id == kSmi) { |
| 1815 __ testq(value, Immediate(kSmiTagMask)); | 1815 __ testq(value, Immediate(kSmiTagMask)); |
| 1816 __ j(NOT_ZERO, deopt); | 1816 __ j(NOT_ZERO, deopt); |
| 1817 switch (op_kind()) { | 1817 switch (op_kind()) { |
| 1818 case Token::kNEGATE: | 1818 case Token::kNEGATE: |
| 1819 __ negq(value); | 1819 __ negq(value); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1851 | 1851 |
| 1852 // TODO(srdjan): Implement for more checks. | 1852 // TODO(srdjan): Implement for more checks. |
| 1853 ASSERT(ic_data.NumberOfChecks() == 1); | 1853 ASSERT(ic_data.NumberOfChecks() == 1); |
| 1854 intptr_t test_class_id; | 1854 intptr_t test_class_id; |
| 1855 Function& target = Function::Handle(); | 1855 Function& target = Function::Handle(); |
| 1856 ic_data.GetOneClassCheckAt(0, &test_class_id, &target); | 1856 ic_data.GetOneClassCheckAt(0, &test_class_id, &target); |
| 1857 | 1857 |
| 1858 Register value = locs()->in(0).reg(); | 1858 Register value = locs()->in(0).reg(); |
| 1859 Register result = locs()->out().reg(); | 1859 Register result = locs()->out().reg(); |
| 1860 ASSERT(value == result); | 1860 ASSERT(value == result); |
| 1861 Label* deopt = compiler->AddDeoptStub(instance_call()->cid(), | 1861 Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(), |
| 1862 instance_call()->token_pos(), | 1862 instance_call()->token_pos(), |
| 1863 instance_call()->try_index(), | 1863 instance_call()->try_index(), |
| 1864 kDeoptUnaryOp, | 1864 kDeoptUnaryOp, |
| 1865 value); | 1865 value); |
| 1866 if (test_class_id == kDouble) { | 1866 if (test_class_id == kDouble) { |
| 1867 Register temp = locs()->temp(0).reg(); | 1867 Register temp = locs()->temp(0).reg(); |
| 1868 __ testq(value, Immediate(kSmiTagMask)); | 1868 __ testq(value, Immediate(kSmiTagMask)); |
| 1869 __ j(ZERO, deopt); // Smi. | 1869 __ j(ZERO, deopt); // Smi. |
| 1870 __ CompareClassId(value, kDouble); | 1870 __ CompareClassId(value, kDouble); |
| 1871 __ j(NOT_EQUAL, deopt); | 1871 __ j(NOT_EQUAL, deopt); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1907 } | 1907 } |
| 1908 } | 1908 } |
| 1909 | 1909 |
| 1910 | 1910 |
| 1911 void ToDoubleComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 1911 void ToDoubleComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1912 Register value = (from() == kDouble) ? locs()->in(0).reg() : RBX; | 1912 Register value = (from() == kDouble) ? locs()->in(0).reg() : RBX; |
| 1913 Register result = locs()->out().reg(); | 1913 Register result = locs()->out().reg(); |
| 1914 | 1914 |
| 1915 const DeoptReasonId deopt_reason = (from() == kDouble) ? | 1915 const DeoptReasonId deopt_reason = (from() == kDouble) ? |
| 1916 kDeoptDoubleToDouble : kDeoptIntegerToDouble; | 1916 kDeoptDoubleToDouble : kDeoptIntegerToDouble; |
| 1917 Label* deopt = compiler->AddDeoptStub(instance_call()->cid(), | 1917 Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(), |
| 1918 instance_call()->token_pos(), | 1918 instance_call()->token_pos(), |
| 1919 instance_call()->try_index(), | 1919 instance_call()->try_index(), |
| 1920 deopt_reason, | 1920 deopt_reason, |
| 1921 value); | 1921 value); |
| 1922 | 1922 |
| 1923 if (from() == kDouble) { | 1923 if (from() == kDouble) { |
| 1924 __ testq(value, Immediate(kSmiTagMask)); | 1924 __ testq(value, Immediate(kSmiTagMask)); |
| 1925 __ j(ZERO, deopt); // Deoptimize if Smi. | 1925 __ j(ZERO, deopt); // Deoptimize if Smi. |
| 1926 __ CompareClassId(value, kDouble); | 1926 __ CompareClassId(value, kDouble); |
| 1927 __ j(NOT_EQUAL, deopt); // Deoptimize if not Double. | 1927 __ j(NOT_EQUAL, deopt); // Deoptimize if not Double. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1951 __ movsd(FieldAddress(result, Double::value_offset()), XMM0); | 1951 __ movsd(FieldAddress(result, Double::value_offset()), XMM0); |
| 1952 } | 1952 } |
| 1953 | 1953 |
| 1954 | 1954 |
| 1955 LocationSummary* PolymorphicInstanceCallComp::MakeLocationSummary() const { | 1955 LocationSummary* PolymorphicInstanceCallComp::MakeLocationSummary() const { |
| 1956 return MakeCallSummary(); | 1956 return MakeCallSummary(); |
| 1957 } | 1957 } |
| 1958 | 1958 |
| 1959 | 1959 |
| 1960 void PolymorphicInstanceCallComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 1960 void PolymorphicInstanceCallComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1961 Label* deopt = compiler->AddDeoptStub(instance_call()->cid(), | 1961 Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(), |
| 1962 instance_call()->token_pos(), | 1962 instance_call()->token_pos(), |
| 1963 instance_call()->try_index(), | 1963 instance_call()->try_index(), |
| 1964 kDeoptPolymorphicInstanceCallTestFail); | 1964 kDeoptPolymorphicInstanceCallTestFail); |
| 1965 if (!HasICData() || (ic_data()->NumberOfChecks() == 0)) { | 1965 if (!HasICData() || (ic_data()->NumberOfChecks() == 0)) { |
| 1966 __ jmp(deopt); | 1966 __ jmp(deopt); |
| 1967 return; | 1967 return; |
| 1968 } | 1968 } |
| 1969 ASSERT(HasICData()); | 1969 ASSERT(HasICData()); |
| 1970 ASSERT(ic_data()->num_args_tested() == 1); | 1970 ASSERT(ic_data()->num_args_tested() == 1); |
| 1971 Label handle_smi; | 1971 Label handle_smi; |
| 1972 Label* is_smi_label = | 1972 Label* is_smi_label = |
| 1973 ic_data()->GetReceiverClassIdAt(0) == kSmi ? &handle_smi : deopt; | 1973 ic_data()->GetReceiverClassIdAt(0) == kSmi ? &handle_smi : deopt; |
| 1974 | 1974 |
| 1975 // Load receiver into RAX. | 1975 // Load receiver into RAX. |
| 1976 __ movq(RAX, | 1976 __ movq(RAX, |
| 1977 Address(RSP, (instance_call()->ArgumentCount() - 1) * kWordSize)); | 1977 Address(RSP, (instance_call()->ArgumentCount() - 1) * kWordSize)); |
| 1978 __ testq(RAX, Immediate(kSmiTagMask)); | 1978 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1979 __ j(ZERO, is_smi_label); | 1979 __ j(ZERO, is_smi_label); |
| 1980 Label done; | 1980 Label done; |
| 1981 __ LoadClassId(RDI, RAX); | 1981 __ LoadClassId(RDI, RAX); |
| 1982 compiler->EmitTestAndCall(*ic_data(), | 1982 compiler->EmitTestAndCall(*ic_data(), |
| 1983 RDI, // Class id register. | 1983 RDI, // Class id register. |
| 1984 instance_call()->ArgumentCount(), | 1984 instance_call()->ArgumentCount(), |
| 1985 instance_call()->argument_names(), | 1985 instance_call()->argument_names(), |
| 1986 deopt, | 1986 deopt, |
| 1987 (is_smi_label == &handle_smi) ? &done : NULL, | 1987 (is_smi_label == &handle_smi) ? &done : NULL, |
| 1988 instance_call()->cid(), | 1988 instance_call()->deopt_id(), |
| 1989 instance_call()->token_pos(), | 1989 instance_call()->token_pos(), |
| 1990 instance_call()->try_index()); | 1990 instance_call()->try_index()); |
| 1991 if (is_smi_label == &handle_smi) { | 1991 if (is_smi_label == &handle_smi) { |
| 1992 __ Bind(&handle_smi); | 1992 __ Bind(&handle_smi); |
| 1993 ASSERT(ic_data()->GetReceiverClassIdAt(0) == kSmi); | 1993 ASSERT(ic_data()->GetReceiverClassIdAt(0) == kSmi); |
| 1994 const Function& target = Function::ZoneHandle(ic_data()->GetTargetAt(0)); | 1994 const Function& target = Function::ZoneHandle(ic_data()->GetTargetAt(0)); |
| 1995 compiler->GenerateStaticCall(instance_call()->cid(), | 1995 compiler->GenerateStaticCall(instance_call()->deopt_id(), |
| 1996 instance_call()->token_pos(), | 1996 instance_call()->token_pos(), |
| 1997 instance_call()->try_index(), | 1997 instance_call()->try_index(), |
| 1998 target, | 1998 target, |
| 1999 instance_call()->ArgumentCount(), | 1999 instance_call()->ArgumentCount(), |
| 2000 instance_call()->argument_names()); | 2000 instance_call()->argument_names()); |
| 2001 } | 2001 } |
| 2002 __ Bind(&done); | 2002 __ Bind(&done); |
| 2003 } | 2003 } |
| 2004 | 2004 |
| 2005 | 2005 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2059 Register right = locs()->in(1).reg(); | 2059 Register right = locs()->in(1).reg(); |
| 2060 __ cmpq(left, right); | 2060 __ cmpq(left, right); |
| 2061 Condition cond = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL; | 2061 Condition cond = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL; |
| 2062 EmitBranchOnCondition(compiler, cond); | 2062 EmitBranchOnCondition(compiler, cond); |
| 2063 return; | 2063 return; |
| 2064 } | 2064 } |
| 2065 // Relational or equality. | 2065 // Relational or equality. |
| 2066 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 2066 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 2067 if (ICDataWithBothClassIds(*ic_data(), kSmi)) { | 2067 if (ICDataWithBothClassIds(*ic_data(), kSmi)) { |
| 2068 EmitSmiComparisonOp(compiler, *locs(), kind(), this, | 2068 EmitSmiComparisonOp(compiler, *locs(), kind(), this, |
| 2069 cid(), token_pos(), try_index()); | 2069 deopt_id(), token_pos(), try_index()); |
| 2070 return; | 2070 return; |
| 2071 } | 2071 } |
| 2072 if (ICDataWithBothClassIds(*ic_data(), kDouble)) { | 2072 if (ICDataWithBothClassIds(*ic_data(), kDouble)) { |
| 2073 EmitDoubleComparisonOp(compiler, *locs(), kind(), this, | 2073 EmitDoubleComparisonOp(compiler, *locs(), kind(), this, |
| 2074 cid(), token_pos(), try_index()); | 2074 deopt_id(), token_pos(), try_index()); |
| 2075 return; | 2075 return; |
| 2076 } | 2076 } |
| 2077 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons. | 2077 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons. |
| 2078 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { | 2078 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { |
| 2079 EmitGenericEqualityCompare(compiler, *locs(), kind(), this, *ic_data(), | 2079 EmitGenericEqualityCompare(compiler, *locs(), kind(), this, *ic_data(), |
| 2080 cid(), token_pos(), try_index()); | 2080 deopt_id(), token_pos(), try_index()); |
| 2081 return; | 2081 return; |
| 2082 } | 2082 } |
| 2083 // Otherwise polymorphic dispatch? | 2083 // Otherwise polymorphic dispatch? |
| 2084 } | 2084 } |
| 2085 // Not equal is always split into '==' and negate, | 2085 // Not equal is always split into '==' and negate, |
| 2086 Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL; | 2086 Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL; |
| 2087 Token::Kind call_kind = (kind() == Token::kNE) ? Token::kEQ : kind(); | 2087 Token::Kind call_kind = (kind() == Token::kNE) ? Token::kEQ : kind(); |
| 2088 const String& function_name = | 2088 const String& function_name = |
| 2089 String::ZoneHandle(Symbols::New(Token::Str(call_kind))); | 2089 String::ZoneHandle(Symbols::New(Token::Str(call_kind))); |
| 2090 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 2090 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 2091 cid(), | 2091 deopt_id(), |
| 2092 token_pos(), | 2092 token_pos(), |
| 2093 try_index()); | 2093 try_index()); |
| 2094 const intptr_t kNumArguments = 2; | 2094 const intptr_t kNumArguments = 2; |
| 2095 const intptr_t kNumArgsChecked = 2; // Type-feedback. | 2095 const intptr_t kNumArgsChecked = 2; // Type-feedback. |
| 2096 compiler->GenerateInstanceCall(cid(), | 2096 compiler->GenerateInstanceCall(deopt_id(), |
| 2097 token_pos(), | 2097 token_pos(), |
| 2098 try_index(), | 2098 try_index(), |
| 2099 function_name, | 2099 function_name, |
| 2100 kNumArguments, | 2100 kNumArguments, |
| 2101 Array::ZoneHandle(), // No optional arguments. | 2101 Array::ZoneHandle(), // No optional arguments. |
| 2102 kNumArgsChecked); | 2102 kNumArgsChecked); |
| 2103 ASSERT(locs()->out().reg() == RAX); | 2103 ASSERT(locs()->out().reg() == RAX); |
| 2104 __ CompareObject(locs()->out().reg(), compiler->bool_true()); | 2104 __ CompareObject(locs()->out().reg(), compiler->bool_true()); |
| 2105 EmitBranchOnCondition(compiler, branch_condition); | 2105 EmitBranchOnCondition(compiler, branch_condition); |
| 2106 } | 2106 } |
| 2107 | 2107 |
| 2108 } // namespace dart | 2108 } // namespace dart |
| 2109 | 2109 |
| 2110 #undef __ | 2110 #undef __ |
| 2111 | 2111 |
| 2112 #endif // defined TARGET_ARCH_X64 | 2112 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |