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/assembler_macros.h" | 7 #include "vm/assembler_macros.h" |
8 #include "vm/ast.h" | 8 #include "vm/ast.h" |
9 #include "vm/code_patcher.h" | 9 #include "vm/code_patcher.h" |
10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 static intptr_t GetCallerLocation() { | 141 static intptr_t GetCallerLocation() { |
142 DartFrameIterator iterator; | 142 DartFrameIterator iterator; |
143 StackFrame* caller_frame = iterator.NextFrame(); | 143 StackFrame* caller_frame = iterator.NextFrame(); |
144 ASSERT(caller_frame != NULL); | 144 ASSERT(caller_frame != NULL); |
145 const Code& code = Code::Handle(caller_frame->LookupDartCode()); | 145 const Code& code = Code::Handle(caller_frame->LookupDartCode()); |
146 const PcDescriptors& descriptors = | 146 const PcDescriptors& descriptors = |
147 PcDescriptors::Handle(code.pc_descriptors()); | 147 PcDescriptors::Handle(code.pc_descriptors()); |
148 ASSERT(!descriptors.IsNull()); | 148 ASSERT(!descriptors.IsNull()); |
149 for (int i = 0; i < descriptors.Length(); i++) { | 149 for (int i = 0; i < descriptors.Length(); i++) { |
150 if (static_cast<uword>(descriptors.PC(i)) == caller_frame->pc()) { | 150 if (static_cast<uword>(descriptors.PC(i)) == caller_frame->pc()) { |
151 return descriptors.TokenIndex(i); | 151 return descriptors.TokenPos(i); |
152 } | 152 } |
153 } | 153 } |
154 return -1; | 154 return -1; |
155 } | 155 } |
156 | 156 |
157 | 157 |
158 // Allocate a new object of a generic type and check that the instantiated type | 158 // Allocate a new object of a generic type and check that the instantiated type |
159 // arguments are within the declared bounds or throw a dynamic type error. | 159 // arguments are within the declared bounds or throw a dynamic type error. |
160 // Arg0: class of the object that needs to be allocated. | 160 // Arg0: class of the object that needs to be allocated. |
161 // Arg1: type arguments of the object that needs to be allocated. | 161 // Arg1: type arguments of the object that needs to be allocated. |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
427 | 427 |
428 | 428 |
429 // This updates the type test cache, an array containing 4-value elements | 429 // This updates the type test cache, an array containing 4-value elements |
430 // (instance class, instance type arguments, instantiator type arguments and | 430 // (instance class, instance type arguments, instantiator type arguments and |
431 // test_result). It can be applied to classes with type arguments in which | 431 // test_result). It can be applied to classes with type arguments in which |
432 // case it contains just the result of the class subtype test, not including | 432 // case it contains just the result of the class subtype test, not including |
433 // the evaluation of type arguments. | 433 // the evaluation of type arguments. |
434 // This operation is currently very slow (lookup of code is not efficient yet). | 434 // This operation is currently very slow (lookup of code is not efficient yet). |
435 // 'instantiator' can be null, in which case inst_targ | 435 // 'instantiator' can be null, in which case inst_targ |
436 static void UpdateTypeTestCache( | 436 static void UpdateTypeTestCache( |
437 intptr_t node_id, | |
438 const Instance& instance, | 437 const Instance& instance, |
439 const AbstractType& type, | 438 const AbstractType& type, |
440 const Instance& instantiator, | 439 const Instance& instantiator, |
441 const AbstractTypeArguments& incoming_instantiator_type_arguments, | 440 const AbstractTypeArguments& incoming_instantiator_type_arguments, |
442 const Bool& result, | 441 const Bool& result, |
443 const SubtypeTestCache& new_cache) { | 442 const SubtypeTestCache& new_cache) { |
444 // Since the test is expensive, don't do it unless necessary. | 443 // Since the test is expensive, don't do it unless necessary. |
445 // The list of disallowed cases will decrease as they are implemented in | 444 // The list of disallowed cases will decrease as they are implemented in |
446 // inlined assembly. | 445 // inlined assembly. |
447 if (new_cache.IsNull()) return; | 446 if (new_cache.IsNull()) return; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
539 Class::Handle(test_type.type_class()).id(), | 538 Class::Handle(test_type.type_class()).id(), |
540 instantiator_type_arguments.raw(), | 539 instantiator_type_arguments.raw(), |
541 instantiator_type_arguments.ToCString(), | 540 instantiator_type_arguments.ToCString(), |
542 result.ToCString()); | 541 result.ToCString()); |
543 } | 542 } |
544 } | 543 } |
545 | 544 |
546 | 545 |
547 // Check that the given instance is an instance of the given type. | 546 // Check that the given instance is an instance of the given type. |
548 // Tested instance may not be null, because the null test is inlined. | 547 // Tested instance may not be null, because the null test is inlined. |
549 // Arg0: node id of the instanceof node. | 548 // Arg0: instance being checked. |
550 // Arg1: instance being checked. | 549 // Arg1: type. |
551 // Arg2: type. | 550 // Arg2: instantiator (or null). |
552 // Arg3: instantiator (or null). | 551 // Arg3: type arguments of the instantiator of the type. |
553 // Arg4: type arguments of the instantiator of the type. | 552 // Arg4: SubtypeTestCache. |
554 // Arg5: SubtypeTestCache. | |
555 // Return value: true or false, or may throw a type error in checked mode. | 553 // Return value: true or false, or may throw a type error in checked mode. |
556 DEFINE_RUNTIME_ENTRY(Instanceof, 6) { | 554 DEFINE_RUNTIME_ENTRY(Instanceof, 5) { |
557 ASSERT(arguments.Count() == kInstanceofRuntimeEntry.argument_count()); | 555 ASSERT(arguments.Count() == kInstanceofRuntimeEntry.argument_count()); |
558 intptr_t node_id = Smi::CheckedHandle(arguments.At(0)).Value(); | 556 const Instance& instance = Instance::CheckedHandle(arguments.At(0)); |
559 const Instance& instance = Instance::CheckedHandle(arguments.At(1)); | 557 const AbstractType& type = AbstractType::CheckedHandle(arguments.At(1)); |
560 const AbstractType& type = AbstractType::CheckedHandle(arguments.At(2)); | 558 const Instance& instantiator = Instance::CheckedHandle(arguments.At(2)); |
561 const Instance& instantiator = Instance::CheckedHandle(arguments.At(3)); | |
562 const AbstractTypeArguments& instantiator_type_arguments = | 559 const AbstractTypeArguments& instantiator_type_arguments = |
563 AbstractTypeArguments::CheckedHandle(arguments.At(4)); | 560 AbstractTypeArguments::CheckedHandle(arguments.At(3)); |
564 const SubtypeTestCache& cache = | 561 const SubtypeTestCache& cache = |
565 SubtypeTestCache::CheckedHandle(arguments.At(5)); | 562 SubtypeTestCache::CheckedHandle(arguments.At(4)); |
566 ASSERT(type.IsFinalized()); | 563 ASSERT(type.IsFinalized()); |
567 Error& malformed_error = Error::Handle(); | 564 Error& malformed_error = Error::Handle(); |
568 const Bool& result = Bool::Handle( | 565 const Bool& result = Bool::Handle( |
569 instance.IsInstanceOf(type, | 566 instance.IsInstanceOf(type, |
570 instantiator_type_arguments, | 567 instantiator_type_arguments, |
571 &malformed_error) ? | 568 &malformed_error) ? |
572 Bool::True() : Bool::False()); | 569 Bool::True() : Bool::False()); |
573 if (FLAG_trace_type_checks) { | 570 if (FLAG_trace_type_checks) { |
574 PrintTypeCheck("InstanceOf", | 571 PrintTypeCheck("InstanceOf", |
575 instance, type, instantiator_type_arguments, result); | 572 instance, type, instantiator_type_arguments, result); |
576 } | 573 } |
577 if (!result.value() && !malformed_error.IsNull()) { | 574 if (!result.value() && !malformed_error.IsNull()) { |
578 // Throw a dynamic type error only if the instanceof test fails. | 575 // Throw a dynamic type error only if the instanceof test fails. |
579 const intptr_t location = GetCallerLocation(); | 576 const intptr_t location = GetCallerLocation(); |
580 String& malformed_error_message = String::Handle( | 577 String& malformed_error_message = String::Handle( |
581 String::New(malformed_error.ToErrorCString())); | 578 String::New(malformed_error.ToErrorCString())); |
582 const String& no_name = String::Handle(Symbols::Empty()); | 579 const String& no_name = String::Handle(Symbols::Empty()); |
583 Exceptions::CreateAndThrowTypeError( | 580 Exceptions::CreateAndThrowTypeError( |
584 location, no_name, no_name, no_name, malformed_error_message); | 581 location, no_name, no_name, no_name, malformed_error_message); |
585 UNREACHABLE(); | 582 UNREACHABLE(); |
586 } | 583 } |
587 UpdateTypeTestCache(node_id, instance, type, instantiator, | 584 UpdateTypeTestCache(instance, type, instantiator, |
588 instantiator_type_arguments, result, cache); | 585 instantiator_type_arguments, result, cache); |
589 arguments.SetReturn(result); | 586 arguments.SetReturn(result); |
590 } | 587 } |
591 | 588 |
592 | 589 |
593 // Check that the type of the given instance is a subtype of the given type and | 590 // Check that the type of the given instance is a subtype of the given type and |
594 // can therefore be assigned. | 591 // can therefore be assigned. |
595 // Arg0: node-id of the assignment. | 592 // Arg0: instance being assigned. |
596 // Arg1: instance being assigned. | 593 // Arg1: type being assigned to. |
597 // Arg2: type being assigned to. | 594 // Arg2: instantiator (or null). |
598 // Arg3: instantiator (or null). | 595 // Arg3: type arguments of the instantiator of the type being assigned to. |
599 // Arg4: type arguments of the instantiator of the type being assigned to. | 596 // Arg4: name of variable being assigned to. |
600 // Arg5: name of variable being assigned to. | 597 // Arg5: SubtypeTestCache. |
601 // Arg6: SubtypeTestCache. | |
602 // Return value: instance if a subtype, otherwise throw a TypeError. | 598 // Return value: instance if a subtype, otherwise throw a TypeError. |
603 DEFINE_RUNTIME_ENTRY(TypeCheck, 7) { | 599 DEFINE_RUNTIME_ENTRY(TypeCheck, 6) { |
604 ASSERT(arguments.Count() == kTypeCheckRuntimeEntry.argument_count()); | 600 ASSERT(arguments.Count() == kTypeCheckRuntimeEntry.argument_count()); |
605 intptr_t node_id = Smi::CheckedHandle(arguments.At(0)).Value(); | 601 const Instance& src_instance = Instance::CheckedHandle(arguments.At(0)); |
606 const Instance& src_instance = Instance::CheckedHandle(arguments.At(1)); | 602 const AbstractType& dst_type = AbstractType::CheckedHandle(arguments.At(1)); |
607 const AbstractType& dst_type = AbstractType::CheckedHandle(arguments.At(2)); | 603 const Instance& dst_instantiator = Instance::CheckedHandle(arguments.At(2)); |
608 const Instance& dst_instantiator = Instance::CheckedHandle(arguments.At(3)); | |
609 const AbstractTypeArguments& instantiator_type_arguments = | 604 const AbstractTypeArguments& instantiator_type_arguments = |
610 AbstractTypeArguments::CheckedHandle(arguments.At(4)); | 605 AbstractTypeArguments::CheckedHandle(arguments.At(3)); |
611 const String& dst_name = String::CheckedHandle(arguments.At(5)); | 606 const String& dst_name = String::CheckedHandle(arguments.At(4)); |
612 const SubtypeTestCache& cache = | 607 const SubtypeTestCache& cache = |
613 SubtypeTestCache::CheckedHandle(arguments.At(6)); | 608 SubtypeTestCache::CheckedHandle(arguments.At(5)); |
614 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment. | 609 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment. |
615 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator. | 610 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator. |
616 ASSERT(!src_instance.IsNull()); // Already checked in inlined code. | 611 ASSERT(!src_instance.IsNull()); // Already checked in inlined code. |
617 | 612 |
618 Error& malformed_error = Error::Handle(); | 613 Error& malformed_error = Error::Handle(); |
619 const bool is_instance_of = src_instance.IsInstanceOf( | 614 const bool is_instance_of = src_instance.IsInstanceOf( |
620 dst_type, instantiator_type_arguments, &malformed_error); | 615 dst_type, instantiator_type_arguments, &malformed_error); |
621 | 616 |
622 if (FLAG_trace_type_checks) { | 617 if (FLAG_trace_type_checks) { |
623 PrintTypeCheck("TypeCheck", | 618 PrintTypeCheck("TypeCheck", |
(...skipping 16 matching lines...) Expand all Loading... |
640 } | 635 } |
641 String& malformed_error_message = String::Handle(); | 636 String& malformed_error_message = String::Handle(); |
642 if (!malformed_error.IsNull()) { | 637 if (!malformed_error.IsNull()) { |
643 ASSERT(FLAG_enable_type_checks); | 638 ASSERT(FLAG_enable_type_checks); |
644 malformed_error_message = String::New(malformed_error.ToErrorCString()); | 639 malformed_error_message = String::New(malformed_error.ToErrorCString()); |
645 } | 640 } |
646 Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name, | 641 Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name, |
647 dst_name, malformed_error_message); | 642 dst_name, malformed_error_message); |
648 UNREACHABLE(); | 643 UNREACHABLE(); |
649 } | 644 } |
650 UpdateTypeTestCache(node_id, src_instance, dst_type, | 645 UpdateTypeTestCache(src_instance, dst_type, |
651 dst_instantiator, instantiator_type_arguments, | 646 dst_instantiator, instantiator_type_arguments, |
652 Bool::ZoneHandle(Bool::True()), cache); | 647 Bool::ZoneHandle(Bool::True()), cache); |
653 arguments.SetReturn(src_instance); | 648 arguments.SetReturn(src_instance); |
654 } | 649 } |
655 | 650 |
656 | 651 |
657 // Report that the type of the given object is not bool in conditional context. | 652 // Report that the type of the given object is not bool in conditional context. |
658 // Arg0: bad object. | 653 // Arg0: bad object. |
659 // Return value: none, throws a TypeError. | 654 // Return value: none, throws a TypeError. |
660 DEFINE_RUNTIME_ENTRY(ConditionTypeError, 1) { | 655 DEFINE_RUNTIME_ENTRY(ConditionTypeError, 1) { |
(...skipping 733 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1394 } | 1389 } |
1395 | 1390 |
1396 | 1391 |
1397 static intptr_t GetDeoptInfo(const Code& code, uword pc) { | 1392 static intptr_t GetDeoptInfo(const Code& code, uword pc) { |
1398 const PcDescriptors& descriptors = | 1393 const PcDescriptors& descriptors = |
1399 PcDescriptors::Handle(code.pc_descriptors()); | 1394 PcDescriptors::Handle(code.pc_descriptors()); |
1400 ASSERT(!descriptors.IsNull()); | 1395 ASSERT(!descriptors.IsNull()); |
1401 // Locate deopt id at deoptimization point inside optimized code. | 1396 // Locate deopt id at deoptimization point inside optimized code. |
1402 for (int i = 0; i < descriptors.Length(); i++) { | 1397 for (int i = 0; i < descriptors.Length(); i++) { |
1403 if (static_cast<uword>(descriptors.PC(i)) == pc) { | 1398 if (static_cast<uword>(descriptors.PC(i)) == pc) { |
1404 return descriptors.NodeId(i); | 1399 return descriptors.DeoptId(i); |
1405 } | 1400 } |
1406 } | 1401 } |
1407 return Computation::kNoCid; | 1402 return Isolate::kNoDeoptId; |
1408 } | 1403 } |
1409 | 1404 |
1410 | 1405 |
1411 // Copy saved registers and caller's frame into temporary buffers. | 1406 // Copy saved registers and caller's frame into temporary buffers. |
1412 // Access the deopt information for the deoptimization point. | 1407 // Access the deopt information for the deoptimization point. |
1413 // Return the new stack size (including PC marker and deopt return address, | 1408 // Return the new stack size (including PC marker and deopt return address, |
1414 // excluding FP). | 1409 // excluding FP). |
1415 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, | 1410 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, |
1416 intptr_t deopt_reason, | 1411 intptr_t deopt_reason, |
1417 intptr_t* saved_registers_address) { | 1412 intptr_t* saved_registers_address) { |
(...skipping 13 matching lines...) Expand all Loading... |
1431 } | 1426 } |
1432 isolate->set_deopt_registers_copy(registers_copy); | 1427 isolate->set_deopt_registers_copy(registers_copy); |
1433 ASSERT(reinterpret_cast<uword>(saved_registers_address) == last_fp); | 1428 ASSERT(reinterpret_cast<uword>(saved_registers_address) == last_fp); |
1434 DartFrameIterator iterator(last_fp); | 1429 DartFrameIterator iterator(last_fp); |
1435 StackFrame* caller_frame = iterator.NextFrame(); | 1430 StackFrame* caller_frame = iterator.NextFrame(); |
1436 ASSERT(caller_frame != NULL); | 1431 ASSERT(caller_frame != NULL); |
1437 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); | 1432 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); |
1438 ASSERT(optimized_code.is_optimized()); | 1433 ASSERT(optimized_code.is_optimized()); |
1439 | 1434 |
1440 const intptr_t deopt_id = GetDeoptInfo(optimized_code, caller_frame->pc()); | 1435 const intptr_t deopt_id = GetDeoptInfo(optimized_code, caller_frame->pc()); |
1441 ASSERT(deopt_id != Computation::kNoCid); | 1436 ASSERT(deopt_id != Isolate::kNoDeoptId); |
1442 | 1437 |
1443 // Add incoming arguments. | 1438 // Add incoming arguments. |
1444 const Function& function = Function::Handle(optimized_code.function()); | 1439 const Function& function = Function::Handle(optimized_code.function()); |
1445 // Think of copied arguments. | 1440 // Think of copied arguments. |
1446 const intptr_t num_args = (function.num_optional_parameters() > 0) ? | 1441 const intptr_t num_args = (function.num_optional_parameters() > 0) ? |
1447 0 : function.num_fixed_parameters(); | 1442 0 : function.num_fixed_parameters(); |
1448 // FP, PC marker and return address will all be copied. | 1443 // FP, PC marker and return address will all be copied. |
1449 const intptr_t frame_copy_size = | 1444 const intptr_t frame_copy_size = |
1450 1 // Deoptimized function's return address: caller_frame->pc(). | 1445 1 // Deoptimized function's return address: caller_frame->pc(). |
1451 + ((caller_frame->fp() - caller_frame->sp()) / kWordSize) | 1446 + ((caller_frame->fp() - caller_frame->sp()) / kWordSize) |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1491 const Function& function = Function::Handle(optimized_code.function()); | 1486 const Function& function = Function::Handle(optimized_code.function()); |
1492 ASSERT(!function.IsNull()); | 1487 ASSERT(!function.IsNull()); |
1493 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); | 1488 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); |
1494 ASSERT(!optimized_code.IsNull() && optimized_code.is_optimized()); | 1489 ASSERT(!optimized_code.IsNull() && optimized_code.is_optimized()); |
1495 ASSERT(!unoptimized_code.IsNull() && !unoptimized_code.is_optimized()); | 1490 ASSERT(!unoptimized_code.IsNull() && !unoptimized_code.is_optimized()); |
1496 | 1491 |
1497 intptr_t* frame_copy = isolate->deopt_frame_copy(); | 1492 intptr_t* frame_copy = isolate->deopt_frame_copy(); |
1498 intptr_t* registers_copy = isolate->deopt_registers_copy(); | 1493 intptr_t* registers_copy = isolate->deopt_registers_copy(); |
1499 | 1494 |
1500 intptr_t deopt_id = GetDeoptInfo(optimized_code, caller_frame->pc()); | 1495 intptr_t deopt_id = GetDeoptInfo(optimized_code, caller_frame->pc()); |
1501 ASSERT(deopt_id != Computation::kNoCid); | 1496 ASSERT(deopt_id != Isolate::kNoDeoptId); |
1502 uword continue_at_pc = unoptimized_code.GetDeoptPcAtNodeId(deopt_id); | 1497 uword continue_at_pc = unoptimized_code.GetDeoptPcAtDeoptId(deopt_id); |
1503 if (FLAG_trace_deopt) { | 1498 if (FLAG_trace_deopt) { |
1504 OS::Print(" -> continue at 0x%x\n", continue_at_pc); | 1499 OS::Print(" -> continue at 0x%x\n", continue_at_pc); |
1505 // TODO(srdjan): If we could allow GC, we could print the line where | 1500 // TODO(srdjan): If we could allow GC, we could print the line where |
1506 // deoptimization occured. | 1501 // deoptimization occured. |
1507 } | 1502 } |
1508 const intptr_t deopt_frame_copy_size = isolate->deopt_frame_copy_size(); | 1503 const intptr_t deopt_frame_copy_size = isolate->deopt_frame_copy_size(); |
1509 // TODO(srdjan): Use deopt info to copy the values to right place. | 1504 // TODO(srdjan): Use deopt info to copy the values to right place. |
1510 const intptr_t pc_marker_index = | 1505 const intptr_t pc_marker_index = |
1511 ((caller_frame->fp() - caller_frame->sp()) / kWordSize); | 1506 ((caller_frame->fp() - caller_frame->sp()) / kWordSize); |
1512 // Patch the return PC and saved PC marker in frame to point to the | 1507 // Patch the return PC and saved PC marker in frame to point to the |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1616 } | 1611 } |
1617 } | 1612 } |
1618 } | 1613 } |
1619 // The cache is null terminated, therefore the loop above should never | 1614 // The cache is null terminated, therefore the loop above should never |
1620 // terminate by itself. | 1615 // terminate by itself. |
1621 UNREACHABLE(); | 1616 UNREACHABLE(); |
1622 return Code::null(); | 1617 return Code::null(); |
1623 } | 1618 } |
1624 | 1619 |
1625 } // namespace dart | 1620 } // namespace dart |
OLD | NEW |