| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 | 188 |
| 189 #define __ assembler()-> | 189 #define __ assembler()-> |
| 190 | 190 |
| 191 | 191 |
| 192 // Fall through if bool_register contains null. | 192 // Fall through if bool_register contains null. |
| 193 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, | 193 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, |
| 194 Label* is_true, | 194 Label* is_true, |
| 195 Label* is_false) { | 195 Label* is_false) { |
| 196 __ TraceSimMsg("BoolToJump"); | 196 __ TraceSimMsg("BoolToJump"); |
| 197 Label fall_through; | 197 Label fall_through; |
| 198 __ BranchEqual(bool_register, reinterpret_cast<int32_t>(Object::null()), | 198 __ BranchEqual(bool_register, Object::null_object(), &fall_through); |
| 199 &fall_through); | |
| 200 __ BranchEqual(bool_register, Bool::True(), is_true); | 199 __ BranchEqual(bool_register, Bool::True(), is_true); |
| 201 __ b(is_false); | 200 __ b(is_false); |
| 202 __ Bind(&fall_through); | 201 __ Bind(&fall_through); |
| 203 } | 202 } |
| 204 | 203 |
| 205 | 204 |
| 206 // A0: instance (must be preserved). | 205 // A0: instance (must be preserved). |
| 207 // A1: instantiator type arguments (if used). | 206 // A1: instantiator type arguments (if used). |
| 208 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 207 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 209 TypeTestStubKind test_kind, | 208 TypeTestStubKind test_kind, |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 const TypeArguments& type_arguments = | 271 const TypeArguments& type_arguments = |
| 273 TypeArguments::ZoneHandle(type.arguments()); | 272 TypeArguments::ZoneHandle(type.arguments()); |
| 274 const bool is_raw_type = type_arguments.IsNull() || | 273 const bool is_raw_type = type_arguments.IsNull() || |
| 275 type_arguments.IsRaw(from_index, num_type_params); | 274 type_arguments.IsRaw(from_index, num_type_params); |
| 276 // Signature class is an instantiated parameterized type. | 275 // Signature class is an instantiated parameterized type. |
| 277 if (!type_class.IsSignatureClass()) { | 276 if (!type_class.IsSignatureClass()) { |
| 278 if (is_raw_type) { | 277 if (is_raw_type) { |
| 279 const Register kClassIdReg = T0; | 278 const Register kClassIdReg = T0; |
| 280 // dynamic type argument, check only classes. | 279 // dynamic type argument, check only classes. |
| 281 __ LoadClassId(kClassIdReg, kInstanceReg); | 280 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 282 __ BranchEqual(kClassIdReg, type_class.id(), is_instance_lbl); | 281 __ BranchEqual(kClassIdReg, Immediate(type_class.id()), is_instance_lbl); |
| 283 // List is a very common case. | 282 // List is a very common case. |
| 284 if (IsListClass(type_class)) { | 283 if (IsListClass(type_class)) { |
| 285 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); | 284 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
| 286 } | 285 } |
| 287 return GenerateSubtype1TestCacheLookup( | 286 return GenerateSubtype1TestCacheLookup( |
| 288 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 287 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 289 } | 288 } |
| 290 // If one type argument only, check if type argument is Object or dynamic. | 289 // If one type argument only, check if type argument is Object or dynamic. |
| 291 if (type_arguments.Length() == 1) { | 290 if (type_arguments.Length() == 1) { |
| 292 const AbstractType& tp_argument = AbstractType::ZoneHandle( | 291 const AbstractType& tp_argument = AbstractType::ZoneHandle( |
| (...skipping 23 matching lines...) Expand all Loading... |
| 316 is_not_instance_lbl); | 315 is_not_instance_lbl); |
| 317 } | 316 } |
| 318 | 317 |
| 319 | 318 |
| 320 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, | 319 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
| 321 const GrowableArray<intptr_t>& class_ids, | 320 const GrowableArray<intptr_t>& class_ids, |
| 322 Label* is_equal_lbl, | 321 Label* is_equal_lbl, |
| 323 Label* is_not_equal_lbl) { | 322 Label* is_not_equal_lbl) { |
| 324 __ TraceSimMsg("CheckClassIds"); | 323 __ TraceSimMsg("CheckClassIds"); |
| 325 for (intptr_t i = 0; i < class_ids.length(); i++) { | 324 for (intptr_t i = 0; i < class_ids.length(); i++) { |
| 326 __ BranchEqual(class_id_reg, class_ids[i], is_equal_lbl); | 325 __ BranchEqual(class_id_reg, Immediate(class_ids[i]), is_equal_lbl); |
| 327 } | 326 } |
| 328 __ b(is_not_equal_lbl); | 327 __ b(is_not_equal_lbl); |
| 329 } | 328 } |
| 330 | 329 |
| 331 | 330 |
| 332 // Testing against an instantiated type with no arguments, without | 331 // Testing against an instantiated type with no arguments, without |
| 333 // SubtypeTestCache. | 332 // SubtypeTestCache. |
| 334 // A0: instance being type checked (preserved). | 333 // A0: instance being type checked (preserved). |
| 335 // Clobbers: T0, T1, T2 | 334 // Clobbers: T0, T1, T2 |
| 336 // Returns true if there is a fallthrough. | 335 // Returns true if there is a fallthrough. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 353 type_class, | 352 type_class, |
| 354 TypeArguments::Handle(), | 353 TypeArguments::Handle(), |
| 355 NULL)) { | 354 NULL)) { |
| 356 __ beq(T0, ZR, is_instance_lbl); | 355 __ beq(T0, ZR, is_instance_lbl); |
| 357 } else { | 356 } else { |
| 358 __ beq(T0, ZR, is_not_instance_lbl); | 357 __ beq(T0, ZR, is_not_instance_lbl); |
| 359 } | 358 } |
| 360 // Compare if the classes are equal. | 359 // Compare if the classes are equal. |
| 361 const Register kClassIdReg = T0; | 360 const Register kClassIdReg = T0; |
| 362 __ LoadClassId(kClassIdReg, kInstanceReg); | 361 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 363 __ BranchEqual(kClassIdReg, type_class.id(), is_instance_lbl); | 362 __ BranchEqual(kClassIdReg, Immediate(type_class.id()), is_instance_lbl); |
| 364 | 363 |
| 365 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted | 364 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted |
| 366 // interfaces. | 365 // interfaces. |
| 367 // Bool interface can be implemented only by core class Bool. | 366 // Bool interface can be implemented only by core class Bool. |
| 368 if (type.IsBoolType()) { | 367 if (type.IsBoolType()) { |
| 369 __ BranchEqual(kClassIdReg, kBoolCid, is_instance_lbl); | 368 __ BranchEqual(kClassIdReg, Immediate(kBoolCid), is_instance_lbl); |
| 370 __ b(is_not_instance_lbl); | 369 __ b(is_not_instance_lbl); |
| 371 return false; | 370 return false; |
| 372 } | 371 } |
| 373 if (type.IsFunctionType()) { | 372 if (type.IsFunctionType()) { |
| 374 // Check if instance is a closure. | 373 // Check if instance is a closure. |
| 375 __ LoadClassById(T1, kClassIdReg); | 374 __ LoadClassById(T1, kClassIdReg); |
| 376 __ lw(T1, FieldAddress(T1, Class::signature_function_offset())); | 375 __ lw(T1, FieldAddress(T1, Class::signature_function_offset())); |
| 377 __ BranchNotEqual(T1, reinterpret_cast<int32_t>(Object::null()), | 376 __ BranchNotEqual(T1, Object::null_object(), is_instance_lbl); |
| 378 is_instance_lbl); | |
| 379 } | 377 } |
| 380 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 378 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 381 // Note that instance is not Smi (checked above). | 379 // Note that instance is not Smi (checked above). |
| 382 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { | 380 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { |
| 383 GenerateNumberTypeCheck( | 381 GenerateNumberTypeCheck( |
| 384 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 382 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
| 385 return false; | 383 return false; |
| 386 } | 384 } |
| 387 if (type.IsStringType()) { | 385 if (type.IsStringType()) { |
| 388 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 386 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 // If type is instantiated and non-parameterized, we can inline code | 578 // If type is instantiated and non-parameterized, we can inline code |
| 581 // checking whether the tested instance is a Smi. | 579 // checking whether the tested instance is a Smi. |
| 582 if (type.IsInstantiated()) { | 580 if (type.IsInstantiated()) { |
| 583 // A null object is only an instance of Object and dynamic, which has | 581 // A null object is only an instance of Object and dynamic, which has |
| 584 // already been checked above (if the type is instantiated). So we can | 582 // already been checked above (if the type is instantiated). So we can |
| 585 // return false here if the instance is null (and if the type is | 583 // return false here if the instance is null (and if the type is |
| 586 // instantiated). | 584 // instantiated). |
| 587 // We can only inline this null check if the type is instantiated at compile | 585 // We can only inline this null check if the type is instantiated at compile |
| 588 // time, since an uninstantiated type at compile time could be Object or | 586 // time, since an uninstantiated type at compile time could be Object or |
| 589 // dynamic at run time. | 587 // dynamic at run time. |
| 590 __ BranchEqual(A0, reinterpret_cast<int32_t>(Object::null()), | 588 __ BranchEqual(A0, Object::null_object(), &is_not_instance); |
| 591 &is_not_instance); | |
| 592 } | 589 } |
| 593 | 590 |
| 594 // Generate inline instanceof test. | 591 // Generate inline instanceof test. |
| 595 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 592 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 596 test_cache = GenerateInlineInstanceof(token_pos, type, | 593 test_cache = GenerateInlineInstanceof(token_pos, type, |
| 597 &is_instance, &is_not_instance); | 594 &is_instance, &is_not_instance); |
| 598 | 595 |
| 599 // test_cache is null if there is no fall-through. | 596 // test_cache is null if there is no fall-through. |
| 600 Label done; | 597 Label done; |
| 601 if (!test_cache.IsNull()) { | 598 if (!test_cache.IsNull()) { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 665 // Assignable check is skipped in FlowGraphBuilder, not here. | 662 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 666 ASSERT(dst_type.IsMalformedOrMalbounded() || | 663 ASSERT(dst_type.IsMalformedOrMalbounded() || |
| 667 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 664 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 668 // Preserve instantiator and its type arguments. | 665 // Preserve instantiator and its type arguments. |
| 669 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 666 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 670 __ sw(A2, Address(SP, 1 * kWordSize)); | 667 __ sw(A2, Address(SP, 1 * kWordSize)); |
| 671 | 668 |
| 672 // A null object is always assignable and is returned as result. | 669 // A null object is always assignable and is returned as result. |
| 673 Label is_assignable, runtime_call; | 670 Label is_assignable, runtime_call; |
| 674 | 671 |
| 675 __ BranchEqual(A0, reinterpret_cast<int32_t>(Object::null()), &is_assignable); | 672 __ BranchEqual(A0, Object::null_object(), &is_assignable); |
| 676 __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize)); | 673 __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize)); |
| 677 | 674 |
| 678 // Generate throw new TypeError() if the type is malformed or malbounded. | 675 // Generate throw new TypeError() if the type is malformed or malbounded. |
| 679 if (dst_type.IsMalformedOrMalbounded()) { | 676 if (dst_type.IsMalformedOrMalbounded()) { |
| 680 __ addiu(SP, SP, Immediate(-4 * kWordSize)); | 677 __ addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 681 __ LoadObject(TMP, Object::null_object()); | 678 __ LoadObject(TMP, Object::null_object()); |
| 682 __ sw(TMP, Address(SP, 3 * kWordSize)); // Make room for the result. | 679 __ sw(TMP, Address(SP, 3 * kWordSize)); // Make room for the result. |
| 683 __ sw(A0, Address(SP, 2 * kWordSize)); // Push the source object. | 680 __ sw(A0, Address(SP, 2 * kWordSize)); // Push the source object. |
| 684 __ LoadObject(TMP, dst_name); | 681 __ LoadObject(TMP, dst_name); |
| 685 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the destination name. | 682 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the destination name. |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 764 ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotFromFp); | 761 ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotFromFp); |
| 765 | 762 |
| 766 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, | 763 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, |
| 767 // where num_pos_args is the number of positional arguments passed in. | 764 // where num_pos_args is the number of positional arguments passed in. |
| 768 const int min_num_pos_args = num_fixed_params; | 765 const int min_num_pos_args = num_fixed_params; |
| 769 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; | 766 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; |
| 770 | 767 |
| 771 __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); | 768 __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); |
| 772 // Check that min_num_pos_args <= num_pos_args. | 769 // Check that min_num_pos_args <= num_pos_args. |
| 773 Label wrong_num_arguments; | 770 Label wrong_num_arguments; |
| 774 __ BranchSignedLess(T2, Smi::RawValue(min_num_pos_args), | 771 __ BranchSignedLess(T2, Immediate(Smi::RawValue(min_num_pos_args)), |
| 775 &wrong_num_arguments); | 772 &wrong_num_arguments); |
| 776 | 773 |
| 777 // Check that num_pos_args <= max_num_pos_args. | 774 // Check that num_pos_args <= max_num_pos_args. |
| 778 __ BranchSignedGreater(T2, Smi::RawValue(max_num_pos_args), | 775 __ BranchSignedGreater(T2, Immediate(Smi::RawValue(max_num_pos_args)), |
| 779 &wrong_num_arguments); | 776 &wrong_num_arguments); |
| 780 | 777 |
| 781 // Copy positional arguments. | 778 // Copy positional arguments. |
| 782 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied | 779 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied |
| 783 // to fp[kFirstLocalSlotFromFp - i]. | 780 // to fp[kFirstLocalSlotFromFp - i]. |
| 784 | 781 |
| 785 __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | 782 __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
| 786 // Since T1 and T2 are Smi, use sll 1 instead of sll 2. | 783 // Since T1 and T2 are Smi, use sll 1 instead of sll 2. |
| 787 // Let T1 point to the last passed positional argument, i.e. to | 784 // Let T1 point to the last passed positional argument, i.e. to |
| 788 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. | 785 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 882 // to be copied to the context that is not yet allocated. | 879 // to be copied to the context that is not yet allocated. |
| 883 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 880 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 884 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); | 881 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); |
| 885 } | 882 } |
| 886 delete[] opt_param; | 883 delete[] opt_param; |
| 887 delete[] opt_param_position; | 884 delete[] opt_param_position; |
| 888 if (check_correct_named_args) { | 885 if (check_correct_named_args) { |
| 889 // Check that T0 now points to the null terminator in the arguments | 886 // Check that T0 now points to the null terminator in the arguments |
| 890 // descriptor. | 887 // descriptor. |
| 891 __ lw(T3, Address(T0)); | 888 __ lw(T3, Address(T0)); |
| 892 __ BranchEqual(T3, reinterpret_cast<int32_t>(Object::null()), | 889 __ BranchEqual(T3, Object::null_object(), &all_arguments_processed); |
| 893 &all_arguments_processed); | |
| 894 } | 890 } |
| 895 } else { | 891 } else { |
| 896 ASSERT(num_opt_pos_params > 0); | 892 ASSERT(num_opt_pos_params > 0); |
| 897 __ Comment("There are optional positional parameters"); | 893 __ Comment("There are optional positional parameters"); |
| 898 __ lw(T2, | 894 __ lw(T2, |
| 899 FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); | 895 FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); |
| 900 __ SmiUntag(T2); | 896 __ SmiUntag(T2); |
| 901 for (int i = 0; i < num_opt_pos_params; i++) { | 897 for (int i = 0; i < num_opt_pos_params; i++) { |
| 902 Label next_parameter; | 898 Label next_parameter; |
| 903 // Handle this optional positional parameter only if k or fewer positional | 899 // Handle this optional positional parameter only if k or fewer positional |
| 904 // arguments have been passed, where k is param_pos, the position of this | 900 // arguments have been passed, where k is param_pos, the position of this |
| 905 // optional parameter in the formal parameter list. | 901 // optional parameter in the formal parameter list. |
| 906 const int param_pos = num_fixed_params + i; | 902 const int param_pos = num_fixed_params + i; |
| 907 __ BranchSignedGreater(T2, param_pos, &next_parameter); | 903 __ BranchSignedGreater(T2, Immediate(param_pos), &next_parameter); |
| 908 // Load T3 with default argument. | 904 // Load T3 with default argument. |
| 909 const Object& value = Object::ZoneHandle( | 905 const Object& value = Object::ZoneHandle( |
| 910 parsed_function().default_parameter_values().At(i)); | 906 parsed_function().default_parameter_values().At(i)); |
| 911 __ LoadObject(T3, value); | 907 __ LoadObject(T3, value); |
| 912 // Assign T3 to fp[kFirstLocalSlotFromFp - param_pos]. | 908 // Assign T3 to fp[kFirstLocalSlotFromFp - param_pos]. |
| 913 // We do not use the final allocation index of the variable here, i.e. | 909 // We do not use the final allocation index of the variable here, i.e. |
| 914 // scope->VariableAt(i)->index(), because captured variables still need | 910 // scope->VariableAt(i)->index(), because captured variables still need |
| 915 // to be copied to the context that is not yet allocated. | 911 // to be copied to the context that is not yet allocated. |
| 916 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 912 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 917 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); | 913 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1015 __ lw(T1, FieldAddress(function_reg, Function::usage_counter_offset())); | 1011 __ lw(T1, FieldAddress(function_reg, Function::usage_counter_offset())); |
| 1016 // Reoptimization of an optimized function is triggered by counting in | 1012 // Reoptimization of an optimized function is triggered by counting in |
| 1017 // IC stubs, but not at the entry of the function. | 1013 // IC stubs, but not at the entry of the function. |
| 1018 if (!is_optimizing()) { | 1014 if (!is_optimizing()) { |
| 1019 __ addiu(T1, T1, Immediate(1)); | 1015 __ addiu(T1, T1, Immediate(1)); |
| 1020 __ sw(T1, FieldAddress(function_reg, Function::usage_counter_offset())); | 1016 __ sw(T1, FieldAddress(function_reg, Function::usage_counter_offset())); |
| 1021 } | 1017 } |
| 1022 | 1018 |
| 1023 // Skip Branch if T1 is less than the threshold. | 1019 // Skip Branch if T1 is less than the threshold. |
| 1024 Label dont_branch; | 1020 Label dont_branch; |
| 1025 __ BranchSignedLess(T1, GetOptimizationThreshold(), &dont_branch); | 1021 __ BranchSignedLess( |
| 1022 T1, Immediate(GetOptimizationThreshold()), &dont_branch); |
| 1026 | 1023 |
| 1027 ASSERT(function_reg == T0); | 1024 ASSERT(function_reg == T0); |
| 1028 __ Branch(&stub_code->OptimizeFunctionLabel()); | 1025 __ Branch(&stub_code->OptimizeFunctionLabel()); |
| 1029 | 1026 |
| 1030 __ Bind(&dont_branch); | 1027 __ Bind(&dont_branch); |
| 1031 | 1028 |
| 1032 } else if (!flow_graph().IsCompiledForOsr()) { | 1029 } else if (!flow_graph().IsCompiledForOsr()) { |
| 1033 entry_patch_pc_offset_ = assembler()->CodeSize(); | 1030 entry_patch_pc_offset_ = assembler()->CodeSize(); |
| 1034 } | 1031 } |
| 1035 __ Comment("Enter frame"); | 1032 __ Comment("Enter frame"); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1078 #else | 1075 #else |
| 1079 const bool check_arguments = | 1076 const bool check_arguments = |
| 1080 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); | 1077 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); |
| 1081 #endif | 1078 #endif |
| 1082 if (check_arguments) { | 1079 if (check_arguments) { |
| 1083 __ TraceSimMsg("Check argument count"); | 1080 __ TraceSimMsg("Check argument count"); |
| 1084 __ Comment("Check argument count"); | 1081 __ Comment("Check argument count"); |
| 1085 // Check that exactly num_fixed arguments are passed in. | 1082 // Check that exactly num_fixed arguments are passed in. |
| 1086 Label correct_num_arguments, wrong_num_arguments; | 1083 Label correct_num_arguments, wrong_num_arguments; |
| 1087 __ lw(T0, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | 1084 __ lw(T0, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
| 1088 __ BranchNotEqual(T0, Smi::RawValue(num_fixed_params), | 1085 __ BranchNotEqual(T0, Immediate(Smi::RawValue(num_fixed_params)), |
| 1089 &wrong_num_arguments); | 1086 &wrong_num_arguments); |
| 1090 | 1087 |
| 1091 __ lw(T1, FieldAddress(S4, | 1088 __ lw(T1, FieldAddress(S4, |
| 1092 ArgumentsDescriptor::positional_count_offset())); | 1089 ArgumentsDescriptor::positional_count_offset())); |
| 1093 __ beq(T0, T1, &correct_num_arguments); | 1090 __ beq(T0, T1, &correct_num_arguments); |
| 1094 __ Bind(&wrong_num_arguments); | 1091 __ Bind(&wrong_num_arguments); |
| 1095 if (function.IsClosureFunction()) { | 1092 if (function.IsClosureFunction()) { |
| 1096 __ LeaveDartFrame(); // The arguments are still on the stack. | 1093 __ LeaveDartFrame(); // The arguments are still on the stack. |
| 1097 __ Branch(&isolate()->stub_code()->CallClosureNoSuchMethodLabel()); | 1094 __ Branch(&isolate()->stub_code()->CallClosureNoSuchMethodLabel()); |
| 1098 // The noSuchMethod call may return to the caller, but not here. | 1095 // The noSuchMethod call may return to the caller, but not here. |
| (...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1541 argument_names)); | 1538 argument_names)); |
| 1542 StubCode* stub_code = isolate()->stub_code(); | 1539 StubCode* stub_code = isolate()->stub_code(); |
| 1543 | 1540 |
| 1544 __ TraceSimMsg("EmitTestAndCall"); | 1541 __ TraceSimMsg("EmitTestAndCall"); |
| 1545 __ Comment("EmitTestAndCall"); | 1542 __ Comment("EmitTestAndCall"); |
| 1546 __ LoadObject(S4, arguments_descriptor); | 1543 __ LoadObject(S4, arguments_descriptor); |
| 1547 for (intptr_t i = 0; i < len; i++) { | 1544 for (intptr_t i = 0; i < len; i++) { |
| 1548 const bool is_last_check = (i == (len - 1)); | 1545 const bool is_last_check = (i == (len - 1)); |
| 1549 Label next_test; | 1546 Label next_test; |
| 1550 if (is_last_check) { | 1547 if (is_last_check) { |
| 1551 __ BranchNotEqual(class_id_reg, sorted[i].cid, deopt); | 1548 __ BranchNotEqual(class_id_reg, Immediate(sorted[i].cid), deopt); |
| 1552 } else { | 1549 } else { |
| 1553 __ BranchNotEqual(class_id_reg, sorted[i].cid, &next_test); | 1550 __ BranchNotEqual(class_id_reg, Immediate(sorted[i].cid), &next_test); |
| 1554 } | 1551 } |
| 1555 // Do not use the code from the function, but let the code be patched so | 1552 // Do not use the code from the function, but let the code be patched so |
| 1556 // that we can record the outgoing edges to other code. | 1553 // that we can record the outgoing edges to other code. |
| 1557 GenerateDartCall(deopt_id, | 1554 GenerateDartCall(deopt_id, |
| 1558 token_index, | 1555 token_index, |
| 1559 &stub_code->CallStaticFunctionLabel(), | 1556 &stub_code->CallStaticFunctionLabel(), |
| 1560 RawPcDescriptors::kOptStaticCall, | 1557 RawPcDescriptors::kOptStaticCall, |
| 1561 locs); | 1558 locs); |
| 1562 const Function& function = *sorted[i].target; | 1559 const Function& function = *sorted[i].target; |
| 1563 AddStaticCallTarget(function); | 1560 AddStaticCallTarget(function); |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1799 __ AddImmediate(SP, kDoubleSize); | 1796 __ AddImmediate(SP, kDoubleSize); |
| 1800 } | 1797 } |
| 1801 | 1798 |
| 1802 | 1799 |
| 1803 #undef __ | 1800 #undef __ |
| 1804 | 1801 |
| 1805 | 1802 |
| 1806 } // namespace dart | 1803 } // namespace dart |
| 1807 | 1804 |
| 1808 #endif // defined TARGET_ARCH_MIPS | 1805 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |