| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/code_generator.h" | 8 #include "vm/code_generator.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 AstPrinter::PrintFunctionNodes(parsed_function_); | 258 AstPrinter::PrintFunctionNodes(parsed_function_); |
| 259 } | 259 } |
| 260 if (FLAG_trace_functions) { | 260 if (FLAG_trace_functions) { |
| 261 // Preserve ECX (ic-data array or object) and EDX (arguments descriptor). | 261 // Preserve ECX (ic-data array or object) and EDX (arguments descriptor). |
| 262 __ pushl(ECX); | 262 __ pushl(ECX); |
| 263 __ pushl(EDX); | 263 __ pushl(EDX); |
| 264 const Function& function = | 264 const Function& function = |
| 265 Function::ZoneHandle(parsed_function_.function().raw()); | 265 Function::ZoneHandle(parsed_function_.function().raw()); |
| 266 __ LoadObject(EAX, function); | 266 __ LoadObject(EAX, function); |
| 267 __ pushl(EAX); | 267 __ pushl(EAX); |
| 268 GenerateCallRuntime(0, kTraceFunctionEntryRuntimeEntry); | 268 GenerateCallRuntime(AstNode::kNoId, |
| 269 0, |
| 270 kTraceFunctionEntryRuntimeEntry); |
| 269 __ popl(EAX); | 271 __ popl(EAX); |
| 270 __ popl(EDX); | 272 __ popl(EDX); |
| 271 __ popl(ECX); | 273 __ popl(ECX); |
| 272 } | 274 } |
| 273 | 275 |
| 274 const bool code_generation_finished = TryIntrinsify(); | 276 const bool code_generation_finished = TryIntrinsify(); |
| 275 // In some cases intrinsifier can generate all code and no AST based | 277 // In some cases intrinsifier can generate all code and no AST based |
| 276 // code generation is needed. In some cases slow-paths (e.g., overflows) are | 278 // code generation is needed. In some cases slow-paths (e.g., overflows) are |
| 277 // implemented by the AST based code generation and 'code_generation_finished' | 279 // implemented by the AST based code generation and 'code_generation_finished' |
| 278 // is false. | 280 // is false. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 291 parsed_function_.node_sequence()->Visit(this); | 293 parsed_function_.node_sequence()->Visit(this); |
| 292 } | 294 } |
| 293 // End of code. | 295 // End of code. |
| 294 __ int3(); | 296 __ int3(); |
| 295 GenerateDeferredCode(); | 297 GenerateDeferredCode(); |
| 296 | 298 |
| 297 // Emit function patching code. This will be swapped with the first 5 bytes | 299 // Emit function patching code. This will be swapped with the first 5 bytes |
| 298 // at entry point. | 300 // at entry point. |
| 299 pc_descriptors_list_->AddDescriptor(PcDescriptors::kPatchCode, | 301 pc_descriptors_list_->AddDescriptor(PcDescriptors::kPatchCode, |
| 300 assembler_->CodeSize(), | 302 assembler_->CodeSize(), |
| 301 AstNode::kInvalidId, | 303 AstNode::kNoId, |
| 302 0, | 304 0, |
| 303 -1); | 305 -1); |
| 304 __ jmp(&StubCode::FixCallersTargetLabel()); | 306 __ jmp(&StubCode::FixCallersTargetLabel()); |
| 305 } | 307 } |
| 306 | 308 |
| 307 | 309 |
| 308 void CodeGenerator::GenerateDeferredCode() { | 310 void CodeGenerator::GenerateDeferredCode() { |
| 309 } | 311 } |
| 310 | 312 |
| 311 | 313 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 if (FLAG_trace_compiler) { | 364 if (FLAG_trace_compiler) { |
| 363 OS::Print("Not checking pc decriptors, length %d\n", | 365 OS::Print("Not checking pc decriptors, length %d\n", |
| 364 descriptors.Length()); | 366 descriptors.Length()); |
| 365 } | 367 } |
| 366 return; | 368 return; |
| 367 } | 369 } |
| 368 for (intptr_t i = 0; i < descriptors.Length(); i++) { | 370 for (intptr_t i = 0; i < descriptors.Length(); i++) { |
| 369 intptr_t pc = descriptors.PC(i); | 371 intptr_t pc = descriptors.PC(i); |
| 370 PcDescriptors::Kind kind = descriptors.DescriptorKind(i); | 372 PcDescriptors::Kind kind = descriptors.DescriptorKind(i); |
| 371 // 'node_id' is set for kDeopt and kIcCall and must be unique for one kind. | 373 // 'node_id' is set for kDeopt and kIcCall and must be unique for one kind. |
| 372 intptr_t node_id = AstNode::kInvalidId; | 374 intptr_t node_id = AstNode::kNoId; |
| 373 if (check_ids) { | 375 if (check_ids) { |
| 374 if ((descriptors.DescriptorKind(i) == PcDescriptors::kDeopt) || | 376 if ((descriptors.DescriptorKind(i) == PcDescriptors::kDeopt) || |
| 375 (descriptors.DescriptorKind(i) == PcDescriptors::kIcCall)) { | 377 (descriptors.DescriptorKind(i) == PcDescriptors::kIcCall)) { |
| 376 node_id = descriptors.NodeId(i); | 378 node_id = descriptors.NodeId(i); |
| 377 } | 379 } |
| 378 } | 380 } |
| 379 for (intptr_t k = i + 1; k < descriptors.Length(); k++) { | 381 for (intptr_t k = i + 1; k < descriptors.Length(); k++) { |
| 380 if (kind == descriptors.DescriptorKind(k)) { | 382 if (kind == descriptors.DescriptorKind(k)) { |
| 381 if (node_id != AstNode::kInvalidId) { | 383 if (node_id != AstNode::kNoId) { |
| 382 ASSERT(descriptors.NodeId(k) != node_id); | 384 ASSERT(descriptors.NodeId(k) != node_id); |
| 383 } | 385 } |
| 384 ASSERT(pc != descriptors.PC(k)); | 386 ASSERT(pc != descriptors.PC(k)); |
| 385 } | 387 } |
| 386 } | 388 } |
| 387 } | 389 } |
| 388 #endif // DEBUG | 390 #endif // DEBUG |
| 389 } | 391 } |
| 390 | 392 |
| 391 | 393 |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 569 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); | 571 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); |
| 570 if (num_opt_params == 0) { | 572 if (num_opt_params == 0) { |
| 571 __ cmpl(EAX, Immediate(Smi::RawValue(num_fixed_params))); | 573 __ cmpl(EAX, Immediate(Smi::RawValue(num_fixed_params))); |
| 572 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); | 574 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); |
| 573 } else { | 575 } else { |
| 574 __ subl(EAX, Immediate(Smi::RawValue(num_fixed_params))); | 576 __ subl(EAX, Immediate(Smi::RawValue(num_fixed_params))); |
| 575 __ cmpl(EAX, Immediate(Smi::RawValue(num_opt_params))); | 577 __ cmpl(EAX, Immediate(Smi::RawValue(num_opt_params))); |
| 576 __ j(BELOW_EQUAL, &argc_in_range, Assembler::kNearJump); | 578 __ j(BELOW_EQUAL, &argc_in_range, Assembler::kNearJump); |
| 577 } | 579 } |
| 578 if (function.IsClosureFunction()) { | 580 if (function.IsClosureFunction()) { |
| 579 GenerateCallRuntime(function.token_index(), | 581 GenerateCallRuntime(AstNode::kNoId, |
| 582 function.token_index(), |
| 580 kClosureArgumentMismatchRuntimeEntry); | 583 kClosureArgumentMismatchRuntimeEntry); |
| 581 } else { | 584 } else { |
| 582 __ Stop("Wrong number of arguments"); | 585 __ Stop("Wrong number of arguments"); |
| 583 } | 586 } |
| 584 __ Bind(&argc_in_range); | 587 __ Bind(&argc_in_range); |
| 585 } | 588 } |
| 586 } else { | 589 } else { |
| 587 ASSERT(first_param_index == -1); | 590 ASSERT(first_param_index == -1); |
| 588 // Copy positional arguments. | 591 // Copy positional arguments. |
| 589 // Check that no fewer than num_fixed_params positional arguments are passed | 592 // Check that no fewer than num_fixed_params positional arguments are passed |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 693 } | 696 } |
| 694 delete[] opt_param; | 697 delete[] opt_param; |
| 695 delete[] opt_param_position; | 698 delete[] opt_param_position; |
| 696 // Check that EDI now points to the null terminator in the array descriptor. | 699 // Check that EDI now points to the null terminator in the array descriptor. |
| 697 Label all_arguments_processed; | 700 Label all_arguments_processed; |
| 698 __ cmpl(Address(EDI, 0), raw_null); | 701 __ cmpl(Address(EDI, 0), raw_null); |
| 699 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); | 702 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
| 700 | 703 |
| 701 __ Bind(&wrong_num_arguments); | 704 __ Bind(&wrong_num_arguments); |
| 702 if (function.IsClosureFunction()) { | 705 if (function.IsClosureFunction()) { |
| 703 GenerateCallRuntime(function.token_index(), | 706 GenerateCallRuntime(AstNode::kNoId, |
| 707 function.token_index(), |
| 704 kClosureArgumentMismatchRuntimeEntry); | 708 kClosureArgumentMismatchRuntimeEntry); |
| 705 } else { | 709 } else { |
| 706 // Invoke noSuchMethod function. | 710 // Invoke noSuchMethod function. |
| 707 ICData ic_data(String::Handle(function.name()), 1); | 711 ICData ic_data(String::Handle(function.name()), 1); |
| 708 __ LoadObject(ECX, Array::ZoneHandle(ic_data.data())); | 712 __ LoadObject(ECX, Array::ZoneHandle(ic_data.data())); |
| 709 // EBP : points to previous frame pointer. | 713 // EBP : points to previous frame pointer. |
| 710 // EBP + 4 : points to return address. | 714 // EBP + 4 : points to return address. |
| 711 // EBP + 8 : address of last argument (arg n-1). | 715 // EBP + 8 : address of last argument (arg n-1). |
| 712 // ESP + 8 + 4*(n-1) : address of first argument (arg 0). | 716 // ESP + 8 + 4*(n-1) : address of first argument (arg 0). |
| 713 // ECX : ic-data array. | 717 // ECX : ic-data array. |
| 714 // EDX : arguments descriptor array. | 718 // EDX : arguments descriptor array. |
| 715 __ call(&StubCode::CallNoSuchMethodFunctionLabel()); | 719 __ call(&StubCode::CallNoSuchMethodFunctionLabel()); |
| 716 } | 720 } |
| 717 | 721 |
| 718 if (FLAG_trace_functions) { | 722 if (FLAG_trace_functions) { |
| 719 __ pushl(EAX); // Preserve result. | 723 __ pushl(EAX); // Preserve result. |
| 720 __ PushObject(function); | 724 __ PushObject(function); |
| 721 GenerateCallRuntime(0, kTraceFunctionExitRuntimeEntry); | 725 GenerateCallRuntime(AstNode::kNoId, |
| 726 0, |
| 727 kTraceFunctionExitRuntimeEntry); |
| 722 __ popl(EAX); // Remove argument. | 728 __ popl(EAX); // Remove argument. |
| 723 __ popl(EAX); // Restore result. | 729 __ popl(EAX); // Restore result. |
| 724 } | 730 } |
| 725 __ LeaveFrame(); | 731 __ LeaveFrame(); |
| 726 __ ret(); | 732 __ ret(); |
| 727 | 733 |
| 728 __ Bind(&all_arguments_processed); | 734 __ Bind(&all_arguments_processed); |
| 729 // Nullify originally passed arguments only after they have been copied and | 735 // Nullify originally passed arguments only after they have been copied and |
| 730 // checked, otherwise noSuchMethod would not see their original values. | 736 // checked, otherwise noSuchMethod would not see their original values. |
| 731 // This step can be skipped in case we decide that formal parameters are | 737 // This step can be skipped in case we decide that formal parameters are |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 783 __ LoadObject(EAX, literal); | 789 __ LoadObject(EAX, literal); |
| 784 } | 790 } |
| 785 } else { | 791 } else { |
| 786 // Pop the previously evaluated result value into EAX. | 792 // Pop the previously evaluated result value into EAX. |
| 787 __ popl(EAX); | 793 __ popl(EAX); |
| 788 } | 794 } |
| 789 | 795 |
| 790 // Generate type check. | 796 // Generate type check. |
| 791 if (FLAG_enable_type_checks) { | 797 if (FLAG_enable_type_checks) { |
| 792 GenerateAssertAssignable( | 798 GenerateAssertAssignable( |
| 799 node->id(), |
| 793 node->value()->token_index(), | 800 node->value()->token_index(), |
| 794 Type::ZoneHandle(parsed_function().function().result_type()), | 801 Type::ZoneHandle(parsed_function().function().result_type()), |
| 795 String::ZoneHandle(String::NewSymbol("function result"))); | 802 String::ZoneHandle(String::NewSymbol("function result"))); |
| 796 } | 803 } |
| 797 // Unchain the context(s) up to context level 0. | 804 // Unchain the context(s) up to context level 0. |
| 798 int context_level = state()->context_level(); | 805 int context_level = state()->context_level(); |
| 799 ASSERT(context_level >= 0); | 806 ASSERT(context_level >= 0); |
| 800 while (context_level-- > 0) { | 807 while (context_level-- > 0) { |
| 801 __ movl(CTX, FieldAddress(CTX, Context::parent_offset())); | 808 __ movl(CTX, FieldAddress(CTX, Context::parent_offset())); |
| 802 } | 809 } |
| 803 #ifdef DEBUG | 810 #ifdef DEBUG |
| 804 // Check that the entry stack size matches the exit stack size. | 811 // Check that the entry stack size matches the exit stack size. |
| 805 __ movl(EDX, EBP); | 812 __ movl(EDX, EBP); |
| 806 __ subl(EDX, ESP); | 813 __ subl(EDX, ESP); |
| 807 ASSERT(locals_space_size() >= 0); | 814 ASSERT(locals_space_size() >= 0); |
| 808 __ cmpl(EDX, Immediate(locals_space_size())); | 815 __ cmpl(EDX, Immediate(locals_space_size())); |
| 809 Label wrong_stack; | 816 Label wrong_stack; |
| 810 __ j(NOT_EQUAL, &wrong_stack, Assembler::kNearJump); | 817 __ j(NOT_EQUAL, &wrong_stack, Assembler::kNearJump); |
| 811 #endif // DEBUG. | 818 #endif // DEBUG. |
| 812 | 819 |
| 813 if (FLAG_trace_functions) { | 820 if (FLAG_trace_functions) { |
| 814 __ pushl(EAX); // Preserve result. | 821 __ pushl(EAX); // Preserve result. |
| 815 const Function& function = | 822 const Function& function = |
| 816 Function::ZoneHandle(parsed_function_.function().raw()); | 823 Function::ZoneHandle(parsed_function_.function().raw()); |
| 817 __ LoadObject(EBX, function); | 824 __ LoadObject(EBX, function); |
| 818 __ pushl(EBX); | 825 __ pushl(EBX); |
| 819 GenerateCallRuntime(0, kTraceFunctionExitRuntimeEntry); | 826 GenerateCallRuntime(AstNode::kNoId, |
| 827 0, |
| 828 kTraceFunctionExitRuntimeEntry); |
| 820 __ popl(EAX); // Remove argument. | 829 __ popl(EAX); // Remove argument. |
| 821 __ popl(EAX); // Restore result. | 830 __ popl(EAX); // Restore result. |
| 822 } | 831 } |
| 823 __ LeaveFrame(); | 832 __ LeaveFrame(); |
| 824 __ ret(); | 833 __ ret(); |
| 825 | 834 |
| 826 #ifdef DEBUG | 835 #ifdef DEBUG |
| 827 __ Bind(&wrong_stack); | 836 __ Bind(&wrong_stack); |
| 828 __ Stop("Exit stack size does not match the entry stack size."); | 837 __ Stop("Exit stack size does not match the entry stack size."); |
| 829 #endif // DEBUG. | 838 #endif // DEBUG. |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1001 if (IsResultNeeded(node)) { | 1010 if (IsResultNeeded(node)) { |
| 1002 GeneratePushVariable(node->local(), EAX); | 1011 GeneratePushVariable(node->local(), EAX); |
| 1003 } | 1012 } |
| 1004 } | 1013 } |
| 1005 | 1014 |
| 1006 | 1015 |
| 1007 void CodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { | 1016 void CodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { |
| 1008 node->value()->Visit(this); | 1017 node->value()->Visit(this); |
| 1009 __ popl(EAX); | 1018 __ popl(EAX); |
| 1010 if (FLAG_enable_type_checks) { | 1019 if (FLAG_enable_type_checks) { |
| 1011 GenerateAssertAssignable(node->value()->token_index(), | 1020 GenerateAssertAssignable(node->id(), |
| 1021 node->value()->token_index(), |
| 1012 node->local().type(), | 1022 node->local().type(), |
| 1013 node->local().name()); | 1023 node->local().name()); |
| 1014 } | 1024 } |
| 1015 GenerateStoreVariable(node->local(), EAX, EDX); | 1025 GenerateStoreVariable(node->local(), EAX, EDX); |
| 1016 if (IsResultNeeded(node)) { | 1026 if (IsResultNeeded(node)) { |
| 1017 __ pushl(EAX); | 1027 __ pushl(EAX); |
| 1018 } | 1028 } |
| 1019 } | 1029 } |
| 1020 | 1030 |
| 1021 | 1031 |
| 1022 void CodeGenerator::VisitLoadInstanceFieldNode(LoadInstanceFieldNode* node) { | 1032 void CodeGenerator::VisitLoadInstanceFieldNode(LoadInstanceFieldNode* node) { |
| 1023 node->instance()->Visit(this); | 1033 node->instance()->Visit(this); |
| 1024 MarkDeoptPoint(node->id(), node->token_index()); | 1034 MarkDeoptPoint(node->id(), node->token_index()); |
| 1025 __ popl(EAX); // Instance. | 1035 __ popl(EAX); // Instance. |
| 1026 __ movl(EAX, FieldAddress(EAX, node->field().Offset())); | 1036 __ movl(EAX, FieldAddress(EAX, node->field().Offset())); |
| 1027 if (IsResultNeeded(node)) { | 1037 if (IsResultNeeded(node)) { |
| 1028 __ pushl(EAX); | 1038 __ pushl(EAX); |
| 1029 } | 1039 } |
| 1030 } | 1040 } |
| 1031 | 1041 |
| 1032 | 1042 |
| 1033 void CodeGenerator::VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node) { | 1043 void CodeGenerator::VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node) { |
| 1034 node->instance()->Visit(this); | 1044 node->instance()->Visit(this); |
| 1035 node->value()->Visit(this); | 1045 node->value()->Visit(this); |
| 1036 MarkDeoptPoint(node->id(), node->token_index()); | 1046 MarkDeoptPoint(node->id(), node->token_index()); |
| 1037 __ popl(EAX); // Value. | 1047 __ popl(EAX); // Value. |
| 1038 if (FLAG_enable_type_checks) { | 1048 if (FLAG_enable_type_checks) { |
| 1039 GenerateAssertAssignable(node->value()->token_index(), | 1049 GenerateAssertAssignable(node->id(), |
| 1050 node->value()->token_index(), |
| 1040 Type::ZoneHandle(node->field().type()), | 1051 Type::ZoneHandle(node->field().type()), |
| 1041 String::ZoneHandle(node->field().name())); | 1052 String::ZoneHandle(node->field().name())); |
| 1042 } | 1053 } |
| 1043 __ popl(EDX); // Instance. | 1054 __ popl(EDX); // Instance. |
| 1044 __ StoreIntoObject(EDX, FieldAddress(EDX, node->field().Offset()), EAX); | 1055 __ StoreIntoObject(EDX, FieldAddress(EDX, node->field().Offset()), EAX); |
| 1045 if (IsResultNeeded(node)) { | 1056 if (IsResultNeeded(node)) { |
| 1046 // The result is the input value. | 1057 // The result is the input value. |
| 1047 __ pushl(EAX); | 1058 __ pushl(EAX); |
| 1048 } | 1059 } |
| 1049 } | 1060 } |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1130 __ pushl(EAX); | 1141 __ pushl(EAX); |
| 1131 } | 1142 } |
| 1132 } | 1143 } |
| 1133 | 1144 |
| 1134 | 1145 |
| 1135 void CodeGenerator::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) { | 1146 void CodeGenerator::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) { |
| 1136 node->value()->Visit(this); | 1147 node->value()->Visit(this); |
| 1137 MarkDeoptPoint(node->id(), node->token_index()); | 1148 MarkDeoptPoint(node->id(), node->token_index()); |
| 1138 __ popl(EAX); // Value. | 1149 __ popl(EAX); // Value. |
| 1139 if (FLAG_enable_type_checks) { | 1150 if (FLAG_enable_type_checks) { |
| 1140 GenerateAssertAssignable(node->value()->token_index(), | 1151 GenerateAssertAssignable(node->id(), |
| 1152 node->value()->token_index(), |
| 1141 Type::ZoneHandle(node->field().type()), | 1153 Type::ZoneHandle(node->field().type()), |
| 1142 String::ZoneHandle(node->field().name())); | 1154 String::ZoneHandle(node->field().name())); |
| 1143 } | 1155 } |
| 1144 __ LoadObject(EDX, node->field()); | 1156 __ LoadObject(EDX, node->field()); |
| 1145 __ StoreIntoObject(EDX, FieldAddress(EDX, Field::value_offset()), EAX); | 1157 __ StoreIntoObject(EDX, FieldAddress(EDX, Field::value_offset()), EAX); |
| 1146 if (IsResultNeeded(node)) { | 1158 if (IsResultNeeded(node)) { |
| 1147 // The result is the input value. | 1159 // The result is the input value. |
| 1148 __ pushl(EAX); | 1160 __ pushl(EAX); |
| 1149 } | 1161 } |
| 1150 } | 1162 } |
| 1151 | 1163 |
| 1152 | 1164 |
| 1153 void CodeGenerator::GenerateLogicalNotOp(UnaryOpNode* node) { | 1165 void CodeGenerator::GenerateLogicalNotOp(UnaryOpNode* node) { |
| 1154 // Generate false if operand is true, otherwise generate true. | 1166 // Generate false if operand is true, otherwise generate true. |
| 1155 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1167 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1156 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1168 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1157 node->operand()->Visit(this); | 1169 node->operand()->Visit(this); |
| 1158 MarkDeoptPoint(node->id(), node->token_index()); | 1170 MarkDeoptPoint(node->id(), node->token_index()); |
| 1159 Label done; | 1171 Label done; |
| 1160 GenerateConditionTypeCheck(node->operand()->token_index()); | 1172 GenerateConditionTypeCheck(node->id(), node->operand()->token_index()); |
| 1161 __ popl(EDX); | 1173 __ popl(EDX); |
| 1162 __ LoadObject(EAX, bool_true); | 1174 __ LoadObject(EAX, bool_true); |
| 1163 __ cmpl(EAX, EDX); | 1175 __ cmpl(EAX, EDX); |
| 1164 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 1176 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 1165 __ LoadObject(EAX, bool_false); | 1177 __ LoadObject(EAX, bool_false); |
| 1166 __ Bind(&done); | 1178 __ Bind(&done); |
| 1167 if (IsResultNeeded(node)) { | 1179 if (IsResultNeeded(node)) { |
| 1168 __ pushl(EAX); | 1180 __ pushl(EAX); |
| 1169 } | 1181 } |
| 1170 } | 1182 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1212 // Preserve as result. | 1224 // Preserve as result. |
| 1213 __ pushl(EAX); | 1225 __ pushl(EAX); |
| 1214 } | 1226 } |
| 1215 const Immediate value = Immediate(reinterpret_cast<int32_t>(Smi::New(1))); | 1227 const Immediate value = Immediate(reinterpret_cast<int32_t>(Smi::New(1))); |
| 1216 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-"; | 1228 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-"; |
| 1217 __ pushl(EAX); | 1229 __ pushl(EAX); |
| 1218 __ pushl(value); | 1230 __ pushl(value); |
| 1219 GenerateBinaryOperatorCall(node->id(), node->token_index(), operator_name); | 1231 GenerateBinaryOperatorCall(node->id(), node->token_index(), operator_name); |
| 1220 // result is in EAX. | 1232 // result is in EAX. |
| 1221 if (FLAG_enable_type_checks) { | 1233 if (FLAG_enable_type_checks) { |
| 1222 GenerateAssertAssignable( | 1234 GenerateAssertAssignable(node->id(), |
| 1223 node->token_index(), node->local().type(), node->local().name()); | 1235 node->token_index(), |
| 1236 node->local().type(), |
| 1237 node->local().name()); |
| 1224 } | 1238 } |
| 1225 GenerateStoreVariable(node->local(), EAX, EDX); | 1239 GenerateStoreVariable(node->local(), EAX, EDX); |
| 1226 if (node->prefix() && IsResultNeeded(node)) { | 1240 if (node->prefix() && IsResultNeeded(node)) { |
| 1227 __ pushl(EAX); | 1241 __ pushl(EAX); |
| 1228 } | 1242 } |
| 1229 } | 1243 } |
| 1230 | 1244 |
| 1231 | 1245 |
| 1232 void CodeGenerator::VisitIncrOpInstanceFieldNode( | 1246 void CodeGenerator::VisitIncrOpInstanceFieldNode( |
| 1233 IncrOpInstanceFieldNode* node) { | 1247 IncrOpInstanceFieldNode* node) { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1296 } | 1310 } |
| 1297 if (node->field().IsNull()) { | 1311 if (node->field().IsNull()) { |
| 1298 __ pushl(EAX); | 1312 __ pushl(EAX); |
| 1299 // It is not necessary to generate a type test of the assigned value here, | 1313 // It is not necessary to generate a type test of the assigned value here, |
| 1300 // because the setter will check the type of its incoming arguments. | 1314 // because the setter will check the type of its incoming arguments. |
| 1301 GenerateStaticSetterCall(node->token_index(), | 1315 GenerateStaticSetterCall(node->token_index(), |
| 1302 node->field_class(), | 1316 node->field_class(), |
| 1303 node->field_name()); | 1317 node->field_name()); |
| 1304 } else { | 1318 } else { |
| 1305 if (FLAG_enable_type_checks) { | 1319 if (FLAG_enable_type_checks) { |
| 1306 GenerateAssertAssignable(node->token_index(), | 1320 GenerateAssertAssignable(node->id(), |
| 1321 node->token_index(), |
| 1307 Type::ZoneHandle(node->field().type()), | 1322 Type::ZoneHandle(node->field().type()), |
| 1308 String::ZoneHandle(node->field().name())); | 1323 String::ZoneHandle(node->field().name())); |
| 1309 } | 1324 } |
| 1310 __ LoadObject(EDX, node->field()); | 1325 __ LoadObject(EDX, node->field()); |
| 1311 __ StoreIntoObject(EDX, FieldAddress(EDX, Field::value_offset()), EAX); | 1326 __ StoreIntoObject(EDX, FieldAddress(EDX, Field::value_offset()), EAX); |
| 1312 } | 1327 } |
| 1313 } | 1328 } |
| 1314 | 1329 |
| 1315 | 1330 |
| 1316 void CodeGenerator::VisitIncrOpIndexedNode(IncrOpIndexedNode* node) { | 1331 void CodeGenerator::VisitIncrOpIndexedNode(IncrOpIndexedNode* node) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1348 | 1363 |
| 1349 // Optimize instanceof type test by adding inlined tests for: | 1364 // Optimize instanceof type test by adding inlined tests for: |
| 1350 // - NULL -> return false. | 1365 // - NULL -> return false. |
| 1351 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 1366 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 1352 // - Class equality (only if class is not parameterized). | 1367 // - Class equality (only if class is not parameterized). |
| 1353 // Inputs: | 1368 // Inputs: |
| 1354 // - EAX: object. | 1369 // - EAX: object. |
| 1355 // Destroys ECX. | 1370 // Destroys ECX. |
| 1356 // Returns: | 1371 // Returns: |
| 1357 // - true or false on stack. | 1372 // - true or false on stack. |
| 1358 void CodeGenerator::GenerateInstanceOf(intptr_t token_index, | 1373 void CodeGenerator::GenerateInstanceOf(intptr_t node_id, |
| 1374 intptr_t token_index, |
| 1359 const Type& type, | 1375 const Type& type, |
| 1360 bool negate_result) { | 1376 bool negate_result) { |
| 1361 ASSERT(type.IsFinalized()); | 1377 ASSERT(type.IsFinalized()); |
| 1362 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1378 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1363 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1379 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1364 | 1380 |
| 1365 // All instances are of type Object. | 1381 // All instances are of type Object. |
| 1366 const Type& object_type = | 1382 const Type& object_type = |
| 1367 Type::Handle(Isolate::Current()->object_store()->object_type()); | 1383 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 1368 if (type.IsInstantiated() && object_type.IsSubtypeOf(type)) { | 1384 if (type.IsInstantiated() && object_type.IsSubtypeOf(type)) { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1425 } | 1441 } |
| 1426 const Object& result = Object::ZoneHandle(); | 1442 const Object& result = Object::ZoneHandle(); |
| 1427 __ PushObject(result); // Make room for the result of the runtime call. | 1443 __ PushObject(result); // Make room for the result of the runtime call. |
| 1428 __ pushl(EAX); // Push the instance. | 1444 __ pushl(EAX); // Push the instance. |
| 1429 __ PushObject(type); // Push the type. | 1445 __ PushObject(type); // Push the type. |
| 1430 if (!type.IsInstantiated()) { | 1446 if (!type.IsInstantiated()) { |
| 1431 GenerateInstantiatorTypeArguments(token_index); | 1447 GenerateInstantiatorTypeArguments(token_index); |
| 1432 } else { | 1448 } else { |
| 1433 __ pushl(raw_null); // Null instantiator. | 1449 __ pushl(raw_null); // Null instantiator. |
| 1434 } | 1450 } |
| 1435 GenerateCallRuntime(token_index, kInstanceofRuntimeEntry); | 1451 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); |
| 1436 // Pop the two parameters supplied to the runtime entry. The result of the | 1452 // Pop the two parameters supplied to the runtime entry. The result of the |
| 1437 // instanceof runtime call will be left as the result of the operation. | 1453 // instanceof runtime call will be left as the result of the operation. |
| 1438 __ addl(ESP, Immediate(3 * kWordSize)); | 1454 __ addl(ESP, Immediate(3 * kWordSize)); |
| 1439 if (negate_result) { | 1455 if (negate_result) { |
| 1440 Label negate_done; | 1456 Label negate_done; |
| 1441 __ popl(EDX); | 1457 __ popl(EDX); |
| 1442 __ LoadObject(EAX, bool_true); | 1458 __ LoadObject(EAX, bool_true); |
| 1443 __ cmpl(EDX, EAX); | 1459 __ cmpl(EDX, EAX); |
| 1444 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); | 1460 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); |
| 1445 __ LoadObject(EAX, bool_false); | 1461 __ LoadObject(EAX, bool_false); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1465 | 1481 |
| 1466 // Optimize assignable type check by adding inlined tests for: | 1482 // Optimize assignable type check by adding inlined tests for: |
| 1467 // - NULL -> return NULL. | 1483 // - NULL -> return NULL. |
| 1468 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 1484 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 1469 // - Class equality (only if class is not parameterized). | 1485 // - Class equality (only if class is not parameterized). |
| 1470 // Inputs: | 1486 // Inputs: |
| 1471 // - EAX: object. | 1487 // - EAX: object. |
| 1472 // Destroys ECX and EDX. | 1488 // Destroys ECX and EDX. |
| 1473 // Returns: | 1489 // Returns: |
| 1474 // - object in EAX for successful assignable check (or throws TypeError). | 1490 // - object in EAX for successful assignable check (or throws TypeError). |
| 1475 void CodeGenerator::GenerateAssertAssignable(intptr_t token_index, | 1491 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, |
| 1492 intptr_t token_index, |
| 1476 const Type& dst_type, | 1493 const Type& dst_type, |
| 1477 const String& dst_name) { | 1494 const String& dst_name) { |
| 1478 ASSERT(FLAG_enable_type_checks); | 1495 ASSERT(FLAG_enable_type_checks); |
| 1479 ASSERT(token_index >= 0); | 1496 ASSERT(token_index >= 0); |
| 1480 ASSERT(!dst_type.IsNull()); | 1497 ASSERT(!dst_type.IsNull()); |
| 1481 ASSERT(dst_type.IsFinalized()); | 1498 ASSERT(dst_type.IsFinalized()); |
| 1482 | 1499 |
| 1483 // Any expression is assignable to the DynamicType. Skip the test. | 1500 // Any expression is assignable to the DynamicType. Skip the test. |
| 1484 if (dst_type.IsDynamicType()) { | 1501 if (dst_type.IsDynamicType()) { |
| 1485 return; | 1502 return; |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1583 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); | 1600 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); |
| 1584 __ pushl(location); // Push the source location. | 1601 __ pushl(location); // Push the source location. |
| 1585 __ pushl(EAX); // Push the source object. | 1602 __ pushl(EAX); // Push the source object. |
| 1586 __ PushObject(dst_type); // Push the type of the destination. | 1603 __ PushObject(dst_type); // Push the type of the destination. |
| 1587 if (!dst_type.IsInstantiated()) { | 1604 if (!dst_type.IsInstantiated()) { |
| 1588 GenerateInstantiatorTypeArguments(token_index); | 1605 GenerateInstantiatorTypeArguments(token_index); |
| 1589 } else { | 1606 } else { |
| 1590 __ pushl(raw_null); // Null instantiator. | 1607 __ pushl(raw_null); // Null instantiator. |
| 1591 } | 1608 } |
| 1592 __ PushObject(dst_name); // Push the name of the destination. | 1609 __ PushObject(dst_name); // Push the name of the destination. |
| 1593 GenerateCallRuntime(token_index, kTypeCheckRuntimeEntry); | 1610 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); |
| 1594 // Pop the parameters supplied to the runtime entry. The result of the | 1611 // Pop the parameters supplied to the runtime entry. The result of the |
| 1595 // type check runtime call is the checked value. | 1612 // type check runtime call is the checked value. |
| 1596 __ addl(ESP, Immediate(5 * kWordSize)); | 1613 __ addl(ESP, Immediate(5 * kWordSize)); |
| 1597 __ popl(EAX); | 1614 __ popl(EAX); |
| 1598 | 1615 |
| 1599 __ Bind(&done); | 1616 __ Bind(&done); |
| 1600 } | 1617 } |
| 1601 | 1618 |
| 1602 | 1619 |
| 1603 void CodeGenerator::GenerateArgumentTypeChecks() { | 1620 void CodeGenerator::GenerateArgumentTypeChecks() { |
| 1604 const Function& function = parsed_function_.function(); | 1621 const Function& function = parsed_function_.function(); |
| 1605 LocalScope* scope = parsed_function_.node_sequence()->scope(); | 1622 LocalScope* scope = parsed_function_.node_sequence()->scope(); |
| 1606 const int num_fixed_params = function.num_fixed_parameters(); | 1623 const int num_fixed_params = function.num_fixed_parameters(); |
| 1607 const int num_opt_params = function.num_optional_parameters(); | 1624 const int num_opt_params = function.num_optional_parameters(); |
| 1608 ASSERT(num_fixed_params + num_opt_params <= scope->num_variables()); | 1625 ASSERT(num_fixed_params + num_opt_params <= scope->num_variables()); |
| 1609 for (int i = 0; i < num_fixed_params + num_opt_params; i++) { | 1626 for (int i = 0; i < num_fixed_params + num_opt_params; i++) { |
| 1610 LocalVariable* parameter = scope->VariableAt(i); | 1627 LocalVariable* parameter = scope->VariableAt(i); |
| 1611 GenerateLoadVariable(EAX, *parameter); | 1628 GenerateLoadVariable(EAX, *parameter); |
| 1612 GenerateAssertAssignable( | 1629 GenerateAssertAssignable(AstNode::kNoId, |
| 1613 parameter->token_index(), parameter->type(), parameter->name()); | 1630 parameter->token_index(), |
| 1631 parameter->type(), |
| 1632 parameter->name()); |
| 1614 } | 1633 } |
| 1615 } | 1634 } |
| 1616 | 1635 |
| 1617 | 1636 |
| 1618 void CodeGenerator::GenerateConditionTypeCheck(intptr_t token_index) { | 1637 void CodeGenerator::GenerateConditionTypeCheck(intptr_t node_id, |
| 1638 intptr_t token_index) { |
| 1619 if (!FLAG_enable_type_checks) { | 1639 if (!FLAG_enable_type_checks) { |
| 1620 return; | 1640 return; |
| 1621 } | 1641 } |
| 1622 | 1642 |
| 1623 // Check that the type of the object on the stack is allowed in conditional | 1643 // Check that the type of the object on the stack is allowed in conditional |
| 1624 // context. | 1644 // context. |
| 1625 // Call the runtime if the object is null or not of type bool. | 1645 // Call the runtime if the object is null or not of type bool. |
| 1626 const Immediate raw_null = | 1646 const Immediate raw_null = |
| 1627 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1647 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1628 Label runtime_call, done; | 1648 Label runtime_call, done; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1640 __ CompareObject(ECX, bool_class); | 1660 __ CompareObject(ECX, bool_class); |
| 1641 __ j(EQUAL, &done, Assembler::kNearJump); | 1661 __ j(EQUAL, &done, Assembler::kNearJump); |
| 1642 | 1662 |
| 1643 __ Bind(&runtime_call); | 1663 __ Bind(&runtime_call); |
| 1644 const Object& result = Object::ZoneHandle(); | 1664 const Object& result = Object::ZoneHandle(); |
| 1645 __ PushObject(result); // Make room for the result of the runtime call. | 1665 __ PushObject(result); // Make room for the result of the runtime call. |
| 1646 const Immediate location = | 1666 const Immediate location = |
| 1647 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); | 1667 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); |
| 1648 __ pushl(location); // Push the source location. | 1668 __ pushl(location); // Push the source location. |
| 1649 __ pushl(EAX); // Push the source object. | 1669 __ pushl(EAX); // Push the source object. |
| 1650 GenerateCallRuntime(token_index, kConditionTypeErrorRuntimeEntry); | 1670 GenerateCallRuntime(node_id, token_index, kConditionTypeErrorRuntimeEntry); |
| 1651 // Pop the parameters supplied to the runtime entry. The result of the | 1671 // Pop the parameters supplied to the runtime entry. The result of the |
| 1652 // type check runtime call is the checked value. | 1672 // type check runtime call is the checked value. |
| 1653 __ addl(ESP, Immediate(3 * kWordSize)); | 1673 __ addl(ESP, Immediate(3 * kWordSize)); |
| 1654 | 1674 |
| 1655 __ Bind(&done); | 1675 __ Bind(&done); |
| 1656 } | 1676 } |
| 1657 | 1677 |
| 1658 | 1678 |
| 1659 void CodeGenerator::VisitComparisonNode(ComparisonNode* node) { | 1679 void CodeGenerator::VisitComparisonNode(ComparisonNode* node) { |
| 1660 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1680 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1661 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1681 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1662 node->left()->Visit(this); | 1682 node->left()->Visit(this); |
| 1663 | 1683 |
| 1664 // The instanceof operator needs special handling. | 1684 // The instanceof operator needs special handling. |
| 1665 if (Token::IsInstanceofOperator(node->kind())) { | 1685 if (Token::IsInstanceofOperator(node->kind())) { |
| 1666 __ popl(EAX); // Left operand. | 1686 __ popl(EAX); // Left operand. |
| 1667 ASSERT(node->right()->IsTypeNode()); | 1687 ASSERT(node->right()->IsTypeNode()); |
| 1668 GenerateInstanceOf(node->token_index(), | 1688 GenerateInstanceOf(node->id(), |
| 1689 node->token_index(), |
| 1669 node->right()->AsTypeNode()->type(), | 1690 node->right()->AsTypeNode()->type(), |
| 1670 (node->kind() == Token::kISNOT)); | 1691 (node->kind() == Token::kISNOT)); |
| 1671 if (!IsResultNeeded(node)) { | 1692 if (!IsResultNeeded(node)) { |
| 1672 __ popl(EAX); // Pop the result of the instanceof operation. | 1693 __ popl(EAX); // Pop the result of the instanceof operation. |
| 1673 } | 1694 } |
| 1674 return; | 1695 return; |
| 1675 } | 1696 } |
| 1676 | 1697 |
| 1677 node->right()->Visit(this); | 1698 node->right()->Visit(this); |
| 1678 // Both left and right values on stack. | 1699 // Both left and right values on stack. |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1790 __ movl(FieldAddress(EAX, Function::invocation_counter_offset()), EBX); | 1811 __ movl(FieldAddress(EAX, Function::invocation_counter_offset()), EBX); |
| 1791 __ Bind(&done); | 1812 __ Bind(&done); |
| 1792 } | 1813 } |
| 1793 | 1814 |
| 1794 | 1815 |
| 1795 void CodeGenerator::VisitWhileNode(WhileNode* node) { | 1816 void CodeGenerator::VisitWhileNode(WhileNode* node) { |
| 1796 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1817 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1797 SourceLabel* label = node->label(); | 1818 SourceLabel* label = node->label(); |
| 1798 __ Bind(label->continue_label()); | 1819 __ Bind(label->continue_label()); |
| 1799 node->condition()->Visit(this); | 1820 node->condition()->Visit(this); |
| 1800 GenerateConditionTypeCheck(node->condition()->token_index()); | 1821 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); |
| 1801 __ popl(EAX); | 1822 __ popl(EAX); |
| 1802 __ LoadObject(EDX, bool_true); | 1823 __ LoadObject(EDX, bool_true); |
| 1803 __ cmpl(EAX, EDX); | 1824 __ cmpl(EAX, EDX); |
| 1804 __ j(NOT_EQUAL, label->break_label()); | 1825 __ j(NOT_EQUAL, label->break_label()); |
| 1805 node->body()->Visit(this); | 1826 node->body()->Visit(this); |
| 1806 CountBackwardLoop(); | 1827 CountBackwardLoop(); |
| 1807 __ jmp(label->continue_label()); | 1828 __ jmp(label->continue_label()); |
| 1808 __ Bind(label->break_label()); | 1829 __ Bind(label->break_label()); |
| 1809 } | 1830 } |
| 1810 | 1831 |
| 1811 | 1832 |
| 1812 void CodeGenerator::VisitDoWhileNode(DoWhileNode* node) { | 1833 void CodeGenerator::VisitDoWhileNode(DoWhileNode* node) { |
| 1813 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1834 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1814 SourceLabel* label = node->label(); | 1835 SourceLabel* label = node->label(); |
| 1815 Label loop; | 1836 Label loop; |
| 1816 __ Bind(&loop); | 1837 __ Bind(&loop); |
| 1817 node->body()->Visit(this); | 1838 node->body()->Visit(this); |
| 1818 CountBackwardLoop(); | 1839 CountBackwardLoop(); |
| 1819 __ Bind(label->continue_label()); | 1840 __ Bind(label->continue_label()); |
| 1820 node->condition()->Visit(this); | 1841 node->condition()->Visit(this); |
| 1821 GenerateConditionTypeCheck(node->condition()->token_index()); | 1842 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); |
| 1822 __ popl(EAX); | 1843 __ popl(EAX); |
| 1823 __ LoadObject(EDX, bool_true); | 1844 __ LoadObject(EDX, bool_true); |
| 1824 __ cmpl(EAX, EDX); | 1845 __ cmpl(EAX, EDX); |
| 1825 __ j(EQUAL, &loop); | 1846 __ j(EQUAL, &loop); |
| 1826 __ Bind(label->break_label()); | 1847 __ Bind(label->break_label()); |
| 1827 } | 1848 } |
| 1828 | 1849 |
| 1829 | 1850 |
| 1830 void CodeGenerator::VisitForNode(ForNode* node) { | 1851 void CodeGenerator::VisitForNode(ForNode* node) { |
| 1831 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1852 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1832 node->initializer()->Visit(this); | 1853 node->initializer()->Visit(this); |
| 1833 SourceLabel* label = node->label(); | 1854 SourceLabel* label = node->label(); |
| 1834 Label loop; | 1855 Label loop; |
| 1835 __ Bind(&loop); | 1856 __ Bind(&loop); |
| 1836 if (node->condition() != NULL) { | 1857 if (node->condition() != NULL) { |
| 1837 node->condition()->Visit(this); | 1858 node->condition()->Visit(this); |
| 1838 GenerateConditionTypeCheck(node->condition()->token_index()); | 1859 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); |
| 1839 __ popl(EAX); | 1860 __ popl(EAX); |
| 1840 __ LoadObject(EDX, bool_true); | 1861 __ LoadObject(EDX, bool_true); |
| 1841 __ cmpl(EAX, EDX); | 1862 __ cmpl(EAX, EDX); |
| 1842 __ j(NOT_EQUAL, label->break_label()); | 1863 __ j(NOT_EQUAL, label->break_label()); |
| 1843 } | 1864 } |
| 1844 node->body()->Visit(this); | 1865 node->body()->Visit(this); |
| 1845 CountBackwardLoop(); | 1866 CountBackwardLoop(); |
| 1846 __ Bind(label->continue_label()); | 1867 __ Bind(label->continue_label()); |
| 1847 node->increment()->Visit(this); | 1868 node->increment()->Visit(this); |
| 1848 __ jmp(&loop); | 1869 __ jmp(&loop); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1880 } else { | 1901 } else { |
| 1881 __ jmp(label->continue_label()); | 1902 __ jmp(label->continue_label()); |
| 1882 } | 1903 } |
| 1883 } | 1904 } |
| 1884 | 1905 |
| 1885 | 1906 |
| 1886 void CodeGenerator::VisitConditionalExprNode(ConditionalExprNode* node) { | 1907 void CodeGenerator::VisitConditionalExprNode(ConditionalExprNode* node) { |
| 1887 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1908 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1888 Label false_label, done; | 1909 Label false_label, done; |
| 1889 node->condition()->Visit(this); | 1910 node->condition()->Visit(this); |
| 1890 GenerateConditionTypeCheck(node->condition()->token_index()); | 1911 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); |
| 1891 __ popl(EAX); | 1912 __ popl(EAX); |
| 1892 __ LoadObject(EDX, bool_true); | 1913 __ LoadObject(EDX, bool_true); |
| 1893 __ cmpl(EAX, EDX); | 1914 __ cmpl(EAX, EDX); |
| 1894 __ j(NOT_EQUAL, &false_label); | 1915 __ j(NOT_EQUAL, &false_label); |
| 1895 node->true_expr()->Visit(this); | 1916 node->true_expr()->Visit(this); |
| 1896 __ jmp(&done); | 1917 __ jmp(&done); |
| 1897 __ Bind(&false_label); | 1918 __ Bind(&false_label); |
| 1898 node->false_expr()->Visit(this); | 1919 node->false_expr()->Visit(this); |
| 1899 __ Bind(&done); | 1920 __ Bind(&done); |
| 1900 if (!IsResultNeeded(node)) { | 1921 if (!IsResultNeeded(node)) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1940 __ Bind(&case_statements); | 1961 __ Bind(&case_statements); |
| 1941 node->statements()->Visit(this); | 1962 node->statements()->Visit(this); |
| 1942 __ Bind(&end_case); | 1963 __ Bind(&end_case); |
| 1943 } | 1964 } |
| 1944 | 1965 |
| 1945 | 1966 |
| 1946 void CodeGenerator::VisitIfNode(IfNode* node) { | 1967 void CodeGenerator::VisitIfNode(IfNode* node) { |
| 1947 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1968 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1948 Label false_label; | 1969 Label false_label; |
| 1949 node->condition()->Visit(this); | 1970 node->condition()->Visit(this); |
| 1950 GenerateConditionTypeCheck(node->condition()->token_index()); | 1971 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); |
| 1951 __ popl(EAX); | 1972 __ popl(EAX); |
| 1952 __ LoadObject(EDX, bool_true); | 1973 __ LoadObject(EDX, bool_true); |
| 1953 __ cmpl(EAX, EDX); | 1974 __ cmpl(EAX, EDX); |
| 1954 __ j(NOT_EQUAL, &false_label); | 1975 __ j(NOT_EQUAL, &false_label); |
| 1955 node->true_branch()->Visit(this); | 1976 node->true_branch()->Visit(this); |
| 1956 if (node->false_branch() != NULL) { | 1977 if (node->false_branch() != NULL) { |
| 1957 Label done; | 1978 Label done; |
| 1958 __ jmp(&done); | 1979 __ jmp(&done); |
| 1959 __ Bind(&false_label); | 1980 __ Bind(&false_label); |
| 1960 node->false_branch()->Visit(this); | 1981 node->false_branch()->Visit(this); |
| 1961 __ Bind(&done); | 1982 __ Bind(&done); |
| 1962 } else { | 1983 } else { |
| 1963 __ Bind(&false_label); | 1984 __ Bind(&false_label); |
| 1964 } | 1985 } |
| 1965 } | 1986 } |
| 1966 | 1987 |
| 1967 | 1988 |
| 1968 // Operators '&&' and '||' are not overloadabled, inline them. | 1989 // Operators '&&' and '||' are not overloadabled, inline them. |
| 1969 void CodeGenerator::GenerateLogicalAndOrOp(BinaryOpNode* node) { | 1990 void CodeGenerator::GenerateLogicalAndOrOp(BinaryOpNode* node) { |
| 1970 // Generate true if (left == true) op (right == true), otherwise generate | 1991 // Generate true if (left == true) op (right == true), otherwise generate |
| 1971 // false, with op being either || or &&. | 1992 // false, with op being either || or &&. |
| 1972 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1993 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1973 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1994 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1974 Label load_false, done; | 1995 Label load_false, done; |
| 1975 node->left()->Visit(this); | 1996 node->left()->Visit(this); |
| 1976 GenerateConditionTypeCheck(node->left()->token_index()); | 1997 GenerateConditionTypeCheck(node->id(), node->left()->token_index()); |
| 1977 __ popl(EAX); | 1998 __ popl(EAX); |
| 1978 __ LoadObject(EDX, bool_true); | 1999 __ LoadObject(EDX, bool_true); |
| 1979 __ cmpl(EAX, EDX); | 2000 __ cmpl(EAX, EDX); |
| 1980 if (node->kind() == Token::kAND) { | 2001 if (node->kind() == Token::kAND) { |
| 1981 __ j(NOT_EQUAL, &load_false); | 2002 __ j(NOT_EQUAL, &load_false); |
| 1982 } else { | 2003 } else { |
| 1983 ASSERT(node->kind() == Token::kOR); | 2004 ASSERT(node->kind() == Token::kOR); |
| 1984 __ j(EQUAL, &done); | 2005 __ j(EQUAL, &done); |
| 1985 } | 2006 } |
| 1986 node->right()->Visit(this); | 2007 node->right()->Visit(this); |
| 1987 GenerateConditionTypeCheck(node->right()->token_index()); | 2008 GenerateConditionTypeCheck(node->id(), node->right()->token_index()); |
| 1988 __ popl(EAX); | 2009 __ popl(EAX); |
| 1989 __ LoadObject(EDX, bool_true); | 2010 __ LoadObject(EDX, bool_true); |
| 1990 __ cmpl(EAX, EDX); | 2011 __ cmpl(EAX, EDX); |
| 1991 __ j(EQUAL, &done); | 2012 __ j(EQUAL, &done); |
| 1992 __ Bind(&load_false); | 2013 __ Bind(&load_false); |
| 1993 __ LoadObject(EAX, bool_false); | 2014 __ LoadObject(EAX, bool_false); |
| 1994 __ Bind(&done); | 2015 __ Bind(&done); |
| 1995 if (IsResultNeeded(node)) { | 2016 if (IsResultNeeded(node)) { |
| 1996 __ pushl(EAX); | 2017 __ pushl(EAX); |
| 1997 } | 2018 } |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2250 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 2271 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 2251 } | 2272 } |
| 2252 __ Bind(&type_arguments_uninstantiated); | 2273 __ Bind(&type_arguments_uninstantiated); |
| 2253 if (node->constructor().IsFactory()) { | 2274 if (node->constructor().IsFactory()) { |
| 2254 // A runtime call to instantiate the type arguments is required before | 2275 // A runtime call to instantiate the type arguments is required before |
| 2255 // calling the factory. | 2276 // calling the factory. |
| 2256 const Object& result = Object::ZoneHandle(); | 2277 const Object& result = Object::ZoneHandle(); |
| 2257 __ PushObject(result); // Make room for the result of the runtime call. | 2278 __ PushObject(result); // Make room for the result of the runtime call. |
| 2258 __ PushObject(node->type_arguments()); | 2279 __ PushObject(node->type_arguments()); |
| 2259 __ pushl(EAX); // Push instantiator type arguments. | 2280 __ pushl(EAX); // Push instantiator type arguments. |
| 2260 GenerateCallRuntime(node->token_index(), | 2281 GenerateCallRuntime(node->id(), |
| 2282 node->token_index(), |
| 2261 kInstantiateTypeArgumentsRuntimeEntry); | 2283 kInstantiateTypeArgumentsRuntimeEntry); |
| 2262 __ popl(EAX); // Pop instantiator type arguments. | 2284 __ popl(EAX); // Pop instantiator type arguments. |
| 2263 __ popl(EAX); // Pop uninstantiated type arguments. | 2285 __ popl(EAX); // Pop uninstantiated type arguments. |
| 2264 __ popl(EAX); // Pop instantiated type arguments. | 2286 __ popl(EAX); // Pop instantiated type arguments. |
| 2265 __ Bind(&type_arguments_instantiated); | 2287 __ Bind(&type_arguments_instantiated); |
| 2266 __ pushl(EAX); // Instantiated type arguments. | 2288 __ pushl(EAX); // Instantiated type arguments. |
| 2267 } else { | 2289 } else { |
| 2268 // In the non-factory case, we rely on the allocation stub to | 2290 // In the non-factory case, we rely on the allocation stub to |
| 2269 // instantiate the type arguments. | 2291 // instantiate the type arguments. |
| 2270 __ PushObject(node->type_arguments()); | 2292 __ PushObject(node->type_arguments()); |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2567 | 2589 |
| 2568 | 2590 |
| 2569 void CodeGenerator::VisitThrowNode(ThrowNode* node) { | 2591 void CodeGenerator::VisitThrowNode(ThrowNode* node) { |
| 2570 const Object& result = Object::ZoneHandle(); | 2592 const Object& result = Object::ZoneHandle(); |
| 2571 node->exception()->Visit(this); | 2593 node->exception()->Visit(this); |
| 2572 __ popl(EAX); // Exception object is now in EAX. | 2594 __ popl(EAX); // Exception object is now in EAX. |
| 2573 if (node->stacktrace() != NULL) { | 2595 if (node->stacktrace() != NULL) { |
| 2574 __ PushObject(result); // Make room for the result of the runtime call. | 2596 __ PushObject(result); // Make room for the result of the runtime call. |
| 2575 __ pushl(EAX); // Push the exception object. | 2597 __ pushl(EAX); // Push the exception object. |
| 2576 node->stacktrace()->Visit(this); | 2598 node->stacktrace()->Visit(this); |
| 2577 GenerateCallRuntime(node->token_index(), kReThrowRuntimeEntry); | 2599 GenerateCallRuntime(node->id(), node->token_index(), kReThrowRuntimeEntry); |
| 2578 } else { | 2600 } else { |
| 2579 __ PushObject(result); // Make room for the result of the runtime call. | 2601 __ PushObject(result); // Make room for the result of the runtime call. |
| 2580 __ pushl(EAX); // Push the exception object. | 2602 __ pushl(EAX); // Push the exception object. |
| 2581 GenerateCallRuntime(node->token_index(), kThrowRuntimeEntry); | 2603 GenerateCallRuntime(node->id(), node->token_index(), kThrowRuntimeEntry); |
| 2582 } | 2604 } |
| 2583 // We should never return here. | 2605 // We should never return here. |
| 2584 __ int3(); | 2606 __ int3(); |
| 2585 } | 2607 } |
| 2586 | 2608 |
| 2587 | 2609 |
| 2588 void CodeGenerator::VisitInlinedFinallyNode(InlinedFinallyNode* node) { | 2610 void CodeGenerator::VisitInlinedFinallyNode(InlinedFinallyNode* node) { |
| 2589 int try_index = state()->try_index(); | 2611 int try_index = state()->try_index(); |
| 2590 if (try_index >= 0) { | 2612 if (try_index >= 0) { |
| 2591 // We are about to generate code for an inlined finally block. Exceptions | 2613 // We are about to generate code for an inlined finally block. Exceptions |
| 2592 // thrown in this block of code should be treated as though they are | 2614 // thrown in this block of code should be treated as though they are |
| 2593 // thrown not from the current try block but the outer try block if any. | 2615 // thrown not from the current try block but the outer try block if any. |
| 2594 // the code generator state. | 2616 // the code generator state. |
| 2595 state()->set_try_index((try_index - 1)); | 2617 state()->set_try_index((try_index - 1)); |
| 2596 } | 2618 } |
| 2597 | 2619 |
| 2598 // Restore CTX from local variable ':saved_context'. | 2620 // Restore CTX from local variable ':saved_context'. |
| 2599 GenerateLoadVariable(CTX, node->context_var()); | 2621 GenerateLoadVariable(CTX, node->context_var()); |
| 2600 node->finally_block()->Visit(this); | 2622 node->finally_block()->Visit(this); |
| 2601 | 2623 |
| 2602 if (try_index >= 0) { | 2624 if (try_index >= 0) { |
| 2603 state()->set_try_index(try_index); | 2625 state()->set_try_index(try_index); |
| 2604 } | 2626 } |
| 2605 } | 2627 } |
| 2606 | 2628 |
| 2607 | 2629 |
| 2608 void CodeGenerator::GenerateCall(intptr_t token_index, | 2630 void CodeGenerator::GenerateCall(intptr_t token_index, |
| 2609 const ExternalLabel* ext_label) { | 2631 const ExternalLabel* ext_label) { |
| 2610 __ call(ext_label); | 2632 __ call(ext_label); |
| 2611 AddCurrentDescriptor(PcDescriptors::kOther, AstNode::kInvalidId, token_index); | 2633 AddCurrentDescriptor(PcDescriptors::kOther, AstNode::kNoId, token_index); |
| 2612 } | 2634 } |
| 2613 | 2635 |
| 2614 | 2636 |
| 2615 void CodeGenerator::GenerateCallRuntime(intptr_t token_index, | 2637 void CodeGenerator::GenerateCallRuntime(intptr_t node_id, |
| 2638 intptr_t token_index, |
| 2616 const RuntimeEntry& entry) { | 2639 const RuntimeEntry& entry) { |
| 2617 __ CallRuntimeFromDart(entry); | 2640 __ CallRuntimeFromDart(entry); |
| 2618 AddCurrentDescriptor(PcDescriptors::kOther, AstNode::kInvalidId, token_index); | 2641 AddCurrentDescriptor(PcDescriptors::kOther, node_id, token_index); |
| 2619 } | 2642 } |
| 2620 | 2643 |
| 2621 | 2644 |
| 2622 void CodeGenerator::MarkDeoptPoint(intptr_t node_id, | 2645 void CodeGenerator::MarkDeoptPoint(intptr_t node_id, |
| 2623 intptr_t token_index) { | 2646 intptr_t token_index) { |
| 2624 ASSERT(node_id != AstNode::kInvalidId); | 2647 ASSERT(node_id != AstNode::kNoId); |
| 2625 AddCurrentDescriptor(PcDescriptors::kDeopt, node_id, token_index); | 2648 AddCurrentDescriptor(PcDescriptors::kDeopt, node_id, token_index); |
| 2626 } | 2649 } |
| 2627 | 2650 |
| 2628 | 2651 |
| 2629 // Uses current pc position and try-index. | 2652 // Uses current pc position and try-index. |
| 2630 void CodeGenerator::AddCurrentDescriptor(PcDescriptors::Kind kind, | 2653 void CodeGenerator::AddCurrentDescriptor(PcDescriptors::Kind kind, |
| 2631 intptr_t node_id, | 2654 intptr_t node_id, |
| 2632 intptr_t token_index) { | 2655 intptr_t token_index) { |
| 2633 pc_descriptors_list_->AddDescriptor(kind, | 2656 pc_descriptors_list_->AddDescriptor(kind, |
| 2634 assembler_->CodeSize(), | 2657 assembler_->CodeSize(), |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2645 const Class& cls = Class::Handle(parsed_function_.function().owner()); | 2668 const Class& cls = Class::Handle(parsed_function_.function().owner()); |
| 2646 const Script& script = Script::Handle(cls.script()); | 2669 const Script& script = Script::Handle(cls.script()); |
| 2647 Parser::ReportMsg(script, token_index, "Error", error_msg, format, args); | 2670 Parser::ReportMsg(script, token_index, "Error", error_msg, format, args); |
| 2648 Isolate::Current()->long_jump_base()->Jump(1, error_msg); | 2671 Isolate::Current()->long_jump_base()->Jump(1, error_msg); |
| 2649 UNREACHABLE(); | 2672 UNREACHABLE(); |
| 2650 } | 2673 } |
| 2651 | 2674 |
| 2652 } // namespace dart | 2675 } // namespace dart |
| 2653 | 2676 |
| 2654 #endif // defined TARGET_ARCH_IA32 | 2677 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |