Chromium Code Reviews| 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/object.h" | 5 #include "vm/object.h" |
| 6 | 6 |
| 7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
| 8 #include "platform/assert.h" | 8 #include "platform/assert.h" |
| 9 #include "vm/assembler.h" | 9 #include "vm/assembler.h" |
| 10 #include "vm/become.h" | 10 #include "vm/become.h" |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 45 #include "vm/thread_registry.h" | 45 #include "vm/thread_registry.h" |
| 46 #include "vm/timeline.h" | 46 #include "vm/timeline.h" |
| 47 #include "vm/timer.h" | 47 #include "vm/timer.h" |
| 48 #include "vm/type_table.h" | 48 #include "vm/type_table.h" |
| 49 #include "vm/unicode.h" | 49 #include "vm/unicode.h" |
| 50 #include "vm/weak_code.h" | 50 #include "vm/weak_code.h" |
| 51 #include "vm/zone_text_buffer.h" | 51 #include "vm/zone_text_buffer.h" |
| 52 | 52 |
| 53 namespace dart { | 53 namespace dart { |
| 54 | 54 |
| 55 DEFINE_FLAG(bool, | |
|
zra
2017/04/20 19:22:09
Should we put this in flag_list.h?
regis
2017/04/20 20:23:30
Done.
| |
| 56 reify_generic_functions, | |
| 57 false, | |
| 58 "Enable reification of generic functions (not yet supported)."); | |
| 55 DEFINE_FLAG(int, | 59 DEFINE_FLAG(int, |
| 56 huge_method_cutoff_in_code_size, | 60 huge_method_cutoff_in_code_size, |
| 57 200000, | 61 200000, |
| 58 "Huge method cutoff in unoptimized code size (in bytes)."); | 62 "Huge method cutoff in unoptimized code size (in bytes)."); |
| 59 DEFINE_FLAG( | 63 DEFINE_FLAG( |
| 60 bool, | 64 bool, |
| 61 overlap_type_arguments, | 65 overlap_type_arguments, |
| 62 true, | 66 true, |
| 63 "When possible, partially or fully overlap the type arguments of a type " | 67 "When possible, partially or fully overlap the type arguments of a type " |
| 64 "with the type arguments of its super type."); | 68 "with the type arguments of its super type."); |
| (...skipping 6360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6425 return chars; | 6429 return chars; |
| 6426 } | 6430 } |
| 6427 | 6431 |
| 6428 | 6432 |
| 6429 bool Function::HasCompatibleParametersWith(const Function& other, | 6433 bool Function::HasCompatibleParametersWith(const Function& other, |
| 6430 Error* bound_error) const { | 6434 Error* bound_error) const { |
| 6431 ASSERT(Isolate::Current()->error_on_bad_override()); | 6435 ASSERT(Isolate::Current()->error_on_bad_override()); |
| 6432 ASSERT((bound_error != NULL) && bound_error->IsNull()); | 6436 ASSERT((bound_error != NULL) && bound_error->IsNull()); |
| 6433 // Check that this function's signature type is a subtype of the other | 6437 // Check that this function's signature type is a subtype of the other |
| 6434 // function's signature type. | 6438 // function's signature type. |
| 6435 // Map type parameters in the signature to dynamic before the test. | 6439 // Map type parameters referred to by formal parameter types and result type |
| 6440 // in the signature to dynamic before the test. | |
| 6441 // Note that type parameters declared by a generic signature are preserved. | |
| 6436 Function& this_fun = Function::Handle(raw()); | 6442 Function& this_fun = Function::Handle(raw()); |
| 6437 if (!this_fun.HasInstantiatedSignature()) { | 6443 if (!this_fun.HasInstantiatedSignature()) { |
| 6438 // TODO(regis): Should we pass the context explicitly here (i.e. null) once | |
| 6439 // we support generic functions? | |
| 6440 this_fun = this_fun.InstantiateSignatureFrom(Object::null_type_arguments(), | 6444 this_fun = this_fun.InstantiateSignatureFrom(Object::null_type_arguments(), |
| 6441 Object::null_type_arguments(), | 6445 Object::null_type_arguments(), |
| 6442 Heap::kOld); | 6446 Heap::kOld); |
| 6443 } | 6447 } |
| 6444 Function& other_fun = Function::Handle(other.raw()); | 6448 Function& other_fun = Function::Handle(other.raw()); |
| 6445 if (!other_fun.HasInstantiatedSignature()) { | 6449 if (!other_fun.HasInstantiatedSignature()) { |
| 6446 // TODO(regis): Should we pass the context explicitly here (i.e. null) once | |
| 6447 // we support generic functions? | |
| 6448 other_fun = other_fun.InstantiateSignatureFrom( | 6450 other_fun = other_fun.InstantiateSignatureFrom( |
| 6449 Object::null_type_arguments(), Object::null_type_arguments(), | 6451 Object::null_type_arguments(), Object::null_type_arguments(), |
| 6450 Heap::kOld); | 6452 Heap::kOld); |
| 6451 } | 6453 } |
| 6452 if (!this_fun.TypeTest(kIsSubtypeOf, other_fun, bound_error, Heap::kOld)) { | 6454 if (!this_fun.TypeTest(kIsSubtypeOf, other_fun, bound_error, Heap::kOld)) { |
| 6453 // For more informative error reporting, use the location of the other | 6455 // For more informative error reporting, use the location of the other |
| 6454 // function here, since the caller will use the location of this function. | 6456 // function here, since the caller will use the location of this function. |
| 6455 *bound_error = LanguageError::NewFormatted( | 6457 *bound_error = LanguageError::NewFormatted( |
| 6456 *bound_error, // A bound error if non null. | 6458 *bound_error, // A bound error if non null. |
| 6457 Script::Handle(other.script()), other.token_pos(), Report::AtLocation, | 6459 Script::Handle(other.script()), other.token_pos(), Report::AtLocation, |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 6477 RawFunction* Function::InstantiateSignatureFrom( | 6479 RawFunction* Function::InstantiateSignatureFrom( |
| 6478 const TypeArguments& instantiator_type_arguments, | 6480 const TypeArguments& instantiator_type_arguments, |
| 6479 const TypeArguments& function_type_arguments, | 6481 const TypeArguments& function_type_arguments, |
| 6480 Heap::Space space) const { | 6482 Heap::Space space) const { |
| 6481 Zone* zone = Thread::Current()->zone(); | 6483 Zone* zone = Thread::Current()->zone(); |
| 6482 const Object& owner = Object::Handle(zone, RawOwner()); | 6484 const Object& owner = Object::Handle(zone, RawOwner()); |
| 6483 ASSERT(!HasInstantiatedSignature()); | 6485 ASSERT(!HasInstantiatedSignature()); |
| 6484 Function& sig = Function::Handle( | 6486 Function& sig = Function::Handle( |
| 6485 zone, | 6487 zone, |
| 6486 Function::NewSignatureFunction(owner, TokenPosition::kNoSource, space)); | 6488 Function::NewSignatureFunction(owner, TokenPosition::kNoSource, space)); |
| 6487 // TODO(regis): If type parameter bounds are not IsInstantiated(kFunctions), | |
| 6488 // clone finalized type parameters and instantiate bounds. | |
| 6489 sig.set_type_parameters(TypeArguments::Handle(zone, type_parameters())); | 6489 sig.set_type_parameters(TypeArguments::Handle(zone, type_parameters())); |
| 6490 AbstractType& type = AbstractType::Handle(zone, result_type()); | 6490 AbstractType& type = AbstractType::Handle(zone, result_type()); |
| 6491 if (!type.IsInstantiated()) { | 6491 if (!type.IsInstantiated()) { |
| 6492 type = | 6492 type = |
| 6493 type.InstantiateFrom(instantiator_type_arguments, | 6493 type.InstantiateFrom(instantiator_type_arguments, |
| 6494 function_type_arguments, NULL, NULL, NULL, space); | 6494 function_type_arguments, NULL, NULL, NULL, space); |
| 6495 } | 6495 } |
| 6496 sig.set_result_type(type); | 6496 sig.set_result_type(type); |
| 6497 const intptr_t num_params = NumParameters(); | 6497 const intptr_t num_params = NumParameters(); |
| 6498 sig.set_num_fixed_parameters(num_fixed_parameters()); | 6498 sig.set_num_fixed_parameters(num_fixed_parameters()); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6570 const intptr_t num_ignored_params = NumImplicitParameters(); | 6570 const intptr_t num_ignored_params = NumImplicitParameters(); |
| 6571 const intptr_t other_num_ignored_params = other.NumImplicitParameters(); | 6571 const intptr_t other_num_ignored_params = other.NumImplicitParameters(); |
| 6572 if (((num_fixed_params - num_ignored_params) > | 6572 if (((num_fixed_params - num_ignored_params) > |
| 6573 (other_num_fixed_params - other_num_ignored_params)) || | 6573 (other_num_fixed_params - other_num_ignored_params)) || |
| 6574 ((num_fixed_params - num_ignored_params + num_opt_pos_params) < | 6574 ((num_fixed_params - num_ignored_params + num_opt_pos_params) < |
| 6575 (other_num_fixed_params - other_num_ignored_params + | 6575 (other_num_fixed_params - other_num_ignored_params + |
| 6576 other_num_opt_pos_params)) || | 6576 other_num_opt_pos_params)) || |
| 6577 (num_opt_named_params < other_num_opt_named_params)) { | 6577 (num_opt_named_params < other_num_opt_named_params)) { |
| 6578 return false; | 6578 return false; |
| 6579 } | 6579 } |
| 6580 | 6580 Thread* thread = Thread::Current(); |
| 6581 // TODO(regis): Check the type parameters and bounds of a generic function. | 6581 Zone* zone = thread->zone(); |
| 6582 | 6582 if (FLAG_reify_generic_functions) { |
| 6583 // Check the type parameters and bounds of a generic function. | |
| 6584 const intptr_t num_type_params = NumTypeParameters(thread); | |
| 6585 if (num_type_params != other.NumTypeParameters(thread)) { | |
| 6586 return false; | |
| 6587 } | |
| 6588 if (num_type_params > 0) { | |
| 6589 const TypeArguments& type_params = | |
| 6590 TypeArguments::Handle(zone, type_parameters()); | |
| 6591 ASSERT(!type_params.IsNull()); | |
| 6592 const TypeArguments& other_type_params = | |
| 6593 TypeArguments::Handle(zone, other.type_parameters()); | |
| 6594 ASSERT(!other_type_params.IsNull()); | |
| 6595 TypeParameter& type_param = TypeParameter::Handle(zone); | |
| 6596 TypeParameter& other_type_param = TypeParameter::Handle(zone); | |
| 6597 AbstractType& bound = AbstractType::Handle(zone); | |
| 6598 AbstractType& other_bound = AbstractType::Handle(zone); | |
| 6599 for (intptr_t i = 0; i < num_type_params; i++) { | |
| 6600 type_param ^= type_params.TypeAt(i); | |
| 6601 other_type_param ^= other_type_params.TypeAt(i); | |
| 6602 bound = type_param.bound(); | |
| 6603 other_bound = other_type_param.bound(); | |
|
siva
2017/04/20 20:32:08
Should we assert here that the two types are final
regis
2017/04/20 21:18:26
The Equals call should do the right thing in case
| |
| 6604 if (!bound.Equals(other_bound)) { | |
| 6605 return false; | |
| 6606 } | |
| 6607 } | |
| 6608 } | |
| 6609 } | |
| 6583 // Check the result type. | 6610 // Check the result type. |
| 6584 const AbstractType& other_res_type = | 6611 const AbstractType& other_res_type = |
| 6585 AbstractType::Handle(other.result_type()); | 6612 AbstractType::Handle(zone, other.result_type()); |
| 6586 if (!other_res_type.IsDynamicType() && !other_res_type.IsVoidType()) { | 6613 if (!other_res_type.IsDynamicType() && !other_res_type.IsVoidType()) { |
| 6587 const AbstractType& res_type = AbstractType::Handle(result_type()); | 6614 const AbstractType& res_type = AbstractType::Handle(zone, result_type()); |
| 6588 if (res_type.IsVoidType()) { | 6615 if (res_type.IsVoidType()) { |
| 6589 return false; | 6616 return false; |
| 6590 } | 6617 } |
| 6591 if (test_kind == kIsSubtypeOf) { | 6618 if (test_kind == kIsSubtypeOf) { |
| 6592 if (!res_type.IsSubtypeOf(other_res_type, bound_error, NULL, space) && | 6619 if (!res_type.IsSubtypeOf(other_res_type, bound_error, NULL, space) && |
| 6593 !other_res_type.IsSubtypeOf(res_type, bound_error, NULL, space)) { | 6620 !other_res_type.IsSubtypeOf(res_type, bound_error, NULL, space)) { |
| 6594 return false; | 6621 return false; |
| 6595 } | 6622 } |
| 6596 } else { | 6623 } else { |
| 6597 ASSERT(test_kind == kIsMoreSpecificThan); | 6624 ASSERT(test_kind == kIsMoreSpecificThan); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 6619 // function type, there exists an optional named parameter of this function | 6646 // function type, there exists an optional named parameter of this function |
| 6620 // type with an identical name and with a type S that is a either a subtype | 6647 // type with an identical name and with a type S that is a either a subtype |
| 6621 // or supertype of T (if test_kind == kIsSubtypeOf) or that is more specific | 6648 // or supertype of T (if test_kind == kIsSubtypeOf) or that is more specific |
| 6622 // than T (if test_kind == kIsMoreSpecificThan). | 6649 // than T (if test_kind == kIsMoreSpecificThan). |
| 6623 // Note that SetParameterNameAt() guarantees that names are symbols, so we | 6650 // Note that SetParameterNameAt() guarantees that names are symbols, so we |
| 6624 // can compare their raw pointers. | 6651 // can compare their raw pointers. |
| 6625 const int num_params = num_fixed_params + num_opt_named_params; | 6652 const int num_params = num_fixed_params + num_opt_named_params; |
| 6626 const int other_num_params = | 6653 const int other_num_params = |
| 6627 other_num_fixed_params + other_num_opt_named_params; | 6654 other_num_fixed_params + other_num_opt_named_params; |
| 6628 bool found_param_name; | 6655 bool found_param_name; |
| 6629 String& other_param_name = String::Handle(); | 6656 String& other_param_name = String::Handle(zone); |
| 6630 for (intptr_t i = other_num_fixed_params; i < other_num_params; i++) { | 6657 for (intptr_t i = other_num_fixed_params; i < other_num_params; i++) { |
| 6631 other_param_name = other.ParameterNameAt(i); | 6658 other_param_name = other.ParameterNameAt(i); |
| 6632 ASSERT(other_param_name.IsSymbol()); | 6659 ASSERT(other_param_name.IsSymbol()); |
| 6633 found_param_name = false; | 6660 found_param_name = false; |
| 6634 for (intptr_t j = num_fixed_params; j < num_params; j++) { | 6661 for (intptr_t j = num_fixed_params; j < num_params; j++) { |
| 6635 ASSERT(String::Handle(ParameterNameAt(j)).IsSymbol()); | 6662 ASSERT(String::Handle(zone, ParameterNameAt(j)).IsSymbol()); |
| 6636 if (ParameterNameAt(j) == other_param_name.raw()) { | 6663 if (ParameterNameAt(j) == other_param_name.raw()) { |
| 6637 found_param_name = true; | 6664 found_param_name = true; |
| 6638 if (!TestParameterType(test_kind, j, i, other, bound_error, space)) { | 6665 if (!TestParameterType(test_kind, j, i, other, bound_error, space)) { |
| 6639 return false; | 6666 return false; |
| 6640 } | 6667 } |
| 6641 break; | 6668 break; |
| 6642 } | 6669 } |
| 6643 } | 6670 } |
| 6644 if (!found_param_name) { | 6671 if (!found_param_name) { |
| 6645 return false; | 6672 return false; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6755 // Functions other than signature functions have no reason to be allocated | 6782 // Functions other than signature functions have no reason to be allocated |
| 6756 // in new space. | 6783 // in new space. |
| 6757 ASSERT(space == Heap::kOld); | 6784 ASSERT(space == Heap::kOld); |
| 6758 } | 6785 } |
| 6759 return result.raw(); | 6786 return result.raw(); |
| 6760 } | 6787 } |
| 6761 | 6788 |
| 6762 | 6789 |
| 6763 RawFunction* Function::Clone(const Class& new_owner) const { | 6790 RawFunction* Function::Clone(const Class& new_owner) const { |
| 6764 ASSERT(!IsGenerativeConstructor()); | 6791 ASSERT(!IsGenerativeConstructor()); |
| 6765 Function& clone = Function::Handle(); | 6792 Thread* thread = Thread::Current(); |
| 6793 Zone* zone = thread->zone(); | |
| 6794 Function& clone = Function::Handle(zone); | |
| 6766 clone ^= Object::Clone(*this, Heap::kOld); | 6795 clone ^= Object::Clone(*this, Heap::kOld); |
| 6767 const Class& origin = Class::Handle(this->origin()); | 6796 const Class& origin = Class::Handle(zone, this->origin()); |
| 6768 const PatchClass& clone_owner = | 6797 const PatchClass& clone_owner = |
| 6769 PatchClass::Handle(PatchClass::New(new_owner, origin)); | 6798 PatchClass::Handle(zone, PatchClass::New(new_owner, origin)); |
| 6770 clone.set_owner(clone_owner); | 6799 clone.set_owner(clone_owner); |
| 6771 clone.ClearICDataArray(); | 6800 clone.ClearICDataArray(); |
| 6772 clone.ClearCode(); | 6801 clone.ClearCode(); |
| 6773 clone.set_usage_counter(0); | 6802 clone.set_usage_counter(0); |
| 6774 clone.set_deoptimization_counter(0); | 6803 clone.set_deoptimization_counter(0); |
| 6775 clone.set_optimized_instruction_count(0); | 6804 clone.set_optimized_instruction_count(0); |
| 6776 clone.set_optimized_call_site_count(0); | 6805 clone.set_optimized_call_site_count(0); |
| 6777 clone.set_kernel_function(kernel_function()); | 6806 clone.set_kernel_function(kernel_function()); |
| 6778 // TODO(regis): Clone function type parameters (their bounds may change). | |
| 6779 if (new_owner.NumTypeParameters() > 0) { | 6807 if (new_owner.NumTypeParameters() > 0) { |
| 6780 // Adjust uninstantiated types to refer to type parameters of the new owner. | 6808 // Adjust uninstantiated types to refer to type parameters of the new owner. |
| 6781 AbstractType& type = AbstractType::Handle(clone.result_type()); | 6809 const TypeArguments& type_params = |
| 6810 TypeArguments::Handle(zone, type_parameters()); | |
| 6811 if (!type_params.IsNull()) { | |
| 6812 const intptr_t num_type_params = type_params.Length(); | |
| 6813 const TypeArguments& type_params_clone = | |
| 6814 TypeArguments::Handle(zone, TypeArguments::New(num_type_params)); | |
| 6815 TypeParameter& type_param = TypeParameter::Handle(zone); | |
| 6816 for (intptr_t i = 0; i < num_type_params; i++) { | |
| 6817 type_param ^= type_params.TypeAt(i); | |
| 6818 type_param ^= type_param.CloneUninstantiated(new_owner); | |
| 6819 type_params_clone.SetTypeAt(i, type_param); | |
| 6820 } | |
| 6821 clone.set_type_parameters(type_params_clone); | |
| 6822 } | |
| 6823 AbstractType& type = AbstractType::Handle(zone, clone.result_type()); | |
| 6782 type ^= type.CloneUninstantiated(new_owner); | 6824 type ^= type.CloneUninstantiated(new_owner); |
| 6783 clone.set_result_type(type); | 6825 clone.set_result_type(type); |
| 6784 const intptr_t num_params = clone.NumParameters(); | 6826 const intptr_t num_params = clone.NumParameters(); |
| 6785 Array& array = Array::Handle(clone.parameter_types()); | 6827 Array& array = Array::Handle(zone, clone.parameter_types()); |
| 6786 array ^= Object::Clone(array, Heap::kOld); | 6828 array ^= Object::Clone(array, Heap::kOld); |
| 6787 clone.set_parameter_types(array); | 6829 clone.set_parameter_types(array); |
| 6788 for (intptr_t i = 0; i < num_params; i++) { | 6830 for (intptr_t i = 0; i < num_params; i++) { |
| 6789 type = clone.ParameterTypeAt(i); | 6831 type = clone.ParameterTypeAt(i); |
| 6790 type ^= type.CloneUninstantiated(new_owner); | 6832 type ^= type.CloneUninstantiated(new_owner); |
| 6791 clone.SetParameterTypeAt(i, type); | 6833 clone.SetParameterTypeAt(i, type); |
| 6792 } | 6834 } |
| 6793 } | 6835 } |
| 6794 return clone.raw(); | 6836 return clone.raw(); |
| 6795 } | 6837 } |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6853 return result.raw(); | 6895 return result.raw(); |
| 6854 } | 6896 } |
| 6855 | 6897 |
| 6856 RawFunction* Function::ImplicitClosureFunction() const { | 6898 RawFunction* Function::ImplicitClosureFunction() const { |
| 6857 // Return the existing implicit closure function if any. | 6899 // Return the existing implicit closure function if any. |
| 6858 if (implicit_closure_function() != Function::null()) { | 6900 if (implicit_closure_function() != Function::null()) { |
| 6859 return implicit_closure_function(); | 6901 return implicit_closure_function(); |
| 6860 } | 6902 } |
| 6861 ASSERT(!IsSignatureFunction() && !IsClosureFunction()); | 6903 ASSERT(!IsSignatureFunction() && !IsClosureFunction()); |
| 6862 // Create closure function. | 6904 // Create closure function. |
| 6863 const String& closure_name = String::Handle(name()); | 6905 const String& closure_name = String::Handle(name()); |
|
zra
2017/04/20 19:22:09
Maybe grab the Zone ahead of time for this functio
regis
2017/04/20 20:23:30
Done.
| |
| 6864 const Function& closure_function = | 6906 const Function& closure_function = |
| 6865 Function::Handle(NewClosureFunction(closure_name, *this, token_pos())); | 6907 Function::Handle(NewClosureFunction(closure_name, *this, token_pos())); |
| 6866 | 6908 |
| 6867 // Set closure function's context scope. | 6909 // Set closure function's context scope. |
| 6868 if (is_static()) { | 6910 if (is_static()) { |
| 6869 closure_function.set_context_scope(Object::empty_context_scope()); | 6911 closure_function.set_context_scope(Object::empty_context_scope()); |
| 6870 } else { | 6912 } else { |
| 6871 const ContextScope& context_scope = | 6913 const ContextScope& context_scope = |
| 6872 ContextScope::Handle(LocalScope::CreateImplicitClosureScope(*this)); | 6914 ContextScope::Handle(LocalScope::CreateImplicitClosureScope(*this)); |
| 6873 closure_function.set_context_scope(context_scope); | 6915 closure_function.set_context_scope(context_scope); |
| 6874 } | 6916 } |
| 6875 | 6917 |
| 6918 // Set closure function's type parameters. | |
| 6919 closure_function.set_type_parameters( | |
| 6920 TypeArguments::Handle(type_parameters())); | |
| 6921 | |
| 6876 // Set closure function's result type to this result type. | 6922 // Set closure function's result type to this result type. |
| 6877 closure_function.set_result_type(AbstractType::Handle(result_type())); | 6923 closure_function.set_result_type(AbstractType::Handle(result_type())); |
| 6878 | 6924 |
| 6879 // Set closure function's end token to this end token. | 6925 // Set closure function's end token to this end token. |
| 6880 closure_function.set_end_token_pos(end_token_pos()); | 6926 closure_function.set_end_token_pos(end_token_pos()); |
| 6881 | 6927 |
| 6882 // The closurized method stub just calls into the original method and should | 6928 // The closurized method stub just calls into the original method and should |
| 6883 // therefore be skipped by the debugger and in stack traces. | 6929 // therefore be skipped by the debugger and in stack traces. |
| 6884 closure_function.set_is_debuggable(false); | 6930 closure_function.set_is_debuggable(false); |
| 6885 closure_function.set_is_visible(false); | 6931 closure_function.set_is_visible(false); |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7058 result &= ((static_cast<intptr_t>(1) << String::kHashBits) - 1); | 7104 result &= ((static_cast<intptr_t>(1) << String::kHashBits) - 1); |
| 7059 ClosureData::Cast(obj).set_hash(result); | 7105 ClosureData::Cast(obj).set_hash(result); |
| 7060 return Smi::New(result); | 7106 return Smi::New(result); |
| 7061 } | 7107 } |
| 7062 | 7108 |
| 7063 | 7109 |
| 7064 RawString* Function::BuildSignature(NameVisibility name_visibility) const { | 7110 RawString* Function::BuildSignature(NameVisibility name_visibility) const { |
| 7065 Thread* thread = Thread::Current(); | 7111 Thread* thread = Thread::Current(); |
| 7066 Zone* zone = thread->zone(); | 7112 Zone* zone = thread->zone(); |
| 7067 GrowableHandlePtrArray<const String> pieces(zone, 4); | 7113 GrowableHandlePtrArray<const String> pieces(zone, 4); |
| 7114 String& name = String::Handle(zone); | |
| 7115 if (FLAG_reify_generic_functions) { | |
| 7116 const TypeArguments& type_params = | |
| 7117 TypeArguments::Handle(zone, type_parameters()); | |
| 7118 if (!type_params.IsNull()) { | |
| 7119 const intptr_t num_type_params = type_params.Length(); | |
| 7120 TypeParameter& type_param = TypeParameter::Handle(zone); | |
| 7121 AbstractType& bound = AbstractType::Handle(zone); | |
| 7122 pieces.Add(Symbols::LAngleBracket()); | |
| 7123 for (intptr_t i = 0; i < num_type_params; i++) { | |
| 7124 type_param ^= type_params.TypeAt(i); | |
| 7125 name = type_param.name(); | |
| 7126 pieces.Add(name); | |
| 7127 bound = type_param.bound(); | |
| 7128 if (!bound.IsNull() && !bound.IsObjectType()) { | |
| 7129 pieces.Add(Symbols::SpaceExtendsSpace()); | |
| 7130 name = bound.BuildName(name_visibility); | |
| 7131 pieces.Add(name); | |
| 7132 } | |
| 7133 if (i < num_type_params - 1) { | |
| 7134 pieces.Add(Symbols::CommaSpace()); | |
| 7135 } | |
| 7136 } | |
| 7137 pieces.Add(Symbols::RAngleBracket()); | |
|
siva
2017/04/20 20:32:08
Do we still want '<>' if num_type_params is 0? or
regis
2017/04/20 21:18:26
Yes, we should never see an empty array. I added a
| |
| 7138 } | |
| 7139 } | |
| 7068 pieces.Add(Symbols::LParen()); | 7140 pieces.Add(Symbols::LParen()); |
| 7069 BuildSignatureParameters(thread, zone, name_visibility, &pieces); | 7141 BuildSignatureParameters(thread, zone, name_visibility, &pieces); |
| 7070 pieces.Add(Symbols::RParenArrow()); | 7142 pieces.Add(Symbols::RParenArrow()); |
| 7071 const AbstractType& res_type = AbstractType::Handle(zone, result_type()); | 7143 const AbstractType& res_type = AbstractType::Handle(zone, result_type()); |
| 7072 const String& name = | 7144 name = res_type.BuildName(name_visibility); |
| 7073 String::Handle(zone, res_type.BuildName(name_visibility)); | |
| 7074 pieces.Add(name); | 7145 pieces.Add(name); |
| 7075 return Symbols::FromConcatAll(thread, pieces); | 7146 return Symbols::FromConcatAll(thread, pieces); |
| 7076 } | 7147 } |
| 7077 | 7148 |
| 7078 | 7149 |
| 7079 bool Function::HasInstantiatedSignature(Genericity genericity, | 7150 bool Function::HasInstantiatedSignature(Genericity genericity, |
| 7080 TrailPtr trail) const { | 7151 TrailPtr trail) const { |
| 7081 AbstractType& type = AbstractType::Handle(result_type()); | 7152 AbstractType& type = AbstractType::Handle(result_type()); |
| 7082 if (!type.IsInstantiated(genericity, trail)) { | 7153 if (!type.IsInstantiated(genericity, trail)) { |
| 7083 return false; | 7154 return false; |
| (...skipping 8723 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 15807 // Check if this instance understands a call() method of a compatible type. | 15878 // Check if this instance understands a call() method of a compatible type. |
| 15808 Function& sig_fun = | 15879 Function& sig_fun = |
| 15809 Function::Handle(zone, cls.LookupCallFunctionForTypeTest()); | 15880 Function::Handle(zone, cls.LookupCallFunctionForTypeTest()); |
| 15810 if (!sig_fun.IsNull()) { | 15881 if (!sig_fun.IsNull()) { |
| 15811 if (other_is_dart_function) { | 15882 if (other_is_dart_function) { |
| 15812 return true; | 15883 return true; |
| 15813 } | 15884 } |
| 15814 if (!sig_fun.HasInstantiatedSignature()) { | 15885 if (!sig_fun.HasInstantiatedSignature()) { |
| 15815 const TypeArguments& function_type_arguments = | 15886 const TypeArguments& function_type_arguments = |
| 15816 TypeArguments::Handle(zone, sig_fun.type_parameters()); | 15887 TypeArguments::Handle(zone, sig_fun.type_parameters()); |
| 15817 // TODO(regis): Pass the closure context to InstantiateSignatureFrom(). | |
| 15818 // No bound error possible, since the instance exists. | 15888 // No bound error possible, since the instance exists. |
| 15819 sig_fun = sig_fun.InstantiateSignatureFrom( | 15889 sig_fun = sig_fun.InstantiateSignatureFrom( |
| 15820 type_arguments, function_type_arguments, Heap::kOld); | 15890 type_arguments, function_type_arguments, Heap::kOld); |
| 15821 } | 15891 } |
| 15822 const Function& other_signature = | 15892 const Function& other_signature = |
| 15823 Function::Handle(zone, Type::Cast(instantiated_other).signature()); | 15893 Function::Handle(zone, Type::Cast(instantiated_other).signature()); |
| 15824 if (sig_fun.IsSubtypeOf(other_signature, bound_error, Heap::kOld)) { | 15894 if (sig_fun.IsSubtypeOf(other_signature, bound_error, Heap::kOld)) { |
| 15825 return true; | 15895 return true; |
| 15826 } | 15896 } |
| 15827 } | 15897 } |
| (...skipping 1288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 17116 ASSERT(Type::Cast(other).IsFunctionType()); | 17186 ASSERT(Type::Cast(other).IsFunctionType()); |
| 17117 // Equal function types must have equal signature types and equal optional | 17187 // Equal function types must have equal signature types and equal optional |
| 17118 // named arguments. | 17188 // named arguments. |
| 17119 if (signature() == other_type.signature()) { | 17189 if (signature() == other_type.signature()) { |
| 17120 return true; | 17190 return true; |
| 17121 } | 17191 } |
| 17122 const Function& sig_fun = Function::Handle(zone, signature()); | 17192 const Function& sig_fun = Function::Handle(zone, signature()); |
| 17123 const Function& other_sig_fun = | 17193 const Function& other_sig_fun = |
| 17124 Function::Handle(zone, other_type.signature()); | 17194 Function::Handle(zone, other_type.signature()); |
| 17125 | 17195 |
| 17196 if (FLAG_reify_generic_functions) { | |
| 17197 // Compare function type parameters and their bounds. | |
| 17198 const intptr_t num_type_params = sig_fun.NumTypeParameters(thread); | |
| 17199 if (num_type_params != other_sig_fun.NumTypeParameters(thread)) { | |
| 17200 return false; | |
| 17201 } | |
| 17202 if (num_type_params > 0) { | |
| 17203 const TypeArguments& type_params = | |
| 17204 TypeArguments::Handle(zone, sig_fun.type_parameters()); | |
| 17205 ASSERT(!type_params.IsNull()); | |
| 17206 const TypeArguments& other_type_params = | |
| 17207 TypeArguments::Handle(zone, other_sig_fun.type_parameters()); | |
| 17208 ASSERT(!other_type_params.IsNull()); | |
| 17209 TypeParameter& type_param = TypeParameter::Handle(zone); | |
| 17210 TypeParameter& other_type_param = TypeParameter::Handle(zone); | |
| 17211 AbstractType& bound = AbstractType::Handle(zone); | |
| 17212 AbstractType& other_bound = AbstractType::Handle(zone); | |
| 17213 for (intptr_t i = 0; i < num_type_params; i++) { | |
| 17214 type_param ^= type_params.TypeAt(i); | |
| 17215 other_type_param ^= other_type_params.TypeAt(i); | |
| 17216 bound = type_param.bound(); | |
| 17217 other_bound = other_type_param.bound(); | |
| 17218 if (!bound.Equals(other_bound)) { | |
| 17219 return false; | |
| 17220 } | |
| 17221 } | |
| 17222 } | |
|
siva
2017/04/20 20:32:08
This code here is very similar to the one in Funct
regis
2017/04/20 21:18:26
That was bugging me too, and then I forgot :-)
I a
| |
| 17223 } | |
| 17224 | |
| 17126 // Compare number of function parameters. | 17225 // Compare number of function parameters. |
| 17127 const intptr_t num_fixed_params = sig_fun.num_fixed_parameters(); | 17226 const intptr_t num_fixed_params = sig_fun.num_fixed_parameters(); |
| 17128 const intptr_t other_num_fixed_params = other_sig_fun.num_fixed_parameters(); | 17227 const intptr_t other_num_fixed_params = other_sig_fun.num_fixed_parameters(); |
| 17129 if (num_fixed_params != other_num_fixed_params) { | 17228 if (num_fixed_params != other_num_fixed_params) { |
| 17130 return false; | 17229 return false; |
| 17131 } | 17230 } |
| 17132 const intptr_t num_opt_pos_params = sig_fun.NumOptionalPositionalParameters(); | 17231 const intptr_t num_opt_pos_params = sig_fun.NumOptionalPositionalParameters(); |
| 17133 const intptr_t other_num_opt_pos_params = | 17232 const intptr_t other_num_opt_pos_params = |
| 17134 other_sig_fun.NumOptionalPositionalParameters(); | 17233 other_sig_fun.NumOptionalPositionalParameters(); |
| 17135 if (num_opt_pos_params != other_num_opt_pos_params) { | 17234 if (num_opt_pos_params != other_num_opt_pos_params) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 17204 if (IsMalbounded()) { | 17303 if (IsMalbounded()) { |
| 17205 const LanguageError& bound_error = LanguageError::Handle(zone, error()); | 17304 const LanguageError& bound_error = LanguageError::Handle(zone, error()); |
| 17206 clone.set_error(bound_error); | 17305 clone.set_error(bound_error); |
| 17207 } | 17306 } |
| 17208 // Clone the signature if this type represents a function type. | 17307 // Clone the signature if this type represents a function type. |
| 17209 Function& fun = Function::Handle(zone, signature()); | 17308 Function& fun = Function::Handle(zone, signature()); |
| 17210 if (!fun.IsNull()) { | 17309 if (!fun.IsNull()) { |
| 17211 const Class& owner = Class::Handle(zone, fun.Owner()); | 17310 const Class& owner = Class::Handle(zone, fun.Owner()); |
| 17212 Function& fun_clone = Function::Handle( | 17311 Function& fun_clone = Function::Handle( |
| 17213 zone, Function::NewSignatureFunction(owner, TokenPosition::kNoSource)); | 17312 zone, Function::NewSignatureFunction(owner, TokenPosition::kNoSource)); |
| 17214 // TODO(regis): Handle cloning of a generic function type. | 17313 const TypeArguments& type_params = |
| 17314 TypeArguments::Handle(zone, fun.type_parameters()); | |
| 17315 if (!type_params.IsNull()) { | |
| 17316 const intptr_t num_type_params = type_params.Length(); | |
| 17317 const TypeArguments& type_params_clone = | |
| 17318 TypeArguments::Handle(zone, TypeArguments::New(num_type_params)); | |
| 17319 TypeParameter& type_param = TypeParameter::Handle(zone); | |
| 17320 for (intptr_t i = 0; i < num_type_params; i++) { | |
| 17321 type_param ^= type_params.TypeAt(i); | |
| 17322 type_param ^= type_param.CloneUnfinalized(); | |
| 17323 type_params_clone.SetTypeAt(i, type_param); | |
| 17324 } | |
| 17325 fun_clone.set_type_parameters(type_params_clone); | |
| 17326 } | |
|
siva
2017/04/20 20:32:08
ditto comment about this matching up with the one
regis
2017/04/20 21:18:25
This one cannot easily be factored out. One is cal
| |
| 17215 AbstractType& type = AbstractType::Handle(zone, fun.result_type()); | 17327 AbstractType& type = AbstractType::Handle(zone, fun.result_type()); |
| 17216 type = type.CloneUnfinalized(); | 17328 type = type.CloneUnfinalized(); |
| 17217 fun_clone.set_result_type(type); | 17329 fun_clone.set_result_type(type); |
| 17218 const intptr_t num_params = fun.NumParameters(); | 17330 const intptr_t num_params = fun.NumParameters(); |
| 17219 fun_clone.set_num_fixed_parameters(fun.num_fixed_parameters()); | 17331 fun_clone.set_num_fixed_parameters(fun.num_fixed_parameters()); |
| 17220 fun_clone.SetNumOptionalParameters(fun.NumOptionalParameters(), | 17332 fun_clone.SetNumOptionalParameters(fun.NumOptionalParameters(), |
| 17221 fun.HasOptionalPositionalParameters()); | 17333 fun.HasOptionalPositionalParameters()); |
| 17222 fun_clone.set_parameter_types( | 17334 fun_clone.set_parameter_types( |
| 17223 Array::Handle(Array::New(num_params, Heap::kOld))); | 17335 Array::Handle(Array::New(num_params, Heap::kOld))); |
| 17224 for (intptr_t i = 0; i < num_params; i++) { | 17336 for (intptr_t i = 0; i < num_params; i++) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 17260 } | 17372 } |
| 17261 // Clone the signature if this type represents a function type. | 17373 // Clone the signature if this type represents a function type. |
| 17262 const Function& fun = Function::Handle(zone, signature()); | 17374 const Function& fun = Function::Handle(zone, signature()); |
| 17263 if (!fun.IsNull()) { | 17375 if (!fun.IsNull()) { |
| 17264 ASSERT(type_cls.IsTypedefClass() || type_cls.IsClosureClass()); | 17376 ASSERT(type_cls.IsTypedefClass() || type_cls.IsClosureClass()); |
| 17265 // If the scope class is not a typedef and if it is generic, it must be the | 17377 // If the scope class is not a typedef and if it is generic, it must be the |
| 17266 // mixin class, set it to the new owner. | 17378 // mixin class, set it to the new owner. |
| 17267 Function& fun_clone = Function::Handle( | 17379 Function& fun_clone = Function::Handle( |
| 17268 zone, | 17380 zone, |
| 17269 Function::NewSignatureFunction(new_owner, TokenPosition::kNoSource)); | 17381 Function::NewSignatureFunction(new_owner, TokenPosition::kNoSource)); |
| 17382 const TypeArguments& type_params = | |
| 17383 TypeArguments::Handle(zone, fun.type_parameters()); | |
| 17384 if (!type_params.IsNull()) { | |
| 17385 const intptr_t num_type_params = type_params.Length(); | |
| 17386 const TypeArguments& type_params_clone = | |
| 17387 TypeArguments::Handle(zone, TypeArguments::New(num_type_params)); | |
| 17388 TypeParameter& type_param = TypeParameter::Handle(zone); | |
| 17389 for (intptr_t i = 0; i < num_type_params; i++) { | |
| 17390 type_param ^= type_params.TypeAt(i); | |
| 17391 type_param ^= type_param.CloneUninstantiated(new_owner, trail); | |
| 17392 type_params_clone.SetTypeAt(i, type_param); | |
| 17393 } | |
| 17394 fun_clone.set_type_parameters(type_params_clone); | |
| 17395 } | |
| 17270 AbstractType& type = AbstractType::Handle(zone, fun.result_type()); | 17396 AbstractType& type = AbstractType::Handle(zone, fun.result_type()); |
| 17271 type = type.CloneUninstantiated(new_owner, trail); | 17397 type = type.CloneUninstantiated(new_owner, trail); |
| 17272 fun_clone.set_result_type(type); | 17398 fun_clone.set_result_type(type); |
| 17273 const intptr_t num_params = fun.NumParameters(); | 17399 const intptr_t num_params = fun.NumParameters(); |
| 17274 fun_clone.set_num_fixed_parameters(fun.num_fixed_parameters()); | 17400 fun_clone.set_num_fixed_parameters(fun.num_fixed_parameters()); |
| 17275 fun_clone.SetNumOptionalParameters(fun.NumOptionalParameters(), | 17401 fun_clone.SetNumOptionalParameters(fun.NumOptionalParameters(), |
| 17276 fun.HasOptionalPositionalParameters()); | 17402 fun.HasOptionalPositionalParameters()); |
| 17277 fun_clone.set_parameter_types( | 17403 fun_clone.set_parameter_types( |
| 17278 Array::Handle(Array::New(num_params, Heap::kOld))); | 17404 Array::Handle(Array::New(num_params, Heap::kOld))); |
| 17279 for (intptr_t i = 0; i < num_params; i++) { | 17405 for (intptr_t i = 0; i < num_params; i++) { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 17386 ASSERT(type_args.IsNull() || type_args.IsOld()); | 17512 ASSERT(type_args.IsNull() || type_args.IsOld()); |
| 17387 | 17513 |
| 17388 // In case of a function type, replace the actual function by a signature | 17514 // In case of a function type, replace the actual function by a signature |
| 17389 // function. | 17515 // function. |
| 17390 if (IsFunctionType()) { | 17516 if (IsFunctionType()) { |
| 17391 const Function& fun = Function::Handle(zone, signature()); | 17517 const Function& fun = Function::Handle(zone, signature()); |
| 17392 if (!fun.IsSignatureFunction()) { | 17518 if (!fun.IsSignatureFunction()) { |
| 17393 Function& sig_fun = Function::Handle( | 17519 Function& sig_fun = Function::Handle( |
| 17394 zone, | 17520 zone, |
| 17395 Function::NewSignatureFunction(cls, TokenPosition::kNoSource)); | 17521 Function::NewSignatureFunction(cls, TokenPosition::kNoSource)); |
| 17522 sig_fun.set_type_parameters( | |
| 17523 TypeArguments::Handle(zone, fun.type_parameters())); | |
| 17396 type = fun.result_type(); | 17524 type = fun.result_type(); |
| 17397 type = type.Canonicalize(trail); | 17525 type = type.Canonicalize(trail); |
| 17398 sig_fun.set_result_type(type); | 17526 sig_fun.set_result_type(type); |
| 17399 const intptr_t num_params = fun.NumParameters(); | 17527 const intptr_t num_params = fun.NumParameters(); |
| 17400 sig_fun.set_num_fixed_parameters(fun.num_fixed_parameters()); | 17528 sig_fun.set_num_fixed_parameters(fun.num_fixed_parameters()); |
| 17401 sig_fun.SetNumOptionalParameters(fun.NumOptionalParameters(), | 17529 sig_fun.SetNumOptionalParameters(fun.NumOptionalParameters(), |
| 17402 fun.HasOptionalPositionalParameters()); | 17530 fun.HasOptionalPositionalParameters()); |
| 17403 sig_fun.set_parameter_types( | 17531 sig_fun.set_parameter_types( |
| 17404 Array::Handle(Array::New(num_params, Heap::kOld))); | 17532 Array::Handle(Array::New(num_params, Heap::kOld))); |
| 17405 for (intptr_t i = 0; i < num_params; i++) { | 17533 for (intptr_t i = 0; i < num_params; i++) { |
| (...skipping 607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 18013 return TypeParameter::New(Class::Handle(parameterized_class()), | 18141 return TypeParameter::New(Class::Handle(parameterized_class()), |
| 18014 Function::Handle(parameterized_function()), index(), | 18142 Function::Handle(parameterized_function()), index(), |
| 18015 String::Handle(name()), | 18143 String::Handle(name()), |
| 18016 AbstractType::Handle(bound()), token_pos()); | 18144 AbstractType::Handle(bound()), token_pos()); |
| 18017 } | 18145 } |
| 18018 | 18146 |
| 18019 | 18147 |
| 18020 RawAbstractType* TypeParameter::CloneUninstantiated(const Class& new_owner, | 18148 RawAbstractType* TypeParameter::CloneUninstantiated(const Class& new_owner, |
| 18021 TrailPtr trail) const { | 18149 TrailPtr trail) const { |
| 18022 ASSERT(IsFinalized()); | 18150 ASSERT(IsFinalized()); |
| 18023 TypeParameter& clone = TypeParameter::Handle(); | 18151 TypeParameter& clone = TypeParameter::Handle(); |
|
zra
2017/04/20 19:22:09
ditto
regis
2017/04/20 20:23:30
Done.
| |
| 18024 clone ^= OnlyBuddyInTrail(trail); | 18152 clone ^= OnlyBuddyInTrail(trail); |
| 18025 if (!clone.IsNull()) { | 18153 if (!clone.IsNull()) { |
| 18026 return clone.raw(); | 18154 return clone.raw(); |
| 18027 } | 18155 } |
| 18028 const Class& old_owner = Class::Handle(parameterized_class()); | 18156 intptr_t new_index = index(); |
| 18029 if (old_owner.IsNull()) { | 18157 AbstractType& upper_bound = AbstractType::Handle(bound()); |
| 18158 const Function& fun = Function::Handle(parameterized_function()); | |
| 18159 Class& cls = Class::Handle(parameterized_class()); | |
| 18160 if (!cls.IsNull()) { | |
| 18161 ASSERT(fun.IsNull()); | |
| 18162 new_index += new_owner.NumTypeArguments() - cls.NumTypeArguments(); | |
| 18163 cls = new_owner.raw(); | |
| 18164 } else { | |
| 18030 ASSERT(IsFunctionTypeParameter()); | 18165 ASSERT(IsFunctionTypeParameter()); |
| 18031 // Function type parameters do not need cloning. | 18166 // Only the bounds of function type parameters need cloning. |
| 18032 return raw(); | |
| 18033 } | 18167 } |
| 18034 const intptr_t new_index = | 18168 clone = TypeParameter::New(cls, fun, new_index, String::Handle(name()), |
| 18035 index() + new_owner.NumTypeArguments() - old_owner.NumTypeArguments(); | |
| 18036 AbstractType& upper_bound = AbstractType::Handle(bound()); | |
| 18037 ASSERT(parameterized_function() == Function::null()); | |
| 18038 clone = TypeParameter::New(new_owner, Function::Handle(), new_index, | |
| 18039 String::Handle(name()), | |
| 18040 upper_bound, // Not cloned yet. | 18169 upper_bound, // Not cloned yet. |
| 18041 token_pos()); | 18170 token_pos()); |
| 18042 clone.SetIsFinalized(); | 18171 clone.SetIsFinalized(); |
| 18043 AddOnlyBuddyToTrail(&trail, clone); | 18172 AddOnlyBuddyToTrail(&trail, clone); |
| 18044 upper_bound = upper_bound.CloneUninstantiated(new_owner, trail); | 18173 upper_bound = upper_bound.CloneUninstantiated(new_owner, trail); |
| 18045 clone.set_bound(upper_bound); | 18174 clone.set_bound(upper_bound); |
| 18046 return clone.raw(); | 18175 return clone.raw(); |
| 18047 } | 18176 } |
| 18048 | 18177 |
| 18049 | 18178 |
| (...skipping 5118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 23168 return UserTag::null(); | 23297 return UserTag::null(); |
| 23169 } | 23298 } |
| 23170 | 23299 |
| 23171 | 23300 |
| 23172 const char* UserTag::ToCString() const { | 23301 const char* UserTag::ToCString() const { |
| 23173 const String& tag_label = String::Handle(label()); | 23302 const String& tag_label = String::Handle(label()); |
| 23174 return tag_label.ToCString(); | 23303 return tag_label.ToCString(); |
| 23175 } | 23304 } |
| 23176 | 23305 |
| 23177 } // namespace dart | 23306 } // namespace dart |
| OLD | NEW |