| 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/code_generator.h" | 5 #include "vm/code_generator.h" |
| 6 | 6 |
| 7 #include "vm/code_patcher.h" | 7 #include "vm/code_patcher.h" |
| 8 #include "vm/compiler.h" | 8 #include "vm/compiler.h" |
| 9 #include "vm/dart_api_impl.h" | 9 #include "vm/dart_api_impl.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 Context& cloned_ctx = Context::Handle(Context::New(ctx.num_variables())); | 369 Context& cloned_ctx = Context::Handle(Context::New(ctx.num_variables())); |
| 370 cloned_ctx.set_parent(Context::Handle(ctx.parent())); | 370 cloned_ctx.set_parent(Context::Handle(ctx.parent())); |
| 371 for (int i = 0; i < ctx.num_variables(); i++) { | 371 for (int i = 0; i < ctx.num_variables(); i++) { |
| 372 cloned_ctx.SetAt(i, Instance::Handle(ctx.At(i))); | 372 cloned_ctx.SetAt(i, Instance::Handle(ctx.At(i))); |
| 373 } | 373 } |
| 374 arguments.SetReturn(cloned_ctx); | 374 arguments.SetReturn(cloned_ctx); |
| 375 } | 375 } |
| 376 | 376 |
| 377 | 377 |
| 378 // Helper routine for tracing a type check. | 378 // Helper routine for tracing a type check. |
| 379 static void PrintTypeCheck(const char* message, | 379 static void PrintTypeCheck( |
| 380 const Instance& instance, | 380 const char* message, |
| 381 const AbstractType&type, | 381 const Instance& instance, |
| 382 const AbstractTypeArguments& type_instantiator, | 382 const AbstractType&type, |
| 383 const Bool& result) { | 383 const AbstractTypeArguments& instantiator_type_arguments, |
| 384 const Bool& result) { |
| 385 DartFrameIterator iterator; |
| 386 StackFrame* caller_frame = iterator.NextFrame(); |
| 387 ASSERT(caller_frame != NULL); |
| 388 |
| 384 const Type& instance_type = Type::Handle(instance.GetType()); | 389 const Type& instance_type = Type::Handle(instance.GetType()); |
| 385 ASSERT(instance_type.IsInstantiated()); | 390 ASSERT(instance_type.IsInstantiated()); |
| 386 if (type.IsInstantiated()) { | 391 if (type.IsInstantiated()) { |
| 387 OS::Print("%s: '%s' %s '%s'.\n", | 392 OS::Print("%s: '%s' %s '%s' (pc: 0x%x).\n", |
| 388 message, | 393 message, |
| 389 String::Handle(instance_type.Name()).ToCString(), | 394 String::Handle(instance_type.Name()).ToCString(), |
| 390 (result.raw() == Bool::True()) ? "is" : "is !", | 395 (result.raw() == Bool::True()) ? "is" : "is !", |
| 391 String::Handle(type.Name()).ToCString()); | 396 String::Handle(type.Name()).ToCString(), |
| 397 caller_frame->pc()); |
| 392 } else { | 398 } else { |
| 393 // Instantiate type before printing. | 399 // Instantiate type before printing. |
| 394 const AbstractType& instantiated_type = | 400 const AbstractType& instantiated_type = |
| 395 AbstractType::Handle(type.InstantiateFrom(type_instantiator)); | 401 AbstractType::Handle(type.InstantiateFrom(instantiator_type_arguments)); |
| 396 OS::Print("%s: '%s' %s '%s' instantiated from '%s'.\n", | 402 OS::Print("%s: '%s' %s '%s' instantiated from '%s' (pc: 0x%x).\n", |
| 397 message, | 403 message, |
| 398 String::Handle(instance_type.Name()).ToCString(), | 404 String::Handle(instance_type.Name()).ToCString(), |
| 399 (result.raw() == Bool::True()) ? "is" : "is !", | 405 (result.raw() == Bool::True()) ? "is" : "is !", |
| 400 String::Handle(instantiated_type.Name()).ToCString(), | 406 String::Handle(instantiated_type.Name()).ToCString(), |
| 401 String::Handle(type.Name()).ToCString()); | 407 String::Handle(type.Name()).ToCString(), |
| 408 caller_frame->pc()); |
| 402 } | 409 } |
| 403 DartFrameIterator iterator; | |
| 404 StackFrame* caller_frame = iterator.NextFrame(); | |
| 405 ASSERT(caller_frame != NULL); | |
| 406 const Function& function = Function::Handle( | 410 const Function& function = Function::Handle( |
| 407 caller_frame->LookupDartFunction()); | 411 caller_frame->LookupDartFunction()); |
| 408 OS::Print(" -> Function %s\n", function.ToFullyQualifiedCString()); | 412 OS::Print(" -> Function %s\n", function.ToFullyQualifiedCString()); |
| 409 } | 413 } |
| 410 | 414 |
| 411 | 415 |
| 412 // Converts InstantiatedTypeArguments to TypeArguments and stores it | 416 // Converts InstantiatedTypeArguments to TypeArguments and stores it |
| 413 // into the instance. The assembly code can handle only type arguments of | 417 // into the instance. The assembly code can handle only type arguments of |
| 414 // class TypeArguments. Because of the overhead, do it only when needed. | 418 // class TypeArguments. Because of the overhead, do it only when needed. |
| 415 static void OptimizeTypeArguments(const Instance& instance) { | 419 // Return false if the optimization was aborted. |
| 420 // Set type_arguments_replaced to true if they have changed. |
| 421 static bool OptimizeTypeArguments(const Instance& instance, |
| 422 bool* type_arguments_replaced) { |
| 423 *type_arguments_replaced = false; |
| 416 const Class& type_class = Class::ZoneHandle(instance.clazz()); | 424 const Class& type_class = Class::ZoneHandle(instance.clazz()); |
| 417 if (type_class.HasTypeArguments()) { | 425 if (!type_class.HasTypeArguments()) { |
| 418 const AbstractTypeArguments& type_arguments = | 426 return true; |
| 419 AbstractTypeArguments::Handle(instance.GetTypeArguments()); | 427 } |
| 420 if (!type_arguments.IsNull() && | 428 const AbstractTypeArguments& type_arguments = |
| 421 type_arguments.IsInstantiatedTypeArguments()) { | 429 AbstractTypeArguments::Handle(instance.GetTypeArguments()); |
| 422 TypeArguments& new_type_arguments = | 430 if (type_arguments.IsNull()) { |
| 423 TypeArguments::Handle(TypeArguments::New(type_arguments.Length())); | 431 return true; |
| 424 for (int i = 0; i < type_arguments.Length(); i++) { | 432 } |
| 425 const AbstractType& type_at = | 433 if (type_arguments.IsInstantiatedTypeArguments()) { |
| 426 AbstractType::Handle(type_arguments.TypeAt(i)); | 434 TypeArguments& new_type_arguments = TypeArguments::Handle(); |
| 427 if (type_at.IsInstantiatedType()) { | 435 InstantiatedTypeArguments& instantiated_type_arguments = |
| 428 // TODO(srdjan): cannot canonicalize TypeArguments that contain | 436 InstantiatedTypeArguments::Handle(); |
| 429 // InstantiatedType. | 437 instantiated_type_arguments ^= type_arguments.raw(); |
| 430 return; | 438 const AbstractTypeArguments& uninstantiated = |
| 431 } else if (!type_at.IsType()) { | 439 AbstractTypeArguments::Handle( |
| 432 // type_at cannot be TypeParameter at runtime. | 440 instantiated_type_arguments.uninstantiated_type_arguments()); |
| 433 UNREACHABLE(); | 441 const AbstractTypeArguments& instantiator = |
| 434 } | 442 AbstractTypeArguments::Handle( |
| 435 new_type_arguments.SetTypeAt(i, type_at); | 443 instantiated_type_arguments.instantiator_type_arguments()); |
| 436 } | 444 AbstractTypeArguments& temp = AbstractTypeArguments::Handle(); |
| 437 new_type_arguments ^= new_type_arguments.Canonicalize(); | 445 temp = uninstantiated.InstantiateFrom(instantiator); |
| 438 instance.SetTypeArguments(new_type_arguments); | 446 if (!temp.IsTypeArguments()) { |
| 447 // TODO(srdjan): Figure out why it does not want to convert to |
| 448 // TypeArguments. |
| 449 return false; |
| 439 } | 450 } |
| 451 new_type_arguments ^= temp.raw(); |
| 452 new_type_arguments ^= new_type_arguments.Canonicalize(); |
| 453 instance.SetTypeArguments(new_type_arguments); |
| 454 *type_arguments_replaced = true; |
| 455 } else if (!type_arguments.IsCanonical()) { |
| 456 AbstractTypeArguments& new_type_arguments = |
| 457 AbstractTypeArguments::Handle(); |
| 458 new_type_arguments ^= type_arguments.Canonicalize(); |
| 459 instance.SetTypeArguments(new_type_arguments); |
| 460 *type_arguments_replaced = true; |
| 440 } | 461 } |
| 462 ASSERT(AbstractTypeArguments::Handle( |
| 463 instance.GetTypeArguments()).IsTypeArguments()); |
| 464 return true; |
| 441 } | 465 } |
| 442 | 466 |
| 443 | 467 |
| 444 // This updates the type test cache, an array containing 4-value elements | 468 // This updates the type test cache, an array containing 4-value elements |
| 445 // (instance class, instance type arguments, instantiator type arguments and | 469 // (instance class, instance type arguments, instantiator type arguments and |
| 446 // test_result). It can be applied to classes with type arguments in which | 470 // test_result). It can be applied to classes with type arguments in which |
| 447 // case it contains just the result of the class subtype test, not including | 471 // case it contains just the result of the class subtype test, not including |
| 448 // the evaluation of type arguments. | 472 // the evaluation of type arguments. |
| 449 // This operation is currently very slow (lookup of code is not efficient yet). | 473 // This operation is currently very slow (lookup of code is not efficient yet). |
| 450 static void UpdateTypeTestCache(intptr_t node_id, | 474 // 'instantiator' can be null, in which case inst_targ |
| 451 const Instance& instance, | 475 static void UpdateTypeTestCache( |
| 452 const AbstractType& type, | 476 intptr_t node_id, |
| 453 const AbstractTypeArguments& type_instantiator, | 477 const Instance& instance, |
| 454 const Bool& result, | 478 const AbstractType& type, |
| 455 const SubtypeTestCache& new_cache) { | 479 const Instance& instantiator, |
| 480 const AbstractTypeArguments& incoming_instantiator_type_arguments, |
| 481 const Bool& result, |
| 482 const SubtypeTestCache& new_cache) { |
| 456 // Since the test is expensive, don't do it unless necessary. | 483 // Since the test is expensive, don't do it unless necessary. |
| 457 // The list of disallowed cases will decrease as they are implemented in | 484 // The list of disallowed cases will decrease as they are implemented in |
| 458 // inlined assembly. | 485 // inlined assembly. |
| 459 if (new_cache.IsNull()) return; | 486 if (new_cache.IsNull()) return; |
| 487 // Instantiator type arguments may be canonicalized later. |
| 488 AbstractTypeArguments& instantiator_type_arguments = |
| 489 AbstractTypeArguments::Handle(incoming_instantiator_type_arguments.raw()); |
| 460 AbstractTypeArguments& instance_type_arguments = | 490 AbstractTypeArguments& instance_type_arguments = |
| 461 AbstractTypeArguments::Handle(); | 491 AbstractTypeArguments::Handle(); |
| 462 const Class& instance_class = Class::Handle(instance.clazz()); | 492 const Class& instance_class = Class::Handle(instance.clazz()); |
| 463 AbstractTypeArguments& original_instance_type_arguments = | 493 |
| 464 AbstractTypeArguments::Handle(); | 494 // Canonicalize type arguments. |
| 495 bool type_arguments_replaced = false; |
| 465 if (instance_class.HasTypeArguments()) { | 496 if (instance_class.HasTypeArguments()) { |
| 466 // Canonicalize type arguments. | 497 // Canonicalize type arguments. |
| 467 original_instance_type_arguments = instance.GetTypeArguments(); | 498 if (!OptimizeTypeArguments(instance, &type_arguments_replaced)) { |
| 468 OptimizeTypeArguments(instance); | 499 if (FLAG_trace_type_checks) { |
| 500 PrintTypeCheck("WARNING: Cannot canonicalize instance type arguments", |
| 501 instance, type, instantiator_type_arguments, result); |
| 502 } |
| 503 return; |
| 504 } |
| 469 instance_type_arguments = instance.GetTypeArguments(); | 505 instance_type_arguments = instance.GetTypeArguments(); |
| 470 } | 506 } |
| 507 if (!instantiator.IsNull()) { |
| 508 bool replaced = false; |
| 509 if (!OptimizeTypeArguments(instantiator, &replaced)) { |
| 510 if (FLAG_trace_type_checks) { |
| 511 PrintTypeCheck("WARNING: Cannot canonicalize instantiator " |
| 512 "type arguments", |
| 513 instance, type, instantiator_type_arguments, result); |
| 514 } |
| 515 return; |
| 516 } |
| 517 if (replaced) { |
| 518 type_arguments_replaced = true; |
| 519 } |
| 520 instantiator_type_arguments ^= instantiator.GetTypeArguments(); |
| 521 } |
| 471 | 522 |
| 472 Class& last_instance_class = Class::Handle(); | 523 Class& last_instance_class = Class::Handle(); |
| 473 AbstractTypeArguments& last_instance_type_arguments = | 524 AbstractTypeArguments& last_instance_type_arguments = |
| 474 AbstractTypeArguments::Handle(); | 525 AbstractTypeArguments::Handle(); |
| 475 AbstractTypeArguments& last_instantiator_type_arguments = | 526 AbstractTypeArguments& last_instantiator_type_arguments = |
| 476 AbstractTypeArguments::Handle(); | 527 AbstractTypeArguments::Handle(); |
| 477 Bool& last_result = Bool::Handle(); | 528 Bool& last_result = Bool::Handle(); |
| 478 intptr_t len = new_cache.NumberOfChecks(); | 529 intptr_t len = new_cache.NumberOfChecks(); |
| 479 for (intptr_t i = 0; i < len; ++i) { | 530 for (intptr_t i = 0; i < len; ++i) { |
| 480 new_cache.GetCheck( | 531 new_cache.GetCheck( |
| 481 i, | 532 i, |
| 482 &last_instance_class, | 533 &last_instance_class, |
| 483 &last_instance_type_arguments, | 534 &last_instance_type_arguments, |
| 484 &last_instantiator_type_arguments, | 535 &last_instantiator_type_arguments, |
| 485 &last_result); | 536 &last_result); |
| 486 if ((last_instance_class.raw() == instance_class.raw()) && | 537 if ((last_instance_class.raw() == instance_class.raw()) && |
| 487 (last_instance_type_arguments.raw() == | 538 (last_instance_type_arguments.raw() == instance_type_arguments.raw()) && |
| 488 instance_type_arguments.raw())) { | 539 (last_instantiator_type_arguments.raw() == |
| 540 instantiator_type_arguments.raw())) { |
| 489 if (FLAG_trace_type_checks) { | 541 if (FLAG_trace_type_checks) { |
| 490 if (original_instance_type_arguments.raw() == | 542 OS::Print("%d ", i); |
| 491 instance_type_arguments.raw()) { | 543 PrintTypeCheck("WARNING duplicate cache entry", instance, type, |
| 492 PrintTypeCheck("WARNING duplicate cache entry", instance, type, | 544 instantiator_type_arguments, result); |
| 493 type_instantiator, result); | |
| 494 } | |
| 495 } | 545 } |
| 496 // A duplicate entry found, likely because the instance type arguments | 546 // Can occur if we have canonicalized arguments. |
| 497 // were not cacnonicalized before. | 547 // TODO(srdjan): Investigate why this assert can fail. |
| 548 // ASSERT(type_arguments_replaced); |
| 498 return; | 549 return; |
| 499 } | 550 } |
| 500 } | 551 } |
| 501 new_cache.AddCheck(instance_class, | 552 new_cache.AddCheck(instance_class, |
| 502 instance_type_arguments, | 553 instance_type_arguments, |
| 503 AbstractTypeArguments::Handle(), | 554 instantiator_type_arguments, |
| 504 result); | 555 result); |
| 505 if (FLAG_trace_type_checks) { | 556 if (FLAG_trace_type_checks) { |
| 506 OS::Print(" Updated test cache 0x%x ix:%d:\n" | 557 OS::Print(" Updated test cache 0x%x ix:%d:\n" |
| 507 " [0x%x %s, 0x%x %s]\n" | 558 " [0x%x %s, 0x%x %s]\n" |
| 508 " [0x%x %s] %s\n", | 559 " [0x%x %s, 0x%x %s] %s\n", |
| 509 new_cache.raw(), | 560 new_cache.raw(), |
| 510 len, | 561 len, |
| 511 instance_class.raw(), | 562 instance_class.raw(), |
| 512 instance_class.ToCString(), | 563 instance_class.ToCString(), |
| 513 instance_type_arguments.raw(), | 564 instance_type_arguments.raw(), |
| 514 instance_type_arguments.ToCString(), | 565 instance_type_arguments.ToCString(), |
| 515 type.type_class(), | 566 type.type_class(), |
| 516 Class::Handle(type.type_class()).ToCString(), | 567 Class::Handle(type.type_class()).ToCString(), |
| 568 instantiator_type_arguments.raw(), |
| 569 instantiator_type_arguments.ToCString(), |
| 517 result.ToCString()); | 570 result.ToCString()); |
| 518 } | 571 } |
| 519 } | 572 } |
| 520 | 573 |
| 521 | 574 |
| 522 // Check that the given instance is an instance of the given type. | 575 // Check that the given instance is an instance of the given type. |
| 523 // Tested instance may not be null, because the null test is inlined. | 576 // Tested instance may not be null, because the null test is inlined. |
| 524 // Arg0: index of the token of the instanceof test (source location). | 577 // Arg0: index of the token of the instanceof test (source location). |
| 525 // Arg1: node id of the instanceof node. | 578 // Arg1: node id of the instanceof node. |
| 526 // Arg2: instance being checked. | 579 // Arg2: instance being checked. |
| 527 // Arg3: type. | 580 // Arg3: type. |
| 528 // Arg4: type arguments of the instantiator of the type. | 581 // Arg4: instantiator (or null). |
| 529 // Arg5: SubtypeTestCache. | 582 // Arg5: type arguments of the instantiator of the type. |
| 583 // Arg6: SubtypeTestCache. |
| 530 // Return value: true or false, or may throw a type error in checked mode. | 584 // Return value: true or false, or may throw a type error in checked mode. |
| 531 DEFINE_RUNTIME_ENTRY(Instanceof, 6) { | 585 DEFINE_RUNTIME_ENTRY(Instanceof, 7) { |
| 532 ASSERT(arguments.Count() == kInstanceofRuntimeEntry.argument_count()); | 586 ASSERT(arguments.Count() == kInstanceofRuntimeEntry.argument_count()); |
| 533 // TODO(regis): Get the token index from the PcDesc (via DartFrame). | 587 // TODO(regis): Get the token index from the PcDesc (via DartFrame). |
| 534 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); | 588 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); |
| 535 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value(); | 589 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value(); |
| 536 const Instance& instance = Instance::CheckedHandle(arguments.At(2)); | 590 const Instance& instance = Instance::CheckedHandle(arguments.At(2)); |
| 537 const AbstractType& type = AbstractType::CheckedHandle(arguments.At(3)); | 591 const AbstractType& type = AbstractType::CheckedHandle(arguments.At(3)); |
| 538 const AbstractTypeArguments& type_instantiator = | 592 const Instance& instantiator = Instance::CheckedHandle(arguments.At(4)); |
| 539 AbstractTypeArguments::CheckedHandle(arguments.At(4)); | 593 const AbstractTypeArguments& instantiator_type_arguments = |
| 594 AbstractTypeArguments::CheckedHandle(arguments.At(5)); |
| 540 const SubtypeTestCache& cache = | 595 const SubtypeTestCache& cache = |
| 541 SubtypeTestCache::CheckedHandle(arguments.At(5)); | 596 SubtypeTestCache::CheckedHandle(arguments.At(6)); |
| 542 ASSERT(type.IsFinalized()); | 597 ASSERT(type.IsFinalized()); |
| 543 Error& malformed_error = Error::Handle(); | 598 Error& malformed_error = Error::Handle(); |
| 544 const Bool& result = Bool::Handle( | 599 const Bool& result = Bool::Handle( |
| 545 instance.IsInstanceOf(type, type_instantiator, &malformed_error) ? | 600 instance.IsInstanceOf(type, |
| 601 instantiator_type_arguments, |
| 602 &malformed_error) ? |
| 546 Bool::True() : Bool::False()); | 603 Bool::True() : Bool::False()); |
| 547 if (FLAG_trace_type_checks) { | 604 if (FLAG_trace_type_checks) { |
| 548 PrintTypeCheck("InstanceOf", instance, type, type_instantiator, result); | 605 PrintTypeCheck("InstanceOf", |
| 606 instance, type, instantiator_type_arguments, result); |
| 549 } | 607 } |
| 550 if (!result.value() && !malformed_error.IsNull()) { | 608 if (!result.value() && !malformed_error.IsNull()) { |
| 551 // Throw a dynamic type error only if the instanceof test fails. | 609 // Throw a dynamic type error only if the instanceof test fails. |
| 552 String& malformed_error_message = String::Handle( | 610 String& malformed_error_message = String::Handle( |
| 553 String::New(malformed_error.ToErrorCString())); | 611 String::New(malformed_error.ToErrorCString())); |
| 554 const String& no_name = String::Handle(String::NewSymbol("")); | 612 const String& no_name = String::Handle(String::NewSymbol("")); |
| 555 Exceptions::CreateAndThrowTypeError( | 613 Exceptions::CreateAndThrowTypeError( |
| 556 location, no_name, no_name, no_name, malformed_error_message); | 614 location, no_name, no_name, no_name, malformed_error_message); |
| 557 UNREACHABLE(); | 615 UNREACHABLE(); |
| 558 } | 616 } |
| 559 UpdateTypeTestCache( | 617 UpdateTypeTestCache(node_id, instance, type, instantiator, |
| 560 node_id, instance, type, type_instantiator, result, cache); | 618 instantiator_type_arguments, result, cache); |
| 561 arguments.SetReturn(result); | 619 arguments.SetReturn(result); |
| 562 } | 620 } |
| 563 | 621 |
| 564 | 622 |
| 565 // For error reporting simplify type name, e.g, all integer types (Smi, Mint, | 623 // For error reporting simplify type name, e.g, all integer types (Smi, Mint, |
| 566 // Bigint) a re reported as 'int'. | 624 // Bigint) a re reported as 'int'. |
| 567 static RawString* GetSimpleTypeName(const Instance& value) { | 625 static RawString* GetSimpleTypeName(const Instance& value) { |
| 568 if (value.IsInteger()) { | 626 if (value.IsInteger()) { |
| 569 return String::NewSymbol("int"); | 627 return String::NewSymbol("int"); |
| 570 } else { | 628 } else { |
| 571 return Type::Handle(value.GetType()).Name(); | 629 return Type::Handle(value.GetType()).Name(); |
| 572 } | 630 } |
| 573 } | 631 } |
| 574 | 632 |
| 575 | 633 |
| 576 // Check that the type of the given instance is a subtype of the given type and | 634 // Check that the type of the given instance is a subtype of the given type and |
| 577 // can therefore be assigned. | 635 // can therefore be assigned. |
| 578 // Arg0: index of the token of the assignment (source location). | 636 // Arg0: index of the token of the assignment (source location). |
| 579 // Arg1: node-id of the assignemnt. | 637 // Arg1: node-id of the assignment. |
| 580 // Arg2: instance being assigned. | 638 // Arg2: instance being assigned. |
| 581 // Arg3: type being assigned to. | 639 // Arg3: type being assigned to. |
| 582 // Arg4: type arguments of the instantiator of the type being assigned to. | 640 // Arg4: instantiator (or null). |
| 583 // Arg5: name of variable being assigned to. | 641 // Arg5: type arguments of the instantiator of the type being assigned to. |
| 584 // Arg6: SubtypeTestCache. | 642 // Arg6: name of variable being assigned to. |
| 643 // Arg7: SubtypeTestCache. |
| 585 // Return value: instance if a subtype, otherwise throw a TypeError. | 644 // Return value: instance if a subtype, otherwise throw a TypeError. |
| 586 DEFINE_RUNTIME_ENTRY(TypeCheck, 7) { | 645 DEFINE_RUNTIME_ENTRY(TypeCheck, 8) { |
| 587 ASSERT(arguments.Count() == kTypeCheckRuntimeEntry.argument_count()); | 646 ASSERT(arguments.Count() == kTypeCheckRuntimeEntry.argument_count()); |
| 588 // TODO(regis): Get the token index from the PcDesc (via DartFrame). | 647 // TODO(regis): Get the token index from the PcDesc (via DartFrame). |
| 589 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); | 648 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); |
| 590 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value(); | 649 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value(); |
| 591 const Instance& src_instance = Instance::CheckedHandle(arguments.At(2)); | 650 const Instance& src_instance = Instance::CheckedHandle(arguments.At(2)); |
| 592 const AbstractType& dst_type = AbstractType::CheckedHandle(arguments.At(3)); | 651 const AbstractType& dst_type = AbstractType::CheckedHandle(arguments.At(3)); |
| 593 const AbstractTypeArguments& dst_type_instantiator = | 652 const Instance& dst_instantiator = Instance::CheckedHandle(arguments.At(4)); |
| 594 AbstractTypeArguments::CheckedHandle(arguments.At(4)); | 653 const AbstractTypeArguments& instantiator_type_arguments = |
| 595 const String& dst_name = String::CheckedHandle(arguments.At(5)); | 654 AbstractTypeArguments::CheckedHandle(arguments.At(5)); |
| 655 const String& dst_name = String::CheckedHandle(arguments.At(6)); |
| 596 const SubtypeTestCache& cache = | 656 const SubtypeTestCache& cache = |
| 597 SubtypeTestCache::CheckedHandle(arguments.At(6)); | 657 SubtypeTestCache::CheckedHandle(arguments.At(7)); |
| 598 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment. | 658 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment. |
| 599 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator. | 659 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator. |
| 600 ASSERT(!src_instance.IsNull()); // Already checked in inlined code. | 660 ASSERT(!src_instance.IsNull()); // Already checked in inlined code. |
| 601 | 661 |
| 602 Error& malformed_error = Error::Handle(); | 662 Error& malformed_error = Error::Handle(); |
| 603 const bool is_instance_of = src_instance.IsInstanceOf( | 663 const bool is_instance_of = src_instance.IsInstanceOf( |
| 604 dst_type, dst_type_instantiator, &malformed_error); | 664 dst_type, instantiator_type_arguments, &malformed_error); |
| 605 | 665 |
| 606 if (FLAG_trace_type_checks) { | 666 if (FLAG_trace_type_checks) { |
| 607 PrintTypeCheck("TypeCheck", src_instance, dst_type, dst_type_instantiator, | 667 PrintTypeCheck("TypeCheck", |
| 668 src_instance, dst_type, instantiator_type_arguments, |
| 608 Bool::Handle(is_instance_of ? Bool::True() : Bool::False())); | 669 Bool::Handle(is_instance_of ? Bool::True() : Bool::False())); |
| 609 } | 670 } |
| 610 if (!is_instance_of) { | 671 if (!is_instance_of) { |
| 611 String& src_type_name = String::Handle(GetSimpleTypeName(src_instance)); | 672 String& src_type_name = String::Handle(GetSimpleTypeName(src_instance)); |
| 612 String& dst_type_name = String::Handle(); | 673 String& dst_type_name = String::Handle(); |
| 613 if (!dst_type.IsInstantiated()) { | 674 if (!dst_type.IsInstantiated()) { |
| 614 // Instantiate dst_type before reporting the error. | 675 // Instantiate dst_type before reporting the error. |
| 615 const AbstractType& instantiated_dst_type = AbstractType::Handle( | 676 const AbstractType& instantiated_dst_type = AbstractType::Handle( |
| 616 dst_type.InstantiateFrom(dst_type_instantiator)); | 677 dst_type.InstantiateFrom(instantiator_type_arguments)); |
| 617 dst_type_name = instantiated_dst_type.Name(); | 678 dst_type_name = instantiated_dst_type.Name(); |
| 618 } else { | 679 } else { |
| 619 dst_type_name = dst_type.Name(); | 680 dst_type_name = dst_type.Name(); |
| 620 } | 681 } |
| 621 String& malformed_error_message = String::Handle(); | 682 String& malformed_error_message = String::Handle(); |
| 622 if (!malformed_error.IsNull()) { | 683 if (!malformed_error.IsNull()) { |
| 623 ASSERT(FLAG_enable_type_checks); | 684 ASSERT(FLAG_enable_type_checks); |
| 624 malformed_error_message = String::New(malformed_error.ToErrorCString()); | 685 malformed_error_message = String::New(malformed_error.ToErrorCString()); |
| 625 } | 686 } |
| 626 Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name, | 687 Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name, |
| 627 dst_name, malformed_error_message); | 688 dst_name, malformed_error_message); |
| 628 UNREACHABLE(); | 689 UNREACHABLE(); |
| 629 } | 690 } |
| 630 UpdateTypeTestCache(node_id, src_instance, dst_type, dst_type_instantiator, | 691 UpdateTypeTestCache(node_id, src_instance, dst_type, |
| 631 Bool::ZoneHandle(Bool::True()), cache); | 692 dst_instantiator, instantiator_type_arguments, |
| 693 Bool::ZoneHandle(Bool::True()), cache); |
| 632 arguments.SetReturn(src_instance); | 694 arguments.SetReturn(src_instance); |
| 633 } | 695 } |
| 634 | 696 |
| 635 | 697 |
| 636 // Report that the type of the given object is not bool in conditional context. | 698 // Report that the type of the given object is not bool in conditional context. |
| 637 // Arg0: index of the token of the assignment (source location). | 699 // Arg0: index of the token of the assignment (source location). |
| 638 // Arg1: bad object. | 700 // Arg1: bad object. |
| 639 // Return value: none, throws a TypeError. | 701 // Return value: none, throws a TypeError. |
| 640 DEFINE_RUNTIME_ENTRY(ConditionTypeError, 2) { | 702 DEFINE_RUNTIME_ENTRY(ConditionTypeError, 2) { |
| 641 ASSERT(arguments.Count() == | 703 ASSERT(arguments.Count() == |
| (...skipping 838 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1480 } | 1542 } |
| 1481 } | 1543 } |
| 1482 } | 1544 } |
| 1483 // The cache is null terminated, therefore the loop above should never | 1545 // The cache is null terminated, therefore the loop above should never |
| 1484 // terminate by itself. | 1546 // terminate by itself. |
| 1485 UNREACHABLE(); | 1547 UNREACHABLE(); |
| 1486 return Code::null(); | 1548 return Code::null(); |
| 1487 } | 1549 } |
| 1488 | 1550 |
| 1489 } // namespace dart | 1551 } // namespace dart |
| OLD | NEW |