| 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 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 // We should never return here. | 183 // We should never return here. |
| 184 __ int3(); | 184 __ int3(); |
| 185 | 185 |
| 186 __ Bind(&done); | 186 __ Bind(&done); |
| 187 ASSERT(obj == result); | 187 ASSERT(obj == result); |
| 188 } | 188 } |
| 189 | 189 |
| 190 | 190 |
| 191 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { | 191 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { |
| 192 const intptr_t kNumInputs = 2; | 192 const intptr_t kNumInputs = 2; |
| 193 if (operands_class_id() == kSmi) { | 193 if ((NumTargets() == 1) && (ClassIdAt(0) == kSmi)) { |
| 194 const intptr_t kNumTemps = 1; | 194 const intptr_t kNumTemps = 1; |
| 195 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); | 195 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); |
| 196 locs->set_in(0, Location::RequiresRegister()); | 196 locs->set_in(0, Location::RequiresRegister()); |
| 197 locs->set_in(1, Location::RequiresRegister()); | 197 locs->set_in(1, Location::RequiresRegister()); |
| 198 locs->set_temp(0, Location::RequiresRegister()); | 198 locs->set_temp(0, Location::RequiresRegister()); |
| 199 if (!is_fused_with_branch()) { | 199 if (!is_fused_with_branch()) { |
| 200 locs->set_out(Location::RequiresRegister()); | 200 locs->set_out(Location::RequiresRegister()); |
| 201 } | 201 } |
| 202 return locs; | 202 return locs; |
| 203 } | 203 } |
| 204 if (operands_class_id() == kObject) { | 204 if (NumTargets() > 0) { |
| 205 const intptr_t kNumTemps = 0; | 205 const intptr_t kNumTemps = 1; |
| 206 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); | 206 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); |
| 207 locs->set_in(0, Location::RequiresRegister()); | 207 locs->set_in(0, Location::RequiresRegister()); |
| 208 locs->set_in(1, Location::RequiresRegister()); | 208 locs->set_in(1, Location::RequiresRegister()); |
| 209 locs->set_temp(0, Location::RequiresRegister()); |
| 209 if (!is_fused_with_branch()) { | 210 if (!is_fused_with_branch()) { |
| 210 locs->set_out(Location::RegisterLocation(EAX)); | 211 locs->set_out(Location::RegisterLocation(EAX)); |
| 211 } | 212 } |
| 212 return locs; | 213 return locs; |
| 213 } | 214 } |
| 214 UNREACHABLE(); | 215 const intptr_t kNumTemps = 0; |
| 215 return NULL; | 216 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); |
| 217 locs->set_in(0, Location::RequiresRegister()); |
| 218 locs->set_in(1, Location::RequiresRegister()); |
| 219 if (!is_fused_with_branch()) { |
| 220 locs->set_out(Location::RegisterLocation(EAX)); |
| 221 } |
| 222 return locs; |
| 216 } | 223 } |
| 217 | 224 |
| 218 | 225 |
| 219 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, | 226 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, |
| 220 EqualityCompareComp* comp) { | 227 EqualityCompareComp* comp) { |
| 221 Register left = comp->locs()->in(0).reg(); | 228 Register left = comp->locs()->in(0).reg(); |
| 222 Register right = comp->locs()->in(1).reg(); | 229 Register right = comp->locs()->in(1).reg(); |
| 223 Register temp = comp->locs()->temp(0).reg(); | 230 Register temp = comp->locs()->temp(0).reg(); |
| 224 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 231 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 225 comp->token_index(), | 232 comp->token_index(), |
| (...skipping 15 matching lines...) Expand all Loading... |
| 241 __ j(EQUAL, &load_true, Assembler::kNearJump); | 248 __ j(EQUAL, &load_true, Assembler::kNearJump); |
| 242 __ LoadObject(result, compiler->bool_false()); | 249 __ LoadObject(result, compiler->bool_false()); |
| 243 __ jmp(&done, Assembler::kNearJump); | 250 __ jmp(&done, Assembler::kNearJump); |
| 244 __ Bind(&load_true); | 251 __ Bind(&load_true); |
| 245 __ LoadObject(result, compiler->bool_true()); | 252 __ LoadObject(result, compiler->bool_true()); |
| 246 __ Bind(&done); | 253 __ Bind(&done); |
| 247 } | 254 } |
| 248 } | 255 } |
| 249 | 256 |
| 250 | 257 |
| 258 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, |
| 259 EqualityCompareComp* comp) { |
| 260 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 261 comp->cid(), |
| 262 comp->token_index(), |
| 263 comp->try_index()); |
| 264 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); |
| 265 const int kNumberOfArguments = 2; |
| 266 const Array& kNoArgumentNames = Array::Handle(); |
| 267 const int kNumArgumentsChecked = 2; |
| 268 |
| 269 compiler->GenerateInstanceCall(comp->cid(), |
| 270 comp->token_index(), |
| 271 comp->try_index(), |
| 272 operator_name, |
| 273 kNumberOfArguments, |
| 274 kNoArgumentNames, |
| 275 kNumArgumentsChecked); |
| 276 ASSERT(comp->is_fused_with_branch() || (comp->locs()->out().reg() == EAX)); |
| 277 |
| 278 if (comp->is_fused_with_branch()) { |
| 279 __ CompareObject(EAX, compiler->bool_true()); |
| 280 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); |
| 281 } |
| 282 } |
| 283 |
| 284 |
| 285 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, |
| 286 EqualityCompareComp* comp, |
| 287 Register left, |
| 288 Register right) { |
| 289 ASSERT(comp->NumTargets() > 0); |
| 290 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 291 comp->token_index(), |
| 292 comp->try_index(), |
| 293 kDeoptEquality); |
| 294 __ testl(left, Immediate(kSmiTagMask)); |
| 295 Register temp = comp->locs()->temp(0).reg(); |
| 296 if (comp->ClassIdAt(0) == kSmi) { |
| 297 Label done, load_class_id; |
| 298 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump); |
| 299 __ movl(temp, Immediate(kSmi)); |
| 300 __ jmp(&done, Assembler::kNearJump); |
| 301 __ Bind(&load_class_id); |
| 302 __ LoadClassId(temp, left); |
| 303 __ Bind(&done); |
| 304 } else { |
| 305 __ j(ZERO, deopt); // Smi deopts. |
| 306 __ LoadClassId(temp, left); |
| 307 } |
| 308 Label done; |
| 309 for (intptr_t i = 0; i < comp->NumTargets(); i++) { |
| 310 ASSERT((comp->ClassIdAt(i) != kSmi) || (i == 0)); |
| 311 Label next_test; |
| 312 __ cmpl(temp, Immediate(comp->ClassIdAt(i))); |
| 313 __ j(NOT_EQUAL, &next_test, Assembler::kNearJump); |
| 314 const Function& target = *comp->TargetAt(i); |
| 315 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 316 if (target.owner() == object_store->object_class()) { |
| 317 // Object.== is same as ===. |
| 318 __ Drop(2); |
| 319 __ cmpl(left, right); |
| 320 if (comp->is_fused_with_branch()) { |
| 321 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); |
| 322 } else { |
| 323 // This case should be rare. |
| 324 Register result = comp->locs()->out().reg(); |
| 325 Label load_true; |
| 326 __ j(EQUAL, &load_true, Assembler::kNearJump); |
| 327 __ LoadObject(result, compiler->bool_false()); |
| 328 __ jmp(&done); |
| 329 __ Bind(&load_true); |
| 330 __ LoadObject(result, compiler->bool_true()); |
| 331 } |
| 332 } else { |
| 333 const int kNumberOfArguments = 2; |
| 334 const Array& kNoArgumentNames = Array::Handle(); |
| 335 compiler->GenerateStaticCall(comp->cid(), |
| 336 comp->token_index(), |
| 337 comp->try_index(), |
| 338 target, |
| 339 kNumberOfArguments, |
| 340 kNoArgumentNames); |
| 341 ASSERT(comp->is_fused_with_branch() || |
| 342 (comp->locs()->out().reg() == EAX)); |
| 343 if (comp->is_fused_with_branch()) { |
| 344 __ CompareObject(EAX, compiler->bool_true()); |
| 345 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); |
| 346 } |
| 347 } |
| 348 __ jmp(&done); |
| 349 __ Bind(&next_test); |
| 350 } |
| 351 // Fall through leads to deoptimization |
| 352 __ jmp(deopt); |
| 353 __ Bind(&done); |
| 354 } |
| 355 |
| 356 |
| 357 // First test if receiver is NULL, in which case === is applied. |
| 358 // If type feedback was provided (lists of <class-id, target>), do a |
| 359 // type by type check (either === or static call to the operator. |
| 251 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, | 360 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, |
| 252 EqualityCompareComp* comp) { | 361 EqualityCompareComp* comp) { |
| 253 Register left = comp->locs()->in(0).reg(); | 362 Register left = comp->locs()->in(0).reg(); |
| 254 Register right = comp->locs()->in(1).reg(); | 363 Register right = comp->locs()->in(1).reg(); |
| 255 const Immediate raw_null = | 364 const Immediate raw_null = |
| 256 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 365 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 257 Label done, non_null_compare; | 366 Label done, non_null_compare; |
| 258 __ cmpl(left, raw_null); | 367 __ cmpl(left, raw_null); |
| 259 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); | 368 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); |
| 260 // Comparison with NULL is "===". | 369 // Comparison with NULL is "===". |
| 261 __ cmpl(left, right); | 370 __ cmpl(left, right); |
| 262 if (comp->is_fused_with_branch()) { | 371 if (comp->is_fused_with_branch()) { |
| 263 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | 372 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); |
| 264 } else { | 373 } else { |
| 265 Register result = comp->locs()->out().reg(); | 374 Register result = comp->locs()->out().reg(); |
| 266 Label load_true; | 375 Label load_true; |
| 267 __ j(EQUAL, &load_true, Assembler::kNearJump); | 376 __ j(EQUAL, &load_true, Assembler::kNearJump); |
| 268 __ LoadObject(result, compiler->bool_false()); | 377 __ LoadObject(result, compiler->bool_false()); |
| 269 __ jmp(&done, Assembler::kNearJump); | 378 __ jmp(&done); |
| 270 __ Bind(&load_true); | 379 __ Bind(&load_true); |
| 271 __ LoadObject(result, compiler->bool_true()); | 380 __ LoadObject(result, compiler->bool_true()); |
| 272 } | 381 } |
| 273 __ jmp(&done); | 382 __ jmp(&done); |
| 274 | 383 |
| 275 __ Bind(&non_null_compare); | 384 __ Bind(&non_null_compare); // Receiver is not null. |
| 276 __ pushl(left); | 385 __ pushl(left); |
| 277 __ pushl(right); | 386 __ pushl(right); |
| 278 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 387 if (comp->NumTargets() > 0) { |
| 279 comp->cid(), | 388 EmitEqualityAsPolymorphicCall(compiler, comp, left, right); |
| 280 comp->token_index(), | 389 } else { |
| 281 comp->try_index()); | 390 EmitEqualityAsInstanceCall(compiler, comp); |
| 282 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); | |
| 283 const int kNumberOfArguments = 2; | |
| 284 const Array& kNoArgumentNames = Array::Handle(); | |
| 285 const int kNumArgumentsChecked = 2; | |
| 286 | |
| 287 compiler->GenerateInstanceCall(comp->cid(), | |
| 288 comp->token_index(), | |
| 289 comp->try_index(), | |
| 290 operator_name, | |
| 291 kNumberOfArguments, | |
| 292 kNoArgumentNames, | |
| 293 kNumArgumentsChecked); | |
| 294 ASSERT(comp->is_fused_with_branch() || (comp->locs()->out().reg() == EAX)); | |
| 295 | |
| 296 if (comp->is_fused_with_branch()) { | |
| 297 __ CompareObject(EAX, compiler->bool_true()); | |
| 298 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | |
| 299 } | 391 } |
| 300 __ Bind(&done); | 392 __ Bind(&done); |
| 301 } | 393 } |
| 302 | 394 |
| 303 | 395 |
| 304 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 396 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 305 if (operands_class_id() == kSmi) { | 397 if ((NumTargets() == 1) && (ClassIdAt(0) == kSmi)) { |
| 306 EmitSmiEqualityCompare(compiler, this); | 398 EmitSmiEqualityCompare(compiler, this); |
| 307 return; | 399 return; |
| 308 } | 400 } |
| 309 if (operands_class_id() == kObject) { | 401 EmitGenericEqualityCompare(compiler, this); |
| 310 EmitGenericEqualityCompare(compiler, this); | |
| 311 return; | |
| 312 } | |
| 313 UNREACHABLE(); | |
| 314 } | 402 } |
| 315 | 403 |
| 316 | 404 |
| 317 LocationSummary* RelationalOpComp::MakeLocationSummary() const { | 405 LocationSummary* RelationalOpComp::MakeLocationSummary() const { |
| 318 if ((operands_class_id() == kSmi) || (operands_class_id() == kDouble)) { | 406 if ((operands_class_id() == kSmi) || (operands_class_id() == kDouble)) { |
| 319 const intptr_t kNumInputs = 2; | 407 const intptr_t kNumInputs = 2; |
| 320 const intptr_t kNumTemps = 1; | 408 const intptr_t kNumTemps = 1; |
| 321 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | 409 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 322 summary->set_in(0, Location::RequiresRegister()); | 410 summary->set_in(0, Location::RequiresRegister()); |
| 323 summary->set_in(1, Location::RequiresRegister()); | 411 summary->set_in(1, Location::RequiresRegister()); |
| (...skipping 1308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1632 } | 1720 } |
| 1633 __ Bind(&done); | 1721 __ Bind(&done); |
| 1634 } | 1722 } |
| 1635 | 1723 |
| 1636 | 1724 |
| 1637 } // namespace dart | 1725 } // namespace dart |
| 1638 | 1726 |
| 1639 #undef __ | 1727 #undef __ |
| 1640 | 1728 |
| 1641 #endif // defined TARGET_ARCH_X64 | 1729 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |