| 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/opt_code_generator.h" | 8 #include "vm/opt_code_generator.h" |
| 9 | 9 |
| 10 #include "vm/assembler_macros.h" | 10 #include "vm/assembler_macros.h" |
| (...skipping 741 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 752 __ sarl(EBX, ECX); | 752 __ sarl(EBX, ECX); |
| 753 __ cmpl(EAX, EBX); | 753 __ cmpl(EAX, EBX); |
| 754 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow. | 754 __ j(NOT_EQUAL, &slow_case, Assembler::kNearJump); // Overflow. |
| 755 | 755 |
| 756 __ shll(EAX, ECX); // Shift for result now we know there is no overflow. | 756 __ shll(EAX, ECX); // Shift for result now we know there is no overflow. |
| 757 // EAX is the correctly tagged Smi. | 757 // EAX is the correctly tagged Smi. |
| 758 __ jmp(&done); | 758 __ jmp(&done); |
| 759 __ Bind(&slow_case); | 759 __ Bind(&slow_case); |
| 760 __ pushl(EAX); | 760 __ pushl(EAX); |
| 761 __ pushl(EDX); | 761 __ pushl(EDX); |
| 762 CodeGenerator::GenerateBinaryOperatorCall(node->id(), | 762 const int number_of_arguments = 2; |
| 763 node->token_index(), | 763 const Array& no_optional_argument_names = Array::Handle(); |
| 764 node->Name()); | 764 GenerateCheckedInstanceCalls(node, |
| 765 node->left(), |
| 766 node->id(), |
| 767 node->token_index(), |
| 768 number_of_arguments, |
| 769 no_optional_argument_names); |
| 765 shift_generated = true; | 770 shift_generated = true; |
| 766 } | 771 } |
| 767 __ Bind(&done); | 772 __ Bind(&done); |
| 768 } | 773 } |
| 769 | 774 |
| 770 | 775 |
| 776 // Implement Token::kSUB and Token::kBIT_NOT. |
| 777 void OptimizingCodeGenerator::GenerateSmiUnaryOp(UnaryOpNode* node) { |
| 778 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 779 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); |
| 780 DeoptReasonId deopt_reason_id = ic_data.NumberOfChecks() == 0 ? |
| 781 kDeoptNoTypeFeedback : kDeoptUnaryOp; |
| 782 DeoptimizationBlob* deopt_blob = |
| 783 AddDeoptimizationBlob(node, EAX, deopt_reason_id); |
| 784 CodeGenInfo info(node->operand()); |
| 785 VisitLoadOne(node->operand(), EAX); |
| 786 if (ic_data.NumberOfChecks() == 0) { |
| 787 // No type feedback. |
| 788 __ jmp(deopt_blob->label()); |
| 789 return; |
| 790 } |
| 791 ASSERT(ic_data.NumberOfChecks() == 1); |
| 792 __ testl(EAX, Immediate(kSmiTagMask)); |
| 793 __ j(NOT_ZERO, deopt_blob->label()); |
| 794 if (node->kind() == Token::kSUB) { |
| 795 __ negl(EAX); |
| 796 __ j(OVERFLOW, deopt_blob->label()); |
| 797 } else { |
| 798 ASSERT(node->kind() == Token::kBIT_NOT); |
| 799 __ notl(EAX); |
| 800 __ andl(EAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. |
| 801 } |
| 802 if (CodeGenerator::IsResultNeeded(node)) { |
| 803 if (IsResultInEaxRequested(node)) { |
| 804 node->info()->set_result_returned_in_eax(true); |
| 805 } else { |
| 806 __ pushl(EAX); |
| 807 } |
| 808 } |
| 809 } |
| 810 |
| 811 |
| 771 // TODO(srdjan): Expand inline caches to detect Smi/double operations, so that | 812 // TODO(srdjan): Expand inline caches to detect Smi/double operations, so that |
| 772 // we do not have to call the instance method, and therefore could guarantee | 813 // we do not have to call the instance method, and therefore could guarantee |
| 773 // that the result is a Smi at the end. | 814 // that the result is a Smi at the end. |
| 774 void OptimizingCodeGenerator::GenerateSmiBinaryOp(BinaryOpNode* node) { | 815 void OptimizingCodeGenerator::GenerateSmiBinaryOp(BinaryOpNode* node) { |
| 775 const char* kOptMessage = "Inlines BinaryOp for Smi"; | 816 const char* kOptMessage = "Inlines BinaryOp for Smi"; |
| 776 Label done; | 817 Label done; |
| 777 const Token::Kind kind = node->kind(); | 818 const Token::Kind kind = node->kind(); |
| 778 if ((kind == Token::kADD) || | 819 if ((kind == Token::kADD) || |
| 779 (kind == Token::kSUB) || | 820 (kind == Token::kSUB) || |
| 780 (kind == Token::kMUL) || | 821 (kind == Token::kMUL) || |
| (...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1204 // instead of calling the operator. | 1245 // instead of calling the operator. |
| 1205 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) { | 1246 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) { |
| 1206 if (FLAG_enable_type_checks) { | 1247 if (FLAG_enable_type_checks) { |
| 1207 CodeGenerator::VisitBinaryOpNode(node); | 1248 CodeGenerator::VisitBinaryOpNode(node); |
| 1208 return; | 1249 return; |
| 1209 } | 1250 } |
| 1210 GenerateLogicalBinaryOp(node); | 1251 GenerateLogicalBinaryOp(node); |
| 1211 return; | 1252 return; |
| 1212 } | 1253 } |
| 1213 | 1254 |
| 1214 ObjectStore* object_store = Isolate::Current()->object_store(); | 1255 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1256 if (ic_data.NumberOfChecks() == 0) { |
| 1257 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 1258 DeoptimizationBlob* deopt_blob = |
| 1259 AddDeoptimizationBlob(node, EAX, EDX, kDeoptNoTypeFeedback); |
| 1260 __ jmp(deopt_blob->label()); |
| 1261 return; |
| 1262 } |
| 1263 |
| 1215 if (AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { | 1264 if (AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { |
| 1216 GenerateSmiBinaryOp(node); | 1265 GenerateSmiBinaryOp(node); |
| 1217 return; | 1266 return; |
| 1218 } | 1267 } |
| 1219 | 1268 |
| 1220 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { | 1269 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { |
| 1221 GenerateDoubleBinaryOp(node); | 1270 GenerateDoubleBinaryOp(node); |
| 1222 return; | 1271 return; |
| 1223 } | 1272 } |
| 1224 | 1273 |
| 1225 if (AtIdNodeHasReceiverClass(node, | 1274 const Class& mint_class = |
| 1226 node->id(), | 1275 Class::Handle(Isolate::Current()->object_store()->mint_class()); |
| 1227 Class::Handle(object_store->mint_class()))) { | 1276 if (AtIdNodeHasReceiverClass(node, node->id(), mint_class)) { |
| 1228 GenerateMintBinaryOp(node, false); | 1277 GenerateMintBinaryOp(node, false); |
| 1229 return; | 1278 return; |
| 1230 } | 1279 } |
| 1231 | 1280 |
| 1232 if (NodeHasBothReceiverClasses(node, | 1281 if (NodeHasBothReceiverClasses(node, smi_class_, mint_class)) { |
| 1233 smi_class_, Class::Handle(object_store->mint_class()))) { | |
| 1234 GenerateMintBinaryOp(node, true); | 1282 GenerateMintBinaryOp(node, true); |
| 1235 return; | 1283 return; |
| 1236 } | 1284 } |
| 1237 | 1285 |
| 1238 // TODO(srdjan): Handle "+" for strings. | 1286 // TODO(srdjan): Implement "+" for Strings. |
| 1239 // Type feedback tells this is not a Smi or Double operation. | 1287 // Type feedback tells this is not a Smi or Double operation. |
| 1240 TraceNotOpt(node, | 1288 TraceNotOpt(node, |
| 1241 "BinaryOp: type feedback tells this is not a Smi or Double op"); | 1289 "BinaryOp: type feedback tells this is not a Smi, Mint or Double op"); |
| 1242 CodeGenerator::VisitBinaryOpNode(node); | 1290 node->left()->Visit(this); |
| 1291 node->right()->Visit(this); |
| 1292 const int number_of_arguments = 2; |
| 1293 const Array& no_optional_argument_names = Array::Handle(); |
| 1294 GenerateCheckedInstanceCalls(node, |
| 1295 node->left(), |
| 1296 node->id(), |
| 1297 node->token_index(), |
| 1298 number_of_arguments, |
| 1299 no_optional_argument_names); |
| 1300 if (IsResultNeeded(node)) { |
| 1301 __ pushl(EAX); |
| 1302 } |
| 1243 return; | 1303 return; |
| 1244 } | 1304 } |
| 1245 | 1305 |
| 1246 | 1306 |
| 1247 void OptimizingCodeGenerator::VisitIncrOpLocalNode(IncrOpLocalNode* node) { | 1307 void OptimizingCodeGenerator::VisitIncrOpLocalNode(IncrOpLocalNode* node) { |
| 1248 if (FLAG_enable_type_checks) { | 1308 if (FLAG_enable_type_checks) { |
| 1249 classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); | 1309 classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); |
| 1250 CodeGenerator::VisitIncrOpLocalNode(node); | 1310 CodeGenerator::VisitIncrOpLocalNode(node); |
| 1251 return; | 1311 return; |
| 1252 } | 1312 } |
| (...skipping 921 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2174 __ j(condition, &is_true); | 2234 __ j(condition, &is_true); |
| 2175 __ PushObject(bool_false); | 2235 __ PushObject(bool_false); |
| 2176 __ jmp(&done); | 2236 __ jmp(&done); |
| 2177 __ Bind(&is_true); | 2237 __ Bind(&is_true); |
| 2178 __ PushObject(bool_true); | 2238 __ PushObject(bool_true); |
| 2179 __ Bind(&done); | 2239 __ Bind(&done); |
| 2180 } | 2240 } |
| 2181 return; | 2241 return; |
| 2182 } | 2242 } |
| 2183 | 2243 |
| 2244 if (Token::IsInstanceofOperator(node->kind())) { |
| 2245 VisitLoadOne(node->left(), EAX); |
| 2246 ASSERT(node->right()->IsTypeNode()); |
| 2247 GenerateInstanceOf(node->id(), |
| 2248 node->token_index(), |
| 2249 node->right()->AsTypeNode()->type(), |
| 2250 (node->kind() == Token::kISNOT)); |
| 2251 if (!IsResultNeeded(node)) { |
| 2252 __ popl(EAX); // Pop the result of the instanceof operation. |
| 2253 } |
| 2254 return; |
| 2255 } |
| 2256 |
| 2184 if (AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { | 2257 if (AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { |
| 2185 if (GenerateSmiComparison(node)) { | 2258 if (GenerateSmiComparison(node)) { |
| 2259 // The comparison was handled, code was emitted. |
| 2186 return; | 2260 return; |
| 2187 } | 2261 } |
| 2188 // Fall through if condition is not supported. | 2262 // Fall through if condition is not supported. |
| 2189 } else if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { | 2263 } else if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { |
| 2190 // Double comparison | 2264 // Double comparison |
| 2191 if (GenerateDoubleComparison(node)) { | 2265 if (GenerateDoubleComparison(node)) { |
| 2192 return; | 2266 return; |
| 2193 } | 2267 } |
| 2194 } else if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { | 2268 } else if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { |
| 2195 // Equality, not-equality comparison of any other type. | 2269 // Equality, not-equality comparison of any other type. |
| 2196 if (GenerateEqualityComparison(node)) { | 2270 if (GenerateEqualityComparison(node)) { |
| 2197 return; | 2271 return; |
| 2198 } | 2272 } |
| 2199 } | 2273 } |
| 2200 | 2274 |
| 2201 // Fall through here if a comparison was not implemented. | 2275 // Fall through here if a comparison was not implemented. |
| 2276 // TODO(srdjan): Implement for Strings. |
| 2202 CodeGenerator::VisitComparisonNode(node); | 2277 CodeGenerator::VisitComparisonNode(node); |
| 2203 } | 2278 } |
| 2204 | 2279 |
| 2205 | 2280 |
| 2206 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { | 2281 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { |
| 2207 const char* kMessage = "Inline indexed access"; | 2282 const char* kMessage = "Inline indexed access"; |
| 2208 ObjectStore* object_store = Isolate::Current()->object_store(); | 2283 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 2209 const Class& object_array_class = | 2284 const Class& object_array_class = |
| 2210 Class::ZoneHandle(object_store->array_class()); | 2285 Class::ZoneHandle(object_store->array_class()); |
| 2211 const Class& immutable_object_array_class = | 2286 const Class& immutable_object_array_class = |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2508 const ICData& ic_data, | 2583 const ICData& ic_data, |
| 2509 const Function& null_target, | 2584 const Function& null_target, |
| 2510 GrowableArray<const Class*>* classes, | 2585 GrowableArray<const Class*>* classes, |
| 2511 GrowableArray<const Function*>* targets) { | 2586 GrowableArray<const Function*>* targets) { |
| 2512 ASSERT(classes != NULL); | 2587 ASSERT(classes != NULL); |
| 2513 ASSERT(targets != NULL); | 2588 ASSERT(targets != NULL); |
| 2514 // Check if we can add Smi class in front. | 2589 // Check if we can add Smi class in front. |
| 2515 Class& smi_test_class = Class::Handle(); | 2590 Class& smi_test_class = Class::Handle(); |
| 2516 Function& smi_target = Function::ZoneHandle(); | 2591 Function& smi_target = Function::ZoneHandle(); |
| 2517 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 2592 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 2518 ic_data.GetOneClassCheckAt(i, &smi_test_class, &smi_target); | 2593 GrowableArray<const Class*> test_classes; |
| 2594 ic_data.GetCheckAt(i, &test_classes, &smi_target); |
| 2595 smi_test_class = test_classes[0]->raw(); |
| 2519 if (smi_test_class.raw() == smi_class_.raw()) { | 2596 if (smi_test_class.raw() == smi_class_.raw()) { |
| 2520 classes->Add(&Class::ZoneHandle(smi_class_.raw())); | 2597 classes->Add(&Class::ZoneHandle(smi_class_.raw())); |
| 2521 targets->Add(&Function::ZoneHandle(smi_target.raw())); | 2598 targets->Add(&Function::ZoneHandle(smi_target.raw())); |
| 2522 break; | 2599 break; |
| 2523 } | 2600 } |
| 2524 } | 2601 } |
| 2525 // Add all classes except Smi. | 2602 // Add all classes except Smi. |
| 2526 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 2603 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 2527 Function& target = Function::ZoneHandle(); | 2604 Function& target = Function::ZoneHandle(); |
| 2528 Class& cls = Class::ZoneHandle(); | 2605 Class& cls = Class::ZoneHandle(); |
| 2529 ic_data.GetOneClassCheckAt(i, &cls, &target); | 2606 GrowableArray<const Class*> test_classes; |
| 2607 ic_data.GetCheckAt(i, &test_classes, &target); |
| 2608 cls = test_classes[0]->raw(); |
| 2530 ASSERT(!cls.IsNullClass()); | 2609 ASSERT(!cls.IsNullClass()); |
| 2531 if (cls.raw() != smi_class_.raw()) { | 2610 if (cls.raw() != smi_class_.raw()) { |
| 2532 ASSERT(!cls.IsNull()); | 2611 ASSERT(!cls.IsNull()); |
| 2533 ASSERT(!target.IsNull()); | 2612 ASSERT(!target.IsNull()); |
| 2534 classes->Add(&cls); | 2613 classes->Add(&cls); |
| 2535 targets->Add(&target); | 2614 targets->Add(&target); |
| 2536 } | 2615 } |
| 2537 } | 2616 } |
| 2538 // Do not add a target that has not been compiled yet. | 2617 // Do not add a target that has not been compiled yet. |
| 2539 if (!null_target.IsNull() && null_target.HasCode()) { | 2618 if (!null_target.IsNull() && null_target.HasCode()) { |
| 2540 ASSERT(null_target.IsZoneHandle()); | 2619 ASSERT(null_target.IsZoneHandle()); |
| 2541 classes->Add(&Class::ZoneHandle(Object::null_class())); | 2620 classes->Add(&Class::ZoneHandle(Object::null_class())); |
| 2542 targets->Add(&null_target); | 2621 targets->Add(&null_target); |
| 2543 } | 2622 } |
| 2544 } | 2623 } |
| 2545 | 2624 |
| 2546 | 2625 |
| 2547 // Use ICData in 'node' to issues checks and calls. | 2626 // Use ICData in 'node' to issues checks and calls. |
| 2627 // IC data can contain one or more argument checks. |
| 2548 void OptimizingCodeGenerator::GenerateCheckedInstanceCalls( | 2628 void OptimizingCodeGenerator::GenerateCheckedInstanceCalls( |
| 2549 AstNode* node, | 2629 AstNode* node, |
| 2550 AstNode* receiver, | 2630 AstNode* receiver, |
| 2551 intptr_t node_id, | 2631 intptr_t node_id, |
| 2552 intptr_t token_index, | 2632 intptr_t token_index, |
| 2553 intptr_t num_args, | 2633 intptr_t num_args, |
| 2554 const Array& optional_arguments_names) { | 2634 const Array& optional_arguments_names) { |
| 2555 ASSERT(node != NULL); | 2635 ASSERT(node != NULL); |
| 2556 ASSERT(receiver != NULL); | 2636 ASSERT(receiver != NULL); |
| 2557 ASSERT(num_args > 0); | 2637 ASSERT(num_args > 0); |
| 2558 const ICData& ic_data = node->ICDataAtId(node_id); | 2638 const ICData& ic_data = node->ICDataAtId(node_id); |
| 2559 if (ic_data.NumberOfChecks() == 0) { | 2639 if (ic_data.NumberOfChecks() == 0) { |
| 2560 // No type feedback means node was never executed. However that can be | 2640 // No type feedback means node was never executed. However that can be |
| 2561 // a common case especially in case of large switch statements. | 2641 // a common case especially in case of large switch statements. |
| 2562 // Use a special inline cache call which can help us decide when to | 2642 // Use a special inline cache call which can help us decide when to |
| 2563 // re-optimize this optiumized function. | 2643 // re-optimize this optiumized function. |
| 2564 GenerateInlineCacheCall( | 2644 GenerateInlineCacheCall( |
| 2565 node_id, token_index, ic_data, num_args, optional_arguments_names); | 2645 node_id, token_index, ic_data, num_args, optional_arguments_names); |
| 2566 return; | 2646 return; |
| 2567 } | 2647 } |
| 2568 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); | |
| 2569 | 2648 |
| 2570 Function& target_for_null = Function::ZoneHandle(); | 2649 Function& target_for_null = Function::ZoneHandle(); |
| 2571 ObjectStore* object_store = Isolate::Current()->object_store(); | 2650 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 2572 int num_optional_args = | 2651 int num_optional_args = |
| 2573 optional_arguments_names.IsNull() ? 0 : optional_arguments_names.Length(); | 2652 optional_arguments_names.IsNull() ? 0 : optional_arguments_names.Length(); |
| 2574 target_for_null = Resolver::ResolveDynamicForReceiverClass( | 2653 target_for_null = Resolver::ResolveDynamicForReceiverClass( |
| 2575 Class::Handle(object_store->object_class()), | 2654 Class::Handle(object_store->object_class()), |
| 2576 String::Handle(ic_data.FunctionName()), | 2655 String::Handle(ic_data.FunctionName()), |
| 2577 num_args, | 2656 num_args, |
| 2578 num_optional_args); | 2657 num_optional_args); |
| 2579 GrowableArray<const Class*> classes; | 2658 GrowableArray<const Class*> classes; |
| 2580 GrowableArray<const Function*> targets; | 2659 GrowableArray<const Function*> targets; |
| 2660 // Make Smi class the first one, if it is in the list. |
| 2581 NormalizeClassChecks(ic_data, target_for_null, &classes, &targets); | 2661 NormalizeClassChecks(ic_data, target_for_null, &classes, &targets); |
| 2582 ASSERT(!classes.is_empty()); | 2662 ASSERT(!classes.is_empty()); |
| 2583 ASSERT(classes.length() == targets.length()); | 2663 ASSERT(classes.length() == targets.length()); |
| 2584 intptr_t start_ix = 0; | 2664 intptr_t start_ix = 0; |
| 2585 | 2665 |
| 2586 Label done; | 2666 Label done; |
| 2587 __ movl(EAX, Address(ESP, (num_args - 1) * kWordSize)); // Load receiver. | 2667 __ movl(EAX, Address(ESP, (num_args - 1) * kWordSize)); // Load receiver. |
| 2588 if (classes[0]->raw() == smi_class_.raw()) { | 2668 if (classes[0]->raw() == smi_class_.raw()) { |
| 2589 start_ix++; | 2669 start_ix++; |
| 2590 // Smi test is needed. | 2670 // Smi test is needed. |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2772 } | 2852 } |
| 2773 | 2853 |
| 2774 | 2854 |
| 2775 void OptimizingCodeGenerator::VisitReturnNode(ReturnNode* node) { | 2855 void OptimizingCodeGenerator::VisitReturnNode(ReturnNode* node) { |
| 2776 if ((node->inlined_finally_list_length() > 0) || FLAG_enable_type_checks) { | 2856 if ((node->inlined_finally_list_length() > 0) || FLAG_enable_type_checks) { |
| 2777 CodeGenerator::VisitReturnNode(node); | 2857 CodeGenerator::VisitReturnNode(node); |
| 2778 return; | 2858 return; |
| 2779 } | 2859 } |
| 2780 ASSERT(!IsResultNeeded(node)); | 2860 ASSERT(!IsResultNeeded(node)); |
| 2781 ASSERT(node->value() != NULL); | 2861 ASSERT(node->value() != NULL); |
| 2782 VisitLoadOne(node->value(), EAX); | 2862 CodeGenInfo value_info(node->value()); |
| 2863 value_info.set_request_result_in_eax(true); |
| 2864 node->value()->Visit(this); |
| 2865 if (!value_info.result_returned_in_eax()) { |
| 2866 __ popl(EAX); |
| 2867 } |
| 2783 GenerateReturnEpilog(); | 2868 GenerateReturnEpilog(); |
| 2784 } | 2869 } |
| 2785 | 2870 |
| 2786 | 2871 |
| 2787 void OptimizingCodeGenerator::VisitSequenceNode(SequenceNode* node_sequence) { | 2872 void OptimizingCodeGenerator::VisitSequenceNode(SequenceNode* node_sequence) { |
| 2788 // TODO(srdjan): Allow limited forwarding of types across sequence nodes. | 2873 // TODO(srdjan): Allow limited forwarding of types across sequence nodes. |
| 2789 classes_for_locals_->Clear(); | 2874 classes_for_locals_->Clear(); |
| 2790 const intptr_t num_context_variables = (node_sequence->scope() != NULL) ? | 2875 const intptr_t num_context_variables = (node_sequence->scope() != NULL) ? |
| 2791 node_sequence->scope()->num_context_variables() : 0; | 2876 node_sequence->scope()->num_context_variables() : 0; |
| 2792 if (FLAG_enable_type_checks || (num_context_variables > 0)) { | 2877 if (FLAG_enable_type_checks || (num_context_variables > 0)) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2827 } | 2912 } |
| 2828 | 2913 |
| 2829 | 2914 |
| 2830 void OptimizingCodeGenerator::VisitTryCatchNode(TryCatchNode* node) { | 2915 void OptimizingCodeGenerator::VisitTryCatchNode(TryCatchNode* node) { |
| 2831 // TODO(srdjan): Set classes for locals. | 2916 // TODO(srdjan): Set classes for locals. |
| 2832 classes_for_locals_->Clear(); | 2917 classes_for_locals_->Clear(); |
| 2833 CodeGenerator::VisitTryCatchNode(node); | 2918 CodeGenerator::VisitTryCatchNode(node); |
| 2834 } | 2919 } |
| 2835 | 2920 |
| 2836 | 2921 |
| 2922 void OptimizingCodeGenerator::VisitUnaryOpNode(UnaryOpNode* node) { |
| 2923 if (FLAG_enable_type_checks) { |
| 2924 CodeGenerator::VisitUnaryOpNode(node); |
| 2925 return; |
| 2926 } |
| 2927 // TODO(srdjan): Jump directly to labels instead of returning a boolean. |
| 2928 if (node->kind() == Token::kNOT) { |
| 2929 // Only a true bool returns false, everything else is true. |
| 2930 CodeGenInfo info(node->operand()); |
| 2931 VisitLoadOne(node->operand(), EDX); |
| 2932 Label done; |
| 2933 __ LoadObject(EAX, Bool::ZoneHandle(Bool::True())); |
| 2934 __ cmpl(EDX, EAX); |
| 2935 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 2936 __ LoadObject(EAX, Bool::ZoneHandle(Bool::False())); |
| 2937 __ Bind(&done); |
| 2938 if (CodeGenerator::IsResultNeeded(node)) { |
| 2939 if (IsResultInEaxRequested(node)) { |
| 2940 node->info()->set_result_returned_in_eax(true); |
| 2941 } else { |
| 2942 __ pushl(EAX); |
| 2943 } |
| 2944 } |
| 2945 return; |
| 2946 } |
| 2947 |
| 2948 if ((node->kind() == Token::kSUB) || (node->kind() == Token::kBIT_NOT)) { |
| 2949 if (AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { |
| 2950 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 2951 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); |
| 2952 GenerateSmiUnaryOp(node); |
| 2953 return; |
| 2954 } |
| 2955 } |
| 2956 // TODO(srdjan): Implement unary kSUB (negate) for doubles and Mint. |
| 2957 CodeGenerator::VisitUnaryOpNode(node); |
| 2958 } |
| 2959 |
| 2960 |
| 2837 } // namespace dart | 2961 } // namespace dart |
| 2838 | 2962 |
| 2839 #endif // defined TARGET_ARCH_IA32 | 2963 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |