Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 278 const Register kTempReg = kNoRegister; | 278 const Register kTempReg = kNoRegister; |
| 279 return GenerateCallSubtypeTestStub(kTestTypeOneArg, | 279 return GenerateCallSubtypeTestStub(kTestTypeOneArg, |
| 280 kInstanceReg, | 280 kInstanceReg, |
| 281 kTypeArgumentsReg, | 281 kTypeArgumentsReg, |
| 282 kTempReg, | 282 kTempReg, |
| 283 is_instance_lbl, | 283 is_instance_lbl, |
| 284 is_not_instance_lbl); | 284 is_not_instance_lbl); |
| 285 } | 285 } |
| 286 | 286 |
| 287 | 287 |
| 288 // Generates inlined check if 'type' is a type parameter or type itsef | |
|
srdjan
2013/04/19 22:56:40
s/itsef/itself/
regis
2013/04/19 23:19:19
Corrected here and in the Intel sources.
| |
| 289 // R0: instance (preserved). | |
| 288 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 290 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| 289 intptr_t token_pos, | 291 intptr_t token_pos, |
| 290 const AbstractType& type, | 292 const AbstractType& type, |
| 291 Label* is_instance_lbl, | 293 Label* is_instance_lbl, |
| 292 Label* is_not_instance_lbl) { | 294 Label* is_not_instance_lbl) { |
| 293 UNIMPLEMENTED(); | 295 __ Comment("UninstantiatedTypeTest"); |
| 294 return NULL; | 296 ASSERT(!type.IsInstantiated()); |
| 297 // Skip check if destination is a dynamic type. | |
| 298 if (type.IsTypeParameter()) { | |
| 299 const TypeParameter& type_param = TypeParameter::Cast(type); | |
| 300 // Load instantiator (or null) and instantiator type arguments on stack. | |
| 301 __ ldr(R1, Address(SP, 0)); // Get instantiator type arguments. | |
| 302 // R1: instantiator type arguments. | |
| 303 // Check if type argument is dynamic. | |
| 304 __ CompareImmediate(R1, reinterpret_cast<intptr_t>(Object::null())); | |
| 305 __ b(is_instance_lbl, EQ); | |
| 306 // Can handle only type arguments that are instances of TypeArguments. | |
| 307 // (runtime checks canonicalize type arguments). | |
| 308 Label fall_through; | |
| 309 __ CompareClassId(R1, kTypeArgumentsCid, R2); | |
| 310 __ b(&fall_through, NE); | |
| 311 __ ldr(R2, | |
| 312 FieldAddress(R1, TypeArguments::type_at_offset(type_param.index()))); | |
| 313 // R2: concrete type of type. | |
| 314 // Check if type argument is dynamic. | |
| 315 __ CompareObject(R2, Type::ZoneHandle(Type::DynamicType())); | |
| 316 __ b(is_instance_lbl, EQ); | |
| 317 __ CompareImmediate(R2, reinterpret_cast<intptr_t>(Object::null())); | |
| 318 __ b(is_instance_lbl, EQ); | |
| 319 const Type& object_type = Type::ZoneHandle(Type::ObjectType()); | |
| 320 __ CompareObject(R2, object_type); | |
| 321 __ b(is_instance_lbl, EQ); | |
| 322 | |
| 323 // For Smi check quickly against int and num interfaces. | |
| 324 Label not_smi; | |
| 325 __ tst(R0, ShifterOperand(kSmiTagMask)); // Value is Smi? | |
| 326 __ b(¬_smi, NE); | |
| 327 __ CompareObject(R2, Type::ZoneHandle(Type::IntType())); | |
| 328 __ b(is_instance_lbl, EQ); | |
| 329 __ CompareObject(R2, Type::ZoneHandle(Type::Number())); | |
| 330 __ b(is_instance_lbl, EQ); | |
| 331 // Smi must be handled in runtime. | |
| 332 __ b(&fall_through); | |
| 333 | |
| 334 __ Bind(¬_smi); | |
| 335 // R1: instantiator type arguments. | |
| 336 // R0: instance. | |
| 337 const Register kInstanceReg = R0; | |
| 338 const Register kTypeArgumentsReg = R1; | |
| 339 const Register kTempReg = kNoRegister; | |
| 340 const SubtypeTestCache& type_test_cache = | |
| 341 SubtypeTestCache::ZoneHandle( | |
| 342 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | |
| 343 kInstanceReg, | |
| 344 kTypeArgumentsReg, | |
| 345 kTempReg, | |
| 346 is_instance_lbl, | |
| 347 is_not_instance_lbl)); | |
| 348 __ Bind(&fall_through); | |
| 349 return type_test_cache.raw(); | |
| 350 } | |
| 351 if (type.IsType()) { | |
| 352 const Register kInstanceReg = R0; | |
| 353 const Register kTypeArgumentsReg = R1; | |
| 354 __ tst(kInstanceReg, ShifterOperand(kSmiTagMask)); // Is instance Smi? | |
| 355 __ b(is_not_instance_lbl, EQ); | |
| 356 __ ldr(kTypeArgumentsReg, Address(SP, 0)); // Instantiator type args. | |
| 357 // Uninstantiated type class is known at compile time, but the type | |
| 358 // arguments are determined at runtime by the instantiator. | |
| 359 const Register kTempReg = kNoRegister; | |
| 360 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | |
| 361 kInstanceReg, | |
| 362 kTypeArgumentsReg, | |
| 363 kTempReg, | |
| 364 is_instance_lbl, | |
| 365 is_not_instance_lbl); | |
| 366 } | |
| 367 return SubtypeTestCache::null(); | |
| 295 } | 368 } |
| 296 | 369 |
| 297 | 370 |
| 298 // Inputs: | 371 // Inputs: |
| 299 // - R0: instance being type checked (preserved). | 372 // - R0: instance being type checked (preserved). |
| 300 // - R1: optional instantiator type arguments (preserved). | 373 // - R1: optional instantiator type arguments (preserved). |
| 301 // Clobbers R2, R3. | 374 // Clobbers R2, R3. |
| 302 // Returns: | 375 // Returns: |
| 303 // - preserved instance in R0 and optional instantiator type arguments in R1. | 376 // - preserved instance in R0 and optional instantiator type arguments in R1. |
| 304 // Note that this inlined code must be followed by the runtime_call code, as it | 377 // Note that this inlined code must be followed by the runtime_call code, as it |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 387 intptr_t deopt_id, | 460 intptr_t deopt_id, |
| 388 const AbstractType& dst_type, | 461 const AbstractType& dst_type, |
| 389 const String& dst_name, | 462 const String& dst_name, |
| 390 LocationSummary* locs) { | 463 LocationSummary* locs) { |
| 391 ASSERT(token_pos >= 0); | 464 ASSERT(token_pos >= 0); |
| 392 ASSERT(!dst_type.IsNull()); | 465 ASSERT(!dst_type.IsNull()); |
| 393 ASSERT(dst_type.IsFinalized()); | 466 ASSERT(dst_type.IsFinalized()); |
| 394 // Assignable check is skipped in FlowGraphBuilder, not here. | 467 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 395 ASSERT(dst_type.IsMalformed() || | 468 ASSERT(dst_type.IsMalformed() || |
| 396 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 469 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 397 // Preserve instantiator and its type arguments. | 470 // Preserve instantiator (R2) and its type arguments (R1). |
| 398 __ PushList((1 << R1) | (1 << R2)); | 471 __ PushList((1 << R1) | (1 << R2)); |
| 399 // A null object is always assignable and is returned as result. | 472 // A null object is always assignable and is returned as result. |
| 400 Label is_assignable, runtime_call; | 473 Label is_assignable, runtime_call; |
| 401 __ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null())); | 474 __ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null())); |
| 402 __ b(&is_assignable, EQ); | 475 __ b(&is_assignable, EQ); |
| 403 | 476 |
| 404 if (!FLAG_eliminate_type_checks) { | 477 if (!FLAG_eliminate_type_checks) { |
| 405 // If type checks are not eliminated during the graph building then | 478 // If type checks are not eliminated during the graph building then |
| 406 // a transition sentinel can be seen here. | 479 // a transition sentinel can be seen here. |
| 407 __ CompareObject(R0, Object::transition_sentinel()); | 480 __ CompareObject(R0, Object::transition_sentinel()); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 418 __ PushObject(dst_name); // Push the name of the destination. | 491 __ PushObject(dst_name); // Push the name of the destination. |
| 419 __ PushObject(error_message); | 492 __ PushObject(error_message); |
| 420 GenerateCallRuntime(token_pos, | 493 GenerateCallRuntime(token_pos, |
| 421 deopt_id, | 494 deopt_id, |
| 422 kMalformedTypeErrorRuntimeEntry, | 495 kMalformedTypeErrorRuntimeEntry, |
| 423 locs); | 496 locs); |
| 424 // We should never return here. | 497 // We should never return here. |
| 425 __ bkpt(0); | 498 __ bkpt(0); |
| 426 | 499 |
| 427 __ Bind(&is_assignable); // For a null object. | 500 __ Bind(&is_assignable); // For a null object. |
| 428 // Restore instantiator and its type arguments. | 501 // Restore instantiator (R2) and its type arguments (R1). |
| 429 __ PopList((1 << R1) | (1 << R2)); | 502 __ PopList((1 << R1) | (1 << R2)); |
| 430 return; | 503 return; |
| 431 } | 504 } |
| 432 | 505 |
| 433 // Generate inline type check, linking to runtime call if not assignable. | 506 // Generate inline type check, linking to runtime call if not assignable. |
| 434 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 507 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 435 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 508 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
| 436 &is_assignable, &runtime_call); | 509 &is_assignable, &runtime_call); |
| 437 | 510 |
| 438 __ Bind(&runtime_call); | 511 __ Bind(&runtime_call); |
| 439 // Load instantiator and its type arguments. | 512 // Load instantiator (R2) and its type arguments (R1). |
| 440 __ ldm(IA, SP, (1 << R1) | (1 << R2)); | 513 __ ldm(IA, SP, (1 << R1) | (1 << R2)); |
| 441 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 514 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 442 __ Push(R0); // Push the source object. | 515 __ Push(R0); // Push the source object. |
| 443 __ PushObject(dst_type); // Push the type of the destination. | 516 __ PushObject(dst_type); // Push the type of the destination. |
| 444 // Push instantiator and its type arguments. | 517 // Push instantiator (R2) and its type arguments (R1). |
| 445 __ PushList((1 << R1) | (1 << R2)); | 518 __ PushList((1 << R1) | (1 << R2)); |
| 446 __ PushObject(dst_name); // Push the name of the destination. | 519 __ PushObject(dst_name); // Push the name of the destination. |
| 447 __ LoadObject(R0, test_cache); | 520 __ LoadObject(R0, test_cache); |
| 448 __ Push(R0); | 521 __ Push(R0); |
| 449 GenerateCallRuntime(token_pos, deopt_id, kTypeCheckRuntimeEntry, locs); | 522 GenerateCallRuntime(token_pos, deopt_id, kTypeCheckRuntimeEntry, locs); |
| 450 // Pop the parameters supplied to the runtime entry. The result of the | 523 // Pop the parameters supplied to the runtime entry. The result of the |
| 451 // type check runtime call is the checked value. | 524 // type check runtime call is the checked value. |
| 452 __ Drop(6); | 525 __ Drop(6); |
| 453 __ Pop(R0); | 526 __ Pop(R0); |
| 454 | 527 |
| 455 __ Bind(&is_assignable); | 528 __ Bind(&is_assignable); |
| 456 // Restore instantiator and its type arguments. | 529 // Restore instantiator (R2) and its type arguments (R1). |
| 457 __ PopList((1 << R1) | (1 << R2)); | 530 __ PopList((1 << R1) | (1 << R2)); |
| 458 } | 531 } |
| 459 | 532 |
| 460 | 533 |
| 461 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) { | 534 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) { |
| 462 if (!is_optimizing()) { | 535 if (!is_optimizing()) { |
| 463 if (FLAG_enable_type_checks && instr->IsAssertAssignable()) { | 536 if (FLAG_enable_type_checks && instr->IsAssertAssignable()) { |
| 464 AssertAssignableInstr* assert = instr->AsAssertAssignable(); | 537 AssertAssignableInstr* assert = instr->AsAssertAssignable(); |
| 465 AddCurrentDescriptor(PcDescriptors::kDeopt, | 538 AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 466 assert->deopt_id(), | 539 assert->deopt_id(), |
| (...skipping 903 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1370 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1443 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
| 1371 __ vldrd(reg, Address(SP, kDoubleSize, Address::PostIndex)); | 1444 __ vldrd(reg, Address(SP, kDoubleSize, Address::PostIndex)); |
| 1372 } | 1445 } |
| 1373 | 1446 |
| 1374 | 1447 |
| 1375 #undef __ | 1448 #undef __ |
| 1376 | 1449 |
| 1377 } // namespace dart | 1450 } // namespace dart |
| 1378 | 1451 |
| 1379 #endif // defined TARGET_ARCH_ARM | 1452 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |