Chromium Code Reviews| 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 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 108 GrowableArray<Pair> data_; | 108 GrowableArray<Pair> data_; |
| 109 DISALLOW_COPY_AND_ASSIGN(CodeGenInfo); | 109 DISALLOW_COPY_AND_ASSIGN(CodeGenInfo); |
| 110 }; | 110 }; |
| 111 | 111 |
| 112 | 112 |
| 113 // Code that calls the deoptimizer, emitted as deferred code (out of line). | 113 // Code that calls the deoptimizer, emitted as deferred code (out of line). |
| 114 // Specify the corresponding 'node' and the registers that need to | 114 // Specify the corresponding 'node' and the registers that need to |
| 115 // be pushed for the deoptimization point in unoptimized code. | 115 // be pushed for the deoptimization point in unoptimized code. |
| 116 class DeoptimizationBlob : public ZoneAllocated { | 116 class DeoptimizationBlob : public ZoneAllocated { |
| 117 public: | 117 public: |
| 118 explicit DeoptimizationBlob(AstNode* node) : node_(node), registers_(2) {} | 118 DeoptimizationBlob(AstNode* node, DeoptReasonId deopt_reason_id) |
| 119 : node_(node), | |
| 120 registers_(2), | |
| 121 label_(), | |
| 122 deopt_reason_id_(deopt_reason_id) {} | |
| 119 | 123 |
| 120 void Push(Register reg) { registers_.Add(reg); } | 124 void Push(Register reg) { registers_.Add(reg); } |
| 121 | 125 |
| 122 void Generate(OptimizingCodeGenerator* codegen) { | 126 void Generate(OptimizingCodeGenerator* codegen) { |
| 123 codegen->assembler()->Bind(&label_); | 127 codegen->assembler()->Bind(&label_); |
| 124 for (int i = 0; i < registers_.length(); i++) { | 128 for (int i = 0; i < registers_.length(); i++) { |
| 125 codegen->assembler()->pushl(registers_[i]); | 129 codegen->assembler()->pushl(registers_[i]); |
| 126 } | 130 } |
| 131 codegen->assembler()->movl(EAX, Immediate(Smi::RawValue(deopt_reason_id_))); | |
| 127 codegen->CallDeoptimize(node_->id(), node_->token_index()); | 132 codegen->CallDeoptimize(node_->id(), node_->token_index()); |
| 128 #if defined(DEBUG) | 133 #if defined(DEBUG) |
| 129 // Check that deoptimization point exists in unoptimized code. | 134 // Check that deoptimization point exists in unoptimized code. |
| 130 const Code& unoptimized_code = | 135 const Code& unoptimized_code = |
| 131 Code::Handle(codegen->parsed_function().function().unoptimized_code()); | 136 Code::Handle(codegen->parsed_function().function().unoptimized_code()); |
| 132 ASSERT(!unoptimized_code.IsNull()); | 137 ASSERT(!unoptimized_code.IsNull()); |
| 133 uword continue_at_pc = | 138 uword continue_at_pc = |
| 134 unoptimized_code.GetDeoptPcAtNodeId(node_->id()); | 139 unoptimized_code.GetDeoptPcAtNodeId(node_->id()); |
| 135 ASSERT(continue_at_pc != 0); | 140 ASSERT(continue_at_pc != 0); |
| 136 #endif // DEBUG | 141 #endif // DEBUG |
| 137 } | 142 } |
| 138 | 143 |
| 139 // Jump to this label to deoptimize. | 144 // Jump to this label to deoptimize. |
| 140 Label* label() { return &label_; } | 145 Label* label() { return &label_; } |
| 141 | 146 |
| 142 private: | 147 private: |
| 143 const AstNode* node_; | 148 const AstNode* node_; |
| 144 GrowableArray<Register> registers_; | 149 GrowableArray<Register> registers_; |
| 145 Label label_; | 150 Label label_; |
| 151 DeoptReasonId deopt_reason_id_; | |
| 146 | 152 |
| 147 DISALLOW_COPY_AND_ASSIGN(DeoptimizationBlob); | 153 DISALLOW_COPY_AND_ASSIGN(DeoptimizationBlob); |
| 148 }; | 154 }; |
| 149 | 155 |
| 150 // TODO(srdjan): Add String_charCodeAt, String_hashCode. | 156 // TODO(srdjan): Add String_charCodeAt, String_hashCode. |
| 151 | 157 |
| 152 #define RECOGNIZED_LIST(V) \ | 158 #define RECOGNIZED_LIST(V) \ |
| 153 V(ObjectArray, get:length, ObjectArrayLength) \ | 159 V(ObjectArray, get:length, ObjectArrayLength) \ |
| 154 V(GrowableObjectArray, get:length, GrowableArrayLength) \ | 160 V(GrowableObjectArray, get:length, GrowableArrayLength) \ |
| 155 V(StringBase, get:length, StringBaseLength) \ | 161 V(StringBase, get:length, StringBaseLength) \ |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 212 deoptimization_blobs_(4), | 218 deoptimization_blobs_(4), |
| 213 smi_class_(Class::ZoneHandle(Isolate::Current()->object_store() | 219 smi_class_(Class::ZoneHandle(Isolate::Current()->object_store() |
| 214 ->smi_class())), | 220 ->smi_class())), |
| 215 double_class_(Class::ZoneHandle(Isolate::Current()->object_store() | 221 double_class_(Class::ZoneHandle(Isolate::Current()->object_store() |
| 216 ->double_class())) { | 222 ->double_class())) { |
| 217 ASSERT(parsed_function.function().is_optimizable()); | 223 ASSERT(parsed_function.function().is_optimizable()); |
| 218 } | 224 } |
| 219 | 225 |
| 220 | 226 |
| 221 DeoptimizationBlob* | 227 DeoptimizationBlob* |
| 222 OptimizingCodeGenerator::AddDeoptimizationBlob(AstNode* node) { | 228 OptimizingCodeGenerator::AddDeoptimizationBlob(AstNode* node, |
| 223 DeoptimizationBlob* d = new DeoptimizationBlob(node); | 229 DeoptReasonId reason_id) { |
| 230 DeoptimizationBlob* d = new DeoptimizationBlob(node, reason_id); | |
| 224 deoptimization_blobs_.Add(d); | 231 deoptimization_blobs_.Add(d); |
| 225 return d; | 232 return d; |
| 226 } | 233 } |
| 227 | 234 |
| 228 | 235 |
| 229 DeoptimizationBlob* | 236 DeoptimizationBlob* |
| 230 OptimizingCodeGenerator::AddDeoptimizationBlob(AstNode* node, Register reg) { | 237 OptimizingCodeGenerator::AddDeoptimizationBlob(AstNode* node, |
| 231 DeoptimizationBlob* d = AddDeoptimizationBlob(node); | 238 Register reg, |
| 239 DeoptReasonId reason_id) { | |
| 240 DeoptimizationBlob* d = AddDeoptimizationBlob(node, reason_id); | |
| 232 d->Push(reg); | 241 d->Push(reg); |
| 233 return d; | 242 return d; |
| 234 } | 243 } |
| 235 | 244 |
| 236 | 245 |
| 237 DeoptimizationBlob* | 246 DeoptimizationBlob* |
| 238 OptimizingCodeGenerator::AddDeoptimizationBlob(AstNode* node, | 247 OptimizingCodeGenerator::AddDeoptimizationBlob(AstNode* node, |
| 239 Register reg1, | 248 Register reg1, |
| 240 Register reg2) { | 249 Register reg2, |
| 241 DeoptimizationBlob* d = AddDeoptimizationBlob(node); | 250 DeoptReasonId reason_id) { |
| 251 DeoptimizationBlob* d = AddDeoptimizationBlob(node, reason_id); | |
| 242 d->Push(reg1); | 252 d->Push(reg1); |
| 243 d->Push(reg2); | 253 d->Push(reg2); |
| 244 return d; | 254 return d; |
| 245 } | 255 } |
| 246 | 256 |
| 247 | 257 |
| 248 DeoptimizationBlob* | 258 DeoptimizationBlob* |
| 249 OptimizingCodeGenerator::AddDeoptimizationBlob(AstNode* node, | 259 OptimizingCodeGenerator::AddDeoptimizationBlob(AstNode* node, |
| 250 Register reg1, | 260 Register reg1, |
| 251 Register reg2, | 261 Register reg2, |
| 252 Register reg3) { | 262 Register reg3, |
| 253 DeoptimizationBlob* d = AddDeoptimizationBlob(node); | 263 DeoptReasonId reason_id) { |
| 264 DeoptimizationBlob* d = AddDeoptimizationBlob(node, reason_id); | |
| 254 d->Push(reg1); | 265 d->Push(reg1); |
| 255 d->Push(reg2); | 266 d->Push(reg2); |
| 256 d->Push(reg3); | 267 d->Push(reg3); |
| 257 return d; | 268 return d; |
| 258 } | 269 } |
| 259 | 270 |
| 260 | 271 |
| 261 void OptimizingCodeGenerator::GenerateDeferredCode() { | 272 void OptimizingCodeGenerator::GenerateDeferredCode() { |
| 262 CodeGenerator::GenerateDeferredCode(); | 273 CodeGenerator::GenerateDeferredCode(); |
| 263 for (int i = 0; i < deoptimization_blobs_.length(); i++) { | 274 for (int i = 0; i < deoptimization_blobs_.length(); i++) { |
| (...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 665 (kind == Token::kBIT_AND) || | 676 (kind == Token::kBIT_AND) || |
| 666 (kind == Token::kBIT_OR) || | 677 (kind == Token::kBIT_OR) || |
| 667 (kind == Token::kBIT_XOR)) { | 678 (kind == Token::kBIT_XOR)) { |
| 668 TraceOpt(node, kOptMessage); | 679 TraceOpt(node, kOptMessage); |
| 669 CodeGenInfo left_info(node->left()); | 680 CodeGenInfo left_info(node->left()); |
| 670 CodeGenInfo right_info(node->right()); | 681 CodeGenInfo right_info(node->right()); |
| 671 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 682 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 672 Label* overflow_label = NULL; | 683 Label* overflow_label = NULL; |
| 673 Label two_smis, call_operator; | 684 Label two_smis, call_operator; |
| 674 if (left_info.IsClass(smi_class_) || right_info.IsClass(smi_class_)) { | 685 if (left_info.IsClass(smi_class_) || right_info.IsClass(smi_class_)) { |
| 675 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, ECX, EDX); | 686 DeoptimizationBlob* deopt_blob = |
| 687 AddDeoptimizationBlob(node, ECX, EDX, kDeoptSmiBinaryOp); | |
| 676 overflow_label = deopt_blob->label(); | 688 overflow_label = deopt_blob->label(); |
| 677 __ movl(ECX, EAX); // Save if overflow (needs original value). | 689 __ movl(ECX, EAX); // Save if overflow (needs original value). |
| 678 if (!left_info.IsClass(smi_class_) || !right_info.IsClass(smi_class_)) { | 690 if (!left_info.IsClass(smi_class_) || !right_info.IsClass(smi_class_)) { |
| 679 Register test_reg = left_info.IsClass(smi_class_) ? EDX : EAX; | 691 Register test_reg = left_info.IsClass(smi_class_) ? EDX : EAX; |
| 680 __ testl(test_reg, Immediate(kSmiTagMask)); | 692 __ testl(test_reg, Immediate(kSmiTagMask)); |
| 681 __ j(NOT_ZERO, deopt_blob->label()); | 693 __ j(NOT_ZERO, deopt_blob->label()); |
| 682 } | 694 } |
| 683 if (node->info() != NULL) { | 695 if (node->info() != NULL) { |
| 684 node->info()->set_is_class(&smi_class_); | 696 node->info()->set_is_class(&smi_class_); |
| 685 } | 697 } |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 770 // any Mint bits above the Smi range. | 782 // any Mint bits above the Smi range. |
| 771 // 'allow_smi' is true if Smi and Mint classes have been encountered. | 783 // 'allow_smi' is true if Smi and Mint classes have been encountered. |
| 772 void OptimizingCodeGenerator::GenerateMintBinaryOp(BinaryOpNode* node, | 784 void OptimizingCodeGenerator::GenerateMintBinaryOp(BinaryOpNode* node, |
| 773 bool allow_smi) { | 785 bool allow_smi) { |
| 774 const char* kOptMessage = "Inline Mint binop."; | 786 const char* kOptMessage = "Inline Mint binop."; |
| 775 ObjectStore* object_store = Isolate::Current()->object_store(); | 787 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 776 const Token::Kind kind = node->kind(); | 788 const Token::Kind kind = node->kind(); |
| 777 if (kind == Token::kBIT_AND) { | 789 if (kind == Token::kBIT_AND) { |
| 778 TraceOpt(node, kOptMessage); | 790 TraceOpt(node, kOptMessage); |
| 779 Label is_smi, slow_case, done; | 791 Label is_smi, slow_case, done; |
| 780 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EDX); | 792 DeoptimizationBlob* deopt_blob = |
| 793 AddDeoptimizationBlob(node, EAX, EDX, kDeoptMintBinaryOp); | |
| 781 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 794 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 782 __ testl(EDX, Immediate(kSmiTagMask)); | 795 __ testl(EDX, Immediate(kSmiTagMask)); |
| 783 __ j(NOT_ZERO, &slow_case); // Call operator if right is not Smi. | 796 __ j(NOT_ZERO, &slow_case); // Call operator if right is not Smi. |
| 784 | 797 |
| 785 // Test left. | 798 // Test left. |
| 786 __ testl(EAX, Immediate(kSmiTagMask)); | 799 __ testl(EAX, Immediate(kSmiTagMask)); |
| 787 __ j(ZERO, &is_smi); | 800 __ j(ZERO, &is_smi); |
| 788 | 801 |
| 789 __ movl(EBX, FieldAddress(EAX, Object::class_offset())); | 802 __ movl(EBX, FieldAddress(EAX, Object::class_offset())); |
| 790 __ CompareObject(EBX, Class::ZoneHandle(object_store->mint_class())); | 803 __ CompareObject(EBX, Class::ZoneHandle(object_store->mint_class())); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 892 // Use inlined temporary double object. | 905 // Use inlined temporary double object. |
| 893 const Double& double_object = | 906 const Double& double_object = |
| 894 Double::ZoneHandle(Double::New(0.0)); | 907 Double::ZoneHandle(Double::New(0.0)); |
| 895 __ LoadObject(result_register, double_object); | 908 __ LoadObject(result_register, double_object); |
| 896 } | 909 } |
| 897 Label is_smi, extract_left; | 910 Label is_smi, extract_left; |
| 898 DeoptimizationBlob* deopt_blob = NULL; | 911 DeoptimizationBlob* deopt_blob = NULL; |
| 899 Label* deopt_lbl = NULL; | 912 Label* deopt_lbl = NULL; |
| 900 if (!left_info.IsClass(double_class_) || | 913 if (!left_info.IsClass(double_class_) || |
| 901 !right_info.IsClass(double_class_)) { | 914 !right_info.IsClass(double_class_)) { |
| 902 deopt_blob = AddDeoptimizationBlob(node, kLeftRegister, kRightRegister); | 915 deopt_blob = AddDeoptimizationBlob(node, |
| 916 kLeftRegister, | |
| 917 kRightRegister, | |
| 918 kDeoptDoubleBinaryOp); | |
| 903 deopt_lbl = deopt_blob->label(); | 919 deopt_lbl = deopt_blob->label(); |
| 904 } | 920 } |
| 905 | 921 |
| 906 bool nodes_of_same_type = AreNodesOfSameType(node->left(), node->right()); | 922 bool nodes_of_same_type = AreNodesOfSameType(node->left(), node->right()); |
| 907 if (!left_info.IsClass(double_class_)) { | 923 if (!left_info.IsClass(double_class_)) { |
| 908 CheckIfDoubleOrSmi(kLeftRegister, kTempRegister, deopt_lbl, deopt_lbl); | 924 CheckIfDoubleOrSmi(kLeftRegister, kTempRegister, deopt_lbl, deopt_lbl); |
| 909 // Fall through for double. Jump to 'deopt' if not double. | 925 // Fall through for double. Jump to 'deopt' if not double. |
| 910 } | 926 } |
| 911 if (!right_info.IsClass(double_class_) && !nodes_of_same_type) { | 927 if (!right_info.IsClass(double_class_) && !nodes_of_same_type) { |
| 912 CheckIfDoubleOrSmi(kRightRegister, kTempRegister, &is_smi, deopt_lbl); | 928 CheckIfDoubleOrSmi(kRightRegister, kTempRegister, &is_smi, deopt_lbl); |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1090 TraceOpt(node, kOptMessage); | 1106 TraceOpt(node, kOptMessage); |
| 1091 | 1107 |
| 1092 GenerateLoadVariable(EAX, node->local()); | 1108 GenerateLoadVariable(EAX, node->local()); |
| 1093 if (!node->prefix() && IsResultNeeded(node)) { | 1109 if (!node->prefix() && IsResultNeeded(node)) { |
| 1094 // Preserve as result. | 1110 // Preserve as result. |
| 1095 __ movl(ECX, EAX); | 1111 __ movl(ECX, EAX); |
| 1096 } | 1112 } |
| 1097 const int int_value = (node->kind() == Token::kINCR) ? 1 : -1; | 1113 const int int_value = (node->kind() == Token::kINCR) ? 1 : -1; |
| 1098 const Immediate smi_value = | 1114 const Immediate smi_value = |
| 1099 Immediate(reinterpret_cast<int32_t>(Smi::New(int_value))); | 1115 Immediate(reinterpret_cast<int32_t>(Smi::New(int_value))); |
| 1100 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node); | 1116 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, kDeoptIncrLocal); |
| 1101 __ testl(EAX, Immediate(kSmiTagMask)); | 1117 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1102 __ j(NOT_ZERO, deopt_blob->label()); | 1118 __ j(NOT_ZERO, deopt_blob->label()); |
| 1103 __ addl(EAX, smi_value); | 1119 __ addl(EAX, smi_value); |
| 1104 __ j(OVERFLOW, deopt_blob->label()); | 1120 __ j(OVERFLOW, deopt_blob->label()); |
| 1105 GenerateStoreVariable(node->local(), EAX, EDX); | 1121 GenerateStoreVariable(node->local(), EAX, EDX); |
| 1106 if (IsResultNeeded(node)) { | 1122 if (IsResultNeeded(node)) { |
| 1107 if (node->info() != NULL) { | 1123 if (node->info() != NULL) { |
| 1108 node->info()->set_is_class(&smi_class_); | 1124 node->info()->set_is_class(&smi_class_); |
| 1109 } | 1125 } |
| 1110 if (node->prefix()) { | 1126 if (node->prefix()) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1153 | 1169 |
| 1154 void OptimizingCodeGenerator::VisitIncrOpInstanceFieldNode( | 1170 void OptimizingCodeGenerator::VisitIncrOpInstanceFieldNode( |
| 1155 IncrOpInstanceFieldNode* node) { | 1171 IncrOpInstanceFieldNode* node) { |
| 1156 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); | 1172 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); |
| 1157 VisitLoadOne(node->receiver(), EBX); | 1173 VisitLoadOne(node->receiver(), EBX); |
| 1158 __ pushl(EBX); // Duplicate receiver (preserve for setter). | 1174 __ pushl(EBX); // Duplicate receiver (preserve for setter). |
| 1159 const ICData& ic_data = node->ICDataAtId(node->id()); | 1175 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1160 if (ic_data.NumberOfChecks() == 0) { | 1176 if (ic_data.NumberOfChecks() == 0) { |
| 1161 // Deoptimization point for this node is after receiver has been | 1177 // Deoptimization point for this node is after receiver has been |
| 1162 // pushed twice on stack and before the getter (above) was executed. | 1178 // pushed twice on stack and before the getter (above) was executed. |
| 1163 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); | 1179 DeoptimizationBlob* deopt_blob = |
| 1180 AddDeoptimizationBlob(node, EBX, kDeoptIncrInstance); | |
| 1164 __ jmp(deopt_blob->label()); | 1181 __ jmp(deopt_blob->label()); |
| 1165 return; | 1182 return; |
| 1166 } | 1183 } |
| 1167 InlineInstanceGetter(node, | 1184 InlineInstanceGetter(node, |
| 1168 node->getter_id(), | 1185 node->getter_id(), |
| 1169 node->receiver(), | 1186 node->receiver(), |
| 1170 node->field_name(), | 1187 node->field_name(), |
| 1171 EBX); | 1188 EBX); |
| 1172 // result is in EAX. | 1189 // result is in EAX. |
| 1173 __ popl(EDX); // Get receiver. | 1190 __ popl(EDX); // Get receiver. |
| 1174 const bool return_original_value = !node->prefix() && IsResultNeeded(node); | 1191 const bool return_original_value = !node->prefix() && IsResultNeeded(node); |
| 1175 const Immediate one_value = Immediate(Smi::RawValue(1)); | 1192 const Immediate one_value = Immediate(Smi::RawValue(1)); |
| 1176 // EAX: Value. | 1193 // EAX: Value. |
| 1177 // EDX: Receiver. | 1194 // EDX: Receiver. |
| 1178 if (AtIdNodeHasOnlyClass(node, node->operator_id(), smi_class_)) { | 1195 if (AtIdNodeHasOnlyClass(node, node->operator_id(), smi_class_)) { |
| 1179 // Deoptimization point for this node is after receiver has been | 1196 // Deoptimization point for this node is after receiver has been |
| 1180 // pushed twice on stack and before the getter (above) was executed. | 1197 // pushed twice on stack and before the getter (above) was executed. |
| 1181 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EDX, EDX); | 1198 DeoptimizationBlob* deopt_blob = |
| 1199 AddDeoptimizationBlob(node, EDX, EDX, kDeoptIncrInstanceOneClass); | |
| 1182 if (return_original_value) { | 1200 if (return_original_value) { |
| 1183 // Preserve pre increment result. | 1201 // Preserve pre increment result. |
| 1184 __ movl(ECX, EAX); | 1202 __ movl(ECX, EAX); |
| 1185 } | 1203 } |
| 1186 __ testl(EAX, Immediate(kSmiTagMask)); | 1204 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1187 __ j(NOT_ZERO, deopt_blob->label()); | 1205 __ j(NOT_ZERO, deopt_blob->label()); |
| 1188 if (node->kind() == Token::kINCR) { | 1206 if (node->kind() == Token::kINCR) { |
| 1189 __ addl(EAX, one_value); | 1207 __ addl(EAX, one_value); |
| 1190 } else { | 1208 } else { |
| 1191 __ subl(EAX, one_value); | 1209 __ subl(EAX, one_value); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1281 void OptimizingCodeGenerator::InlineInstanceGettersWithSameTarget( | 1299 void OptimizingCodeGenerator::InlineInstanceGettersWithSameTarget( |
| 1282 AstNode* node, | 1300 AstNode* node, |
| 1283 intptr_t id, | 1301 intptr_t id, |
| 1284 AstNode* receiver, | 1302 AstNode* receiver, |
| 1285 const String& field_name, | 1303 const String& field_name, |
| 1286 Register recv_reg) { | 1304 Register recv_reg) { |
| 1287 if (recv_reg != EBX) { | 1305 if (recv_reg != EBX) { |
| 1288 // TODO(srdjan): Do not hardwire register. | 1306 // TODO(srdjan): Do not hardwire register. |
| 1289 UNIMPLEMENTED(); | 1307 UNIMPLEMENTED(); |
| 1290 } | 1308 } |
| 1291 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); | 1309 DeoptimizationBlob* deopt_blob = |
| 1310 AddDeoptimizationBlob(node, EBX, kDeoptInstanceGetterSameTarget); | |
| 1292 if (NodeMayBeSmi(receiver)) { | 1311 if (NodeMayBeSmi(receiver)) { |
| 1293 __ testl(EBX, Immediate(kSmiTagMask)); | 1312 __ testl(EBX, Immediate(kSmiTagMask)); |
| 1294 __ j(ZERO, deopt_blob->label()); | 1313 __ j(ZERO, deopt_blob->label()); |
| 1295 } | 1314 } |
| 1296 | 1315 |
| 1297 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); | 1316 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); |
| 1298 const ICData& ic_data = node->ICDataAtId(id); | 1317 const ICData& ic_data = node->ICDataAtId(id); |
| 1299 Function& target = Function::Handle(); | 1318 Function& target = Function::Handle(); |
| 1300 Label load_field; | 1319 Label load_field; |
| 1301 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 1320 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1422 | 1441 |
| 1423 | 1442 |
| 1424 // TODO(srdjan): Implement for multiple getter targets. | 1443 // TODO(srdjan): Implement for multiple getter targets. |
| 1425 // For every class inline its implicit getter, or call the instance getter. | 1444 // For every class inline its implicit getter, or call the instance getter. |
| 1426 void OptimizingCodeGenerator::VisitInstanceGetterNode( | 1445 void OptimizingCodeGenerator::VisitInstanceGetterNode( |
| 1427 InstanceGetterNode* node) { | 1446 InstanceGetterNode* node) { |
| 1428 const ICData& ic_data = node->ICDataAtId(node->id()); | 1447 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1429 if (ic_data.NumberOfChecks() == 0) { | 1448 if (ic_data.NumberOfChecks() == 0) { |
| 1430 // No type feedback collected. | 1449 // No type feedback collected. |
| 1431 node->receiver()->Visit(this); | 1450 node->receiver()->Visit(this); |
| 1432 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node); | 1451 DeoptimizationBlob* deopt_blob = |
| 1452 AddDeoptimizationBlob(node, kDeoptInstanceGetter); | |
| 1433 __ jmp(deopt_blob->label()); | 1453 __ jmp(deopt_blob->label()); |
| 1434 return; | 1454 return; |
| 1435 } | 1455 } |
| 1436 | 1456 |
| 1437 VisitLoadOne(node->receiver(), EBX); | 1457 VisitLoadOne(node->receiver(), EBX); |
| 1438 InlineInstanceGetter(node, | 1458 InlineInstanceGetter(node, |
| 1439 node->id(), | 1459 node->id(), |
| 1440 node->receiver(), | 1460 node->receiver(), |
| 1441 node->field_name(), | 1461 node->field_name(), |
| 1442 EBX); | 1462 EBX); |
| 1443 // Result is in EAX. | 1463 // Result is in EAX. |
| 1444 if (CodeGenerator::IsResultNeeded(node)) { | 1464 if (CodeGenerator::IsResultNeeded(node)) { |
| 1445 __ pushl(EAX); | 1465 __ pushl(EAX); |
| 1446 } | 1466 } |
| 1447 } | 1467 } |
| 1448 | 1468 |
| 1449 | 1469 |
| 1450 // Clobber EBX leave 'value_reg' untouched. | 1470 // Clobber EBX leave 'value_reg' untouched. |
| 1451 void OptimizingCodeGenerator::InlineInstanceSettersWithSameTarget( | 1471 void OptimizingCodeGenerator::InlineInstanceSettersWithSameTarget( |
| 1452 AstNode* node, | 1472 AstNode* node, |
| 1453 intptr_t id, | 1473 intptr_t id, |
| 1454 AstNode* receiver, | 1474 AstNode* receiver, |
| 1455 const String& field_name, | 1475 const String& field_name, |
| 1456 Register recv_reg, | 1476 Register recv_reg, |
| 1457 Register value_reg) { | 1477 Register value_reg) { |
| 1458 ASSERT((recv_reg != EBX) && (value_reg != EBX)); | 1478 ASSERT((recv_reg != EBX) && (value_reg != EBX)); |
| 1459 DeoptimizationBlob* deopt_blob = | 1479 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob( |
| 1460 AddDeoptimizationBlob(node, recv_reg, value_reg); | 1480 node, recv_reg, value_reg, kDeoptInstanceSetterSameTarget); |
| 1461 if (NodeMayBeSmi(receiver)) { | 1481 if (NodeMayBeSmi(receiver)) { |
| 1462 __ testl(recv_reg, Immediate(kSmiTagMask)); | 1482 __ testl(recv_reg, Immediate(kSmiTagMask)); |
| 1463 __ j(ZERO, deopt_blob->label()); | 1483 __ j(ZERO, deopt_blob->label()); |
| 1464 } | 1484 } |
| 1465 __ movl(EBX, FieldAddress(recv_reg, Object::class_offset())); | 1485 __ movl(EBX, FieldAddress(recv_reg, Object::class_offset())); |
| 1466 const ICData& ic_data = node->ICDataAtId(id); | 1486 const ICData& ic_data = node->ICDataAtId(id); |
| 1467 Function& target = Function::Handle(); | 1487 Function& target = Function::Handle(); |
| 1468 Label store_field; | 1488 Label store_field; |
| 1469 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 1489 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 1470 Class& cls = Class::ZoneHandle(); | 1490 Class& cls = Class::ZoneHandle(); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1513 InstanceSetterNode* node) { | 1533 InstanceSetterNode* node) { |
| 1514 // TODO(srdjan): inline setters to different targets as well. | 1534 // TODO(srdjan): inline setters to different targets as well. |
| 1515 if (FLAG_enable_type_checks || | 1535 if (FLAG_enable_type_checks || |
| 1516 !ICDataToSameInlineableInstanceSetter(node->ICDataAtId(node->id()))) { | 1536 !ICDataToSameInlineableInstanceSetter(node->ICDataAtId(node->id()))) { |
| 1517 CodeGenerator::VisitInstanceSetterNode(node); | 1537 CodeGenerator::VisitInstanceSetterNode(node); |
| 1518 return; | 1538 return; |
| 1519 } | 1539 } |
| 1520 VisitLoadTwo(node->receiver(), node->value(), EDX, EAX); | 1540 VisitLoadTwo(node->receiver(), node->value(), EDX, EAX); |
| 1521 const ICData& ic_data = node->ICDataAtId(node->id()); | 1541 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1522 if (ic_data.NumberOfChecks() == 0) { | 1542 if (ic_data.NumberOfChecks() == 0) { |
| 1523 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EDX, EAX); | 1543 DeoptimizationBlob* deopt_blob = |
| 1544 AddDeoptimizationBlob(node, EDX, EAX, kDeoptInstanceSetter); | |
| 1524 __ jmp(deopt_blob->label()); | 1545 __ jmp(deopt_blob->label()); |
| 1525 return; | 1546 return; |
| 1526 } | 1547 } |
| 1527 // Value in EAX survives and will be stored on stack if result is needed. | 1548 // Value in EAX survives and will be stored on stack if result is needed. |
| 1528 InlineInstanceSetter(node, | 1549 InlineInstanceSetter(node, |
| 1529 node->id(), | 1550 node->id(), |
| 1530 node->receiver(), | 1551 node->receiver(), |
| 1531 node->field_name(), | 1552 node->field_name(), |
| 1532 EDX, | 1553 EDX, |
| 1533 EAX); | 1554 EAX); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1613 CodeGenInfo left_info(node->left()); | 1634 CodeGenInfo left_info(node->left()); |
| 1614 CodeGenInfo right_info(node->right()); | 1635 CodeGenInfo right_info(node->right()); |
| 1615 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 1636 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 1616 if (!CodeGenerator::IsResultNeeded(node)) { | 1637 if (!CodeGenerator::IsResultNeeded(node)) { |
| 1617 return; | 1638 return; |
| 1618 } | 1639 } |
| 1619 const Immediate raw_null = | 1640 const Immediate raw_null = |
| 1620 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1641 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1621 Label evaluate_comparison; | 1642 Label evaluate_comparison; |
| 1622 if (!left_info.IsClass(smi_class_)) { | 1643 if (!left_info.IsClass(smi_class_)) { |
| 1623 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EDX); | 1644 DeoptimizationBlob* deopt_blob = |
| 1645 AddDeoptimizationBlob(node, EAX, EDX, kDeoptSmiEquality); | |
| 1624 Label left_not_null; | 1646 Label left_not_null; |
| 1625 __ cmpl(EAX, raw_null); | 1647 __ cmpl(EAX, raw_null); |
| 1626 __ j(NOT_EQUAL, &left_not_null, Assembler::kNearJump); | 1648 __ j(NOT_EQUAL, &left_not_null, Assembler::kNearJump); |
| 1627 | 1649 |
| 1628 // Left is null, strict compare. | 1650 // Left is null, strict compare. |
| 1629 __ cmpl(EAX, EDX); | 1651 __ cmpl(EAX, EDX); |
| 1630 __ jmp(&evaluate_comparison, Assembler::kNearJump); | 1652 __ jmp(&evaluate_comparison, Assembler::kNearJump); |
| 1631 | 1653 |
| 1632 // Deoptimize if left is not Smi. | 1654 // Deoptimize if left is not Smi. |
| 1633 __ Bind(&left_not_null); | 1655 __ Bind(&left_not_null); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1705 CodeGenInfo left_info(node->left()); | 1727 CodeGenInfo left_info(node->left()); |
| 1706 CodeGenInfo right_info(node->right()); | 1728 CodeGenInfo right_info(node->right()); |
| 1707 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 1729 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 1708 if (!CodeGenerator::IsResultNeeded(node)) { | 1730 if (!CodeGenerator::IsResultNeeded(node)) { |
| 1709 return true; | 1731 return true; |
| 1710 } | 1732 } |
| 1711 if (left_info.IsClass(smi_class_) && right_info.IsClass(smi_class_)) { | 1733 if (left_info.IsClass(smi_class_) && right_info.IsClass(smi_class_)) { |
| 1712 __ cmpl(EAX, EDX); | 1734 __ cmpl(EAX, EDX); |
| 1713 } else if (left_info.IsClass(smi_class_) || right_info.IsClass(smi_class_)) { | 1735 } else if (left_info.IsClass(smi_class_) || right_info.IsClass(smi_class_)) { |
| 1714 // One is Smi. | 1736 // One is Smi. |
| 1715 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EDX); | 1737 DeoptimizationBlob* deopt_blob = |
| 1738 AddDeoptimizationBlob(node, EAX, EDX, kDeoptSmiCompareSmis); | |
| 1716 Register reg_to_test = left_info.IsClass(smi_class_) ? EDX : EAX; | 1739 Register reg_to_test = left_info.IsClass(smi_class_) ? EDX : EAX; |
| 1717 __ testl(reg_to_test, Immediate(kSmiTagMask)); | 1740 __ testl(reg_to_test, Immediate(kSmiTagMask)); |
| 1718 __ j(NOT_ZERO, deopt_blob->label()); | 1741 __ j(NOT_ZERO, deopt_blob->label()); |
| 1719 __ cmpl(EAX, EDX); | 1742 __ cmpl(EAX, EDX); |
| 1720 } else { | 1743 } else { |
| 1721 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, ECX, EDX); | 1744 DeoptimizationBlob* deopt_blob = |
| 1745 AddDeoptimizationBlob(node, ECX, EDX, kDeoptSmiCompareAny); | |
| 1722 __ movl(ECX, EAX); | 1746 __ movl(ECX, EAX); |
| 1723 __ orl(EAX, EDX); | 1747 __ orl(EAX, EDX); |
| 1724 __ testl(EAX, Immediate(kSmiTagMask)); | 1748 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1725 __ j(NOT_ZERO, deopt_blob->label()); | 1749 __ j(NOT_ZERO, deopt_blob->label()); |
| 1726 __ cmpl(ECX, EDX); | 1750 __ cmpl(ECX, EDX); |
| 1727 } | 1751 } |
| 1728 if (NodeInfoHasLabels(node)) { | 1752 if (NodeInfoHasLabels(node)) { |
| 1729 GenerateConditionalJumps(*(node->info()), condition); | 1753 GenerateConditionalJumps(*(node->info()), condition); |
| 1730 node->info()->set_labels_used(true); | 1754 node->info()->set_labels_used(true); |
| 1731 } else { | 1755 } else { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1805 TraceNotOpt(node, "Equality comparison, mixed with Smi"); | 1829 TraceNotOpt(node, "Equality comparison, mixed with Smi"); |
| 1806 return false; | 1830 return false; |
| 1807 } | 1831 } |
| 1808 } | 1832 } |
| 1809 | 1833 |
| 1810 // All targets are Object.==, i.e., '==='. Smi is not among the classes. | 1834 // All targets are Object.==, i.e., '==='. Smi is not among the classes. |
| 1811 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 1835 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 1812 if (!CodeGenerator::IsResultNeeded(node)) { | 1836 if (!CodeGenerator::IsResultNeeded(node)) { |
| 1813 return true; | 1837 return true; |
| 1814 } | 1838 } |
| 1815 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EDX); | |
| 1816 Label compare; | 1839 Label compare; |
| 1817 // Comparison with NULL is "===". | 1840 // Comparison with NULL is "===". |
| 1818 const Immediate raw_null = | 1841 const Immediate raw_null = |
| 1819 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1842 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1820 __ cmpl(EAX, raw_null); | 1843 __ cmpl(EAX, raw_null); |
| 1821 if (num_classes == 0) { | 1844 if (num_classes == 0) { |
| 1845 DeoptimizationBlob* deopt_blob = | |
| 1846 AddDeoptimizationBlob(node, EAX, EDX, kDeoptEqualityNoFeedback); | |
| 1822 __ j(NOT_EQUAL, deopt_blob->label()); | 1847 __ j(NOT_EQUAL, deopt_blob->label()); |
| 1823 } else { | 1848 } else { |
| 1849 DeoptimizationBlob* deopt_blob = | |
| 1850 AddDeoptimizationBlob(node, EAX, EDX, kDeoptEqualityClassCheck); | |
| 1824 __ j(EQUAL, &compare); | 1851 __ j(EQUAL, &compare); |
| 1825 // Smi causes deoptimization. | 1852 // Smi causes deoptimization. |
| 1826 __ testl(EAX, Immediate(kSmiTagMask)); | 1853 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1827 __ j(ZERO, deopt_blob->label()); | 1854 __ j(ZERO, deopt_blob->label()); |
| 1828 __ movl(EBX, FieldAddress(EAX, Object::class_offset())); | 1855 __ movl(EBX, FieldAddress(EAX, Object::class_offset())); |
| 1829 for (intptr_t i = 0; i < num_classes; i++) { | 1856 for (intptr_t i = 0; i < num_classes; i++) { |
| 1830 const Class& cls = *(*classes)[i]; | 1857 const Class& cls = *(*classes)[i]; |
| 1831 __ CompareObject(EBX, cls); | 1858 __ CompareObject(EBX, cls); |
| 1832 if (i == (num_classes - 1)) { | 1859 if (i == (num_classes - 1)) { |
| 1833 __ j(NOT_EQUAL, deopt_blob->label()); | 1860 __ j(NOT_EQUAL, deopt_blob->label()); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1869 if (!SupportedTokenKindToDoubleCondition(node->kind(), &true_condition)) { | 1896 if (!SupportedTokenKindToDoubleCondition(node->kind(), &true_condition)) { |
| 1870 return false; | 1897 return false; |
| 1871 } | 1898 } |
| 1872 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1899 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1873 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1900 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1874 CodeGenInfo left_info(node->left()); | 1901 CodeGenInfo left_info(node->left()); |
| 1875 CodeGenInfo right_info(node->right()); | 1902 CodeGenInfo right_info(node->right()); |
| 1876 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 1903 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 1877 DeoptimizationBlob* deopt_blob = NULL; | 1904 DeoptimizationBlob* deopt_blob = NULL; |
| 1878 if (!left_info.IsClass(double_class_) || !right_info.IsClass(double_class_)) { | 1905 if (!left_info.IsClass(double_class_) || !right_info.IsClass(double_class_)) { |
| 1879 deopt_blob = AddDeoptimizationBlob(node, EAX, EDX); | 1906 deopt_blob = AddDeoptimizationBlob(node, EAX, EDX, kDeoptDoubleComparison); |
| 1880 } | 1907 } |
| 1881 if (!left_info.IsClass(double_class_)) { | 1908 if (!left_info.IsClass(double_class_)) { |
| 1882 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); | 1909 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); |
| 1883 } | 1910 } |
| 1884 if (!right_info.IsClass(double_class_)) { | 1911 if (!right_info.IsClass(double_class_)) { |
| 1885 CheckIfDoubleOrSmi(EDX, EBX, deopt_blob->label(), deopt_blob->label()); | 1912 CheckIfDoubleOrSmi(EDX, EBX, deopt_blob->label(), deopt_blob->label()); |
| 1886 } | 1913 } |
| 1887 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1914 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
| 1888 __ movsd(XMM1, FieldAddress(EDX, Double::value_offset())); | 1915 __ movsd(XMM1, FieldAddress(EDX, Double::value_offset())); |
| 1889 __ comisd(XMM0, XMM1); | 1916 __ comisd(XMM0, XMM1); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1970 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { | 1997 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { |
| 1971 const char* kMessage = "Inline indexed access"; | 1998 const char* kMessage = "Inline indexed access"; |
| 1972 ObjectStore* object_store = Isolate::Current()->object_store(); | 1999 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 1973 const Class& object_array_class = | 2000 const Class& object_array_class = |
| 1974 Class::ZoneHandle(object_store->array_class()); | 2001 Class::ZoneHandle(object_store->array_class()); |
| 1975 const Class& immutable_object_array_class = | 2002 const Class& immutable_object_array_class = |
| 1976 Class::ZoneHandle(object_store->immutable_array_class()); | 2003 Class::ZoneHandle(object_store->immutable_array_class()); |
| 1977 if (AtIdNodeHasOnlyClass(node, node->id(), object_array_class) || | 2004 if (AtIdNodeHasOnlyClass(node, node->id(), object_array_class) || |
| 1978 AtIdNodeHasOnlyClass(node, node->id(), immutable_object_array_class)) { | 2005 AtIdNodeHasOnlyClass(node, node->id(), immutable_object_array_class)) { |
| 1979 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX); | 2006 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX); |
| 1980 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX, EDX); | 2007 DeoptimizationBlob* deopt_blob = |
| 2008 AddDeoptimizationBlob(node, EBX, EDX, kDeoptLoadIndexedFixedArray); | |
| 1981 const Class& test_class = | 2009 const Class& test_class = |
| 1982 AtIdNodeHasOnlyClass(node, node->id(), object_array_class) ? | 2010 AtIdNodeHasOnlyClass(node, node->id(), object_array_class) ? |
| 1983 object_array_class : immutable_object_array_class; | 2011 object_array_class : immutable_object_array_class; |
| 1984 // Type checks of array. | 2012 // Type checks of array. |
| 1985 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi. | 2013 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi. |
| 1986 __ j(ZERO, deopt_blob->label()); | 2014 __ j(ZERO, deopt_blob->label()); |
| 1987 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); | 2015 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); |
| 1988 __ CompareObject(EAX, test_class); | 2016 __ CompareObject(EAX, test_class); |
| 1989 __ j(NOT_EQUAL, deopt_blob->label()); | 2017 __ j(NOT_EQUAL, deopt_blob->label()); |
| 1990 | 2018 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 2012 if (AtIdNodeHasOnlyClass(node, node->id(), growable_array_class)) { | 2040 if (AtIdNodeHasOnlyClass(node, node->id(), growable_array_class)) { |
| 2013 const String& growable_array_length_field_name = | 2041 const String& growable_array_length_field_name = |
| 2014 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName)); | 2042 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName)); |
| 2015 const String& growable_array_array_field_name = | 2043 const String& growable_array_array_field_name = |
| 2016 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName)); | 2044 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName)); |
| 2017 intptr_t length_offset = GetFieldOffset(growable_array_class, | 2045 intptr_t length_offset = GetFieldOffset(growable_array_class, |
| 2018 growable_array_length_field_name); | 2046 growable_array_length_field_name); |
| 2019 intptr_t array_offset = GetFieldOffset(growable_array_class, | 2047 intptr_t array_offset = GetFieldOffset(growable_array_class, |
| 2020 growable_array_array_field_name); | 2048 growable_array_array_field_name); |
| 2021 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX); | 2049 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX); |
| 2022 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EDX, EAX); | 2050 DeoptimizationBlob* deopt_blob = |
| 2051 AddDeoptimizationBlob(node, EDX, EAX, kDeoptLoadIndexedGrowableArray); | |
| 2023 // TODO(srdjan): Use CodeGenInfo to eliminate Smi test if possible. | 2052 // TODO(srdjan): Use CodeGenInfo to eliminate Smi test if possible. |
| 2024 // EAX: index, EDX: array. | 2053 // EAX: index, EDX: array. |
| 2025 __ testl(EAX, Immediate(kSmiTagMask)); | 2054 __ testl(EAX, Immediate(kSmiTagMask)); |
| 2026 __ j(NOT_ZERO, deopt_blob->label()); // Not Smi index. | 2055 __ j(NOT_ZERO, deopt_blob->label()); // Not Smi index. |
| 2027 __ testl(EDX, Immediate(kSmiTagMask)); | 2056 __ testl(EDX, Immediate(kSmiTagMask)); |
| 2028 __ j(ZERO, deopt_blob->label()); // Array is Smi. | 2057 __ j(ZERO, deopt_blob->label()); // Array is Smi. |
| 2029 __ movl(EBX, FieldAddress(EDX, Object::class_offset())); | 2058 __ movl(EBX, FieldAddress(EDX, Object::class_offset())); |
| 2030 __ CompareObject(EBX, growable_array_class); | 2059 __ CompareObject(EBX, growable_array_class); |
| 2031 __ j(NOT_EQUAL, deopt_blob->label()); // Array is not GrowableObjectArray. | 2060 __ j(NOT_EQUAL, deopt_blob->label()); // Array is not GrowableObjectArray. |
| 2032 // Range check: deoptimize if out of bounds. | 2061 // Range check: deoptimize if out of bounds. |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 2053 CodeGenerator::VisitStoreIndexedNode(node); | 2082 CodeGenerator::VisitStoreIndexedNode(node); |
| 2054 return; | 2083 return; |
| 2055 } | 2084 } |
| 2056 node->array()->Visit(this); | 2085 node->array()->Visit(this); |
| 2057 // TODO(srdjan): Use VisitLoadTwo and check if index is smi (CodeGenInfo). | 2086 // TODO(srdjan): Use VisitLoadTwo and check if index is smi (CodeGenInfo). |
| 2058 ObjectStore* object_store = Isolate::Current()->object_store(); | 2087 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 2059 const Class& object_array_class = | 2088 const Class& object_array_class = |
| 2060 Class::ZoneHandle(object_store->array_class()); | 2089 Class::ZoneHandle(object_store->array_class()); |
| 2061 if (AtIdNodeHasOnlyClass(node, node->id(), object_array_class)) { | 2090 if (AtIdNodeHasOnlyClass(node, node->id(), object_array_class)) { |
| 2062 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); | 2091 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); |
| 2063 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EBX, ECX); | 2092 DeoptimizationBlob* deopt_blob = |
| 2093 AddDeoptimizationBlob(node, EAX, EBX, ECX, kDeoptStoreIndexed); | |
| 2064 __ popl(EAX); // array. | 2094 __ popl(EAX); // array. |
| 2065 // ECX: value, EBX:index, EAX: array. | 2095 // ECX: value, EBX:index, EAX: array. |
| 2066 // Check type of array. | 2096 // Check type of array. |
| 2067 __ testl(EAX, Immediate(kSmiTagMask)); | 2097 __ testl(EAX, Immediate(kSmiTagMask)); |
| 2068 __ j(ZERO, deopt_blob->label()); // Array is smi -> deopt. | 2098 __ j(ZERO, deopt_blob->label()); // Array is smi -> deopt. |
| 2069 __ movl(EDX, FieldAddress(EAX, Object::class_offset())); | 2099 __ movl(EDX, FieldAddress(EAX, Object::class_offset())); |
| 2070 __ CompareObject(EDX, object_array_class); | 2100 __ CompareObject(EDX, object_array_class); |
| 2071 __ j(NOT_EQUAL, deopt_blob->label()); // Not ObjectArray -> deopt. | 2101 __ j(NOT_EQUAL, deopt_blob->label()); // Not ObjectArray -> deopt. |
| 2072 // Check type of index. | 2102 // Check type of index. |
| 2073 __ testl(EBX, Immediate(kSmiTagMask)); | 2103 __ testl(EBX, Immediate(kSmiTagMask)); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2207 } else { | 2237 } else { |
| 2208 __ Bind(&false_label); | 2238 __ Bind(&false_label); |
| 2209 } | 2239 } |
| 2210 __ Bind(&done); | 2240 __ Bind(&done); |
| 2211 } | 2241 } |
| 2212 | 2242 |
| 2213 | 2243 |
| 2214 void OptimizingCodeGenerator::GenerateDirectCall( | 2244 void OptimizingCodeGenerator::GenerateDirectCall( |
| 2215 intptr_t node_id, | 2245 intptr_t node_id, |
| 2216 intptr_t token_index, | 2246 intptr_t token_index, |
| 2217 Function& target, | 2247 const Function& target, |
| 2218 intptr_t arg_count, | 2248 intptr_t arg_count, |
| 2219 const Array& optional_argument_names) { | 2249 const Array& optional_argument_names) { |
| 2220 ASSERT(!target.IsNull()); | 2250 ASSERT(!target.IsNull()); |
| 2221 const Code& code = Code::Handle(target.code()); | 2251 const Code& code = Code::Handle(target.code()); |
| 2222 ASSERT(!code.IsNull()); | 2252 ASSERT(!code.IsNull()); |
| 2223 ExternalLabel target_label("DirectInstanceCall", code.EntryPoint()); | 2253 ExternalLabel target_label("DirectInstanceCall", code.EntryPoint()); |
| 2224 | 2254 |
| 2225 __ LoadObject(ECX, target); | 2255 __ LoadObject(ECX, target); |
| 2226 __ LoadObject(EDX, ArgumentsDescriptor(arg_count, optional_argument_names)); | 2256 __ LoadObject(EDX, ArgumentsDescriptor(arg_count, optional_argument_names)); |
| 2227 __ call(&target_label); | 2257 __ call(&target_label); |
| 2228 AddCurrentDescriptor(PcDescriptors::kOther, node_id, token_index); | 2258 AddCurrentDescriptor(PcDescriptors::kOther, node_id, token_index); |
| 2229 __ addl(ESP, Immediate(arg_count * kWordSize)); | 2259 __ addl(ESP, Immediate(arg_count * kWordSize)); |
| 2230 } | 2260 } |
| 2231 | 2261 |
| 2232 | 2262 |
| 2263 // Generate inline cache calls instead of deoptimizing when no type feedback is | |
| 2264 // provided. | |
| 2265 // TODO(srdjan): Recompilation framework should recognize active IC calls | |
| 2266 // in optimized code and mark them for reoptimization since type feedback was | |
| 2267 // collected in the meantime. | |
| 2268 void OptimizingCodeGenerator::GenerateInlineCacheCall( | |
| 2269 intptr_t node_id, | |
| 2270 intptr_t token_index, | |
| 2271 const ICData& ic_data, | |
| 2272 intptr_t num_args, | |
| 2273 const Array& optional_arguments_names) { | |
| 2274 __ LoadObject(ECX, Array::ZoneHandle(ic_data.data())); | |
| 2275 __ LoadObject(EDX, ArgumentsDescriptor(num_args, optional_arguments_names)); | |
| 2276 ExternalLabel target_label( | |
| 2277 "InlineCache", StubCode::InlineCacheEntryPoint()); | |
| 2278 | |
| 2279 __ call(&target_label); | |
| 2280 AddCurrentDescriptor(PcDescriptors::kIcCall, | |
| 2281 node_id, | |
| 2282 token_index); | |
| 2283 __ addl(ESP, Immediate(num_args * kWordSize)); | |
| 2284 } | |
| 2285 | |
| 2286 | |
| 2287 // Normalizes the ic_data class/target pairs: | |
| 2288 // - If Smi class exists, make it the first one. | |
| 2289 // - If 'null_target' not null, append null-class/'null_target' | |
| 2290 void OptimizingCodeGenerator::NormalizeClassChecks( | |
| 2291 const ICData& ic_data, | |
| 2292 const Function& null_target, | |
| 2293 GrowableArray<const Class*>* classes, | |
| 2294 GrowableArray<const Function*>* targets) { | |
| 2295 ASSERT(classes != NULL); | |
| 2296 ASSERT(targets != NULL); | |
| 2297 // Check if we can add Smi class in front. | |
| 2298 Class& smi_test_class = Class::Handle(); | |
| 2299 Function& smi_target = Function::ZoneHandle(); | |
| 2300 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | |
| 2301 ic_data.GetOneClassCheckAt(i, &smi_test_class, &smi_target); | |
| 2302 if (smi_test_class.raw() == smi_class_.raw()) { | |
| 2303 classes->Add(&Class::ZoneHandle(smi_class_.raw())); | |
| 2304 targets->Add(&Function::ZoneHandle(smi_target.raw())); | |
| 2305 break; | |
| 2306 } | |
| 2307 } | |
| 2308 // Add all classes except Smi. | |
| 2309 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | |
| 2310 Function& target = Function::ZoneHandle(); | |
| 2311 Class& cls = Class::ZoneHandle(); | |
| 2312 ic_data.GetOneClassCheckAt(i, &cls, &target); | |
| 2313 ASSERT(!cls.IsNullClass()); | |
| 2314 if (cls.raw() != smi_class_.raw()) { | |
| 2315 ASSERT(!cls.IsNull()); | |
| 2316 ASSERT(!target.IsNull()); | |
| 2317 classes->Add(&cls); | |
| 2318 targets->Add(&target); | |
| 2319 } | |
| 2320 } | |
| 2321 // Do not add a target that has not been compiled yet. | |
| 2322 if (!null_target.IsNull() && null_target.HasCode()) { | |
| 2323 ASSERT(null_target.IsZoneHandle()); | |
| 2324 classes->Add(&Class::ZoneHandle(Object::null_class())); | |
| 2325 targets->Add(&null_target); | |
| 2326 } | |
| 2327 } | |
| 2328 | |
| 2329 | |
| 2233 // Use ICData in 'node' to issues checks and calls. | 2330 // Use ICData in 'node' to issues checks and calls. |
| 2234 void OptimizingCodeGenerator::GenerateCheckedInstanceCalls( | 2331 void OptimizingCodeGenerator::GenerateCheckedInstanceCalls( |
| 2235 AstNode* node, | 2332 AstNode* node, |
| 2236 AstNode* receiver, | 2333 AstNode* receiver, |
| 2237 intptr_t node_id, | 2334 intptr_t node_id, |
| 2238 intptr_t token_index, | 2335 intptr_t token_index, |
| 2239 intptr_t num_args, | 2336 intptr_t num_args, |
| 2240 const Array& optional_argument_names) { | 2337 const Array& optional_arguments_names) { |
| 2241 ASSERT(node != NULL); | 2338 ASSERT(node != NULL); |
| 2242 ASSERT(receiver != NULL); | 2339 ASSERT(receiver != NULL); |
| 2243 ASSERT(num_args > 0); | 2340 ASSERT(num_args > 0); |
| 2244 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node); | |
| 2245 const ICData& ic_data = node->ICDataAtId(node_id); | 2341 const ICData& ic_data = node->ICDataAtId(node_id); |
| 2246 if (ic_data.NumberOfChecks() == 0) { | 2342 if (ic_data.NumberOfChecks() == 0) { |
| 2247 // No type feedback means node was never executed. | 2343 // No type feedback means node was never executed. However that can be |
| 2248 __ jmp(deopt_blob->label()); | 2344 // a common case especially in case of large switch statements. |
| 2345 // Use a special inline cache call which can help us decide when to | |
| 2346 // re-optimize this optiumized function. | |
|
regis
2011/11/16 23:06:45
optiumized?
opium-ized?
| |
| 2347 GenerateInlineCacheCall( | |
| 2348 node_id, token_index, ic_data, num_args, optional_arguments_names); | |
| 2249 return; | 2349 return; |
| 2250 } | 2350 } |
| 2251 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); | 2351 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); |
| 2252 | 2352 |
| 2253 // First test for Smi. Null object will cause deoptimization. | 2353 Function& target_for_null = Function::ZoneHandle(); |
| 2254 intptr_t smi_class_index = -1; | 2354 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 2255 Class& smi_test_class = Class::Handle(); | 2355 int num_optional_args = |
| 2256 Function& smi_target = Function::ZoneHandle(); | 2356 optional_arguments_names.IsNull() ? 0 : optional_arguments_names.Length(); |
| 2257 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 2357 target_for_null = Resolver::ResolveDynamicForReceiverClass( |
| 2258 ic_data.GetOneClassCheckAt(i, &smi_test_class, &smi_target); | 2358 Class::Handle(object_store->object_class()), |
| 2259 if (smi_test_class.raw() == smi_class_.raw()) { | 2359 String::Handle(ic_data.FunctionName()), |
| 2260 smi_class_index = i; | 2360 num_args, |
| 2261 break; | 2361 num_optional_args); |
| 2262 } | 2362 GrowableArray<const Class*> classes; |
| 2263 } | 2363 GrowableArray<const Function*> targets; |
| 2364 NormalizeClassChecks(ic_data, target_for_null, &classes, &targets); | |
| 2365 ASSERT(!classes.is_empty()); | |
| 2366 ASSERT(classes.length() == targets.length()); | |
| 2367 intptr_t start_ix = 0; | |
| 2264 | 2368 |
| 2265 Label done; | 2369 Label done; |
| 2266 __ movl(EAX, Address(ESP, (num_args - 1) * kWordSize)); // Load receiver. | 2370 __ movl(EAX, Address(ESP, (num_args - 1) * kWordSize)); // Load receiver. |
| 2267 if (smi_class_index >= 0) { | 2371 if (classes[0]->raw() == smi_class_.raw()) { |
| 2372 start_ix++; | |
| 2268 // Smi test is needed. | 2373 // Smi test is needed. |
| 2269 __ testl(EAX, Immediate(kSmiTagMask)); | 2374 __ testl(EAX, Immediate(kSmiTagMask)); |
| 2270 if (ic_data.NumberOfChecks() == 1) { | 2375 if (classes.length() == 1) { |
| 2271 // Only the Smi test. | 2376 // Only Smi test. |
| 2377 DeoptimizationBlob* deopt_blob = | |
| 2378 AddDeoptimizationBlob(node, kDeoptCheckedInstanceCallSmiOnly); | |
| 2272 __ j(NOT_ZERO, deopt_blob->label()); | 2379 __ j(NOT_ZERO, deopt_blob->label()); |
| 2273 GenerateDirectCall(node_id, | 2380 GenerateDirectCall(node_id, |
| 2274 token_index, | 2381 token_index, |
| 2275 smi_target, | 2382 *targets[0], |
| 2276 num_args, | 2383 num_args, |
| 2277 optional_argument_names); | 2384 optional_arguments_names); |
| 2278 return; | 2385 return; |
| 2279 } | 2386 } |
| 2280 Label not_smi; | 2387 Label not_smi; |
| 2281 __ j(NOT_ZERO, ¬_smi); | 2388 __ j(NOT_ZERO, ¬_smi); |
| 2282 GenerateDirectCall(node_id, | 2389 GenerateDirectCall(node_id, |
| 2283 token_index, | 2390 token_index, |
| 2284 smi_target, | 2391 *targets[0], |
| 2285 num_args, | 2392 num_args, |
| 2286 optional_argument_names); | 2393 optional_arguments_names); |
| 2287 __ jmp(&done); | 2394 __ jmp(&done); |
| 2288 __ Bind(¬_smi); // Continue with other test below. | 2395 __ Bind(¬_smi); // Continue with other test below. |
| 2289 } else if (NodeMayBeSmi(receiver)) { | 2396 } else if (NodeMayBeSmi(receiver)) { |
| 2397 DeoptimizationBlob* deopt_blob = | |
| 2398 AddDeoptimizationBlob(node, kDeoptCheckedInstanceCallSmiFail); | |
| 2290 __ testl(EAX, Immediate(kSmiTagMask)); | 2399 __ testl(EAX, Immediate(kSmiTagMask)); |
| 2291 __ j(ZERO, deopt_blob->label()); | 2400 __ j(ZERO, deopt_blob->label()); |
| 2292 } else { | 2401 } else { |
| 2293 // Receiver cannot be Smi, no need to test it. | 2402 // Receiver cannot be Smi, no need to test it. |
| 2294 } | 2403 } |
| 2295 | |
| 2296 intptr_t last_check_at = (smi_class_index == ic_data.NumberOfChecks() - 1) ? | |
| 2297 ic_data.NumberOfChecks() - 2 : ic_data.NumberOfChecks() - 1; | |
| 2298 // Every class may appear only once in the 'classes' array. Therefore, if | |
| 2299 // Smi class is last, it cannot be the second to last. | |
| 2300 __ movl(EAX, FieldAddress(EAX, Object::class_offset())); // Receiver's class. | 2404 __ movl(EAX, FieldAddress(EAX, Object::class_offset())); // Receiver's class. |
| 2301 for (intptr_t i = 0; i <= last_check_at; i++) { | 2405 for (intptr_t i = start_ix; i < classes.length(); i++) { |
| 2302 Function& target = Function::ZoneHandle(); | 2406 const Class& cls = *classes[i]; |
| 2303 Class& cls = Class::ZoneHandle(); | 2407 const Function& target = *targets[i]; |
| 2304 ic_data.GetOneClassCheckAt(i, &cls, &target); | |
| 2305 ASSERT(!cls.IsNullClass()); | |
| 2306 if (cls.raw() == smi_class_.raw()) { | |
| 2307 ASSERT(i < last_check_at); // Smi class may not be last. | |
| 2308 continue; // Skip Smi test. | |
| 2309 } | |
| 2310 __ CompareObject(EAX, cls); | 2408 __ CompareObject(EAX, cls); |
| 2311 if (i == last_check_at) { | 2409 if (i == (classes.length() - 1)) { |
| 2410 // Last check. | |
| 2411 DeoptimizationBlob* deopt_blob = | |
| 2412 AddDeoptimizationBlob(node, kDeoptCheckedInstanceCallCheckFail); | |
| 2312 __ j(NOT_EQUAL, deopt_blob->label()); | 2413 __ j(NOT_EQUAL, deopt_blob->label()); |
| 2313 GenerateDirectCall(node_id, | 2414 GenerateDirectCall(node_id, |
| 2314 token_index, | 2415 token_index, |
| 2315 target, | 2416 target, |
| 2316 num_args, | 2417 num_args, |
| 2317 optional_argument_names); | 2418 optional_arguments_names); |
| 2318 } else { | 2419 } else { |
| 2319 Label next; | 2420 Label next; |
| 2320 __ j(NOT_EQUAL, &next); | 2421 __ j(NOT_EQUAL, &next); |
| 2321 GenerateDirectCall(node_id, | 2422 GenerateDirectCall(node_id, |
| 2322 token_index, | 2423 token_index, |
| 2323 target, | 2424 target, |
| 2324 num_args, | 2425 num_args, |
| 2325 optional_argument_names); | 2426 optional_arguments_names); |
| 2326 __ jmp(&done); | 2427 __ jmp(&done); |
| 2327 __ Bind(&next); | 2428 __ Bind(&next); |
| 2328 } | 2429 } |
| 2329 } | 2430 } |
| 2330 __ Bind(&done); | 2431 __ Bind(&done); |
| 2331 } | 2432 } |
| 2332 | 2433 |
| 2333 | 2434 |
| 2334 void OptimizingCodeGenerator::VisitInstanceCallNode(InstanceCallNode* node) { | 2435 void OptimizingCodeGenerator::VisitInstanceCallNode(InstanceCallNode* node) { |
| 2335 const int number_of_arguments = node->arguments()->length() + 1; | 2436 const int number_of_arguments = node->arguments()->length() + 1; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2375 } | 2476 } |
| 2376 if ((recognized == Recognizer::kIntegerToDouble) && | 2477 if ((recognized == Recognizer::kIntegerToDouble) && |
| 2377 AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { | 2478 AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { |
| 2378 // TODO(srdjan): Check if we could use temporary double instead of | 2479 // TODO(srdjan): Check if we could use temporary double instead of |
| 2379 // allocating a new object every time. | 2480 // allocating a new object every time. |
| 2380 const Code& stub = | 2481 const Code& stub = |
| 2381 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); | 2482 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); |
| 2382 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); | 2483 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); |
| 2383 GenerateCall(node->token_index(), &label); | 2484 GenerateCall(node->token_index(), &label); |
| 2384 // EAX is double object. | 2485 // EAX is double object. |
| 2385 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); | 2486 DeoptimizationBlob* deopt_blob = |
| 2487 AddDeoptimizationBlob(node, EBX, kDeoptIntegerToDouble); | |
| 2386 __ popl(EBX); // Receiver | 2488 __ popl(EBX); // Receiver |
| 2387 __ testl(EBX, Immediate(kSmiTagMask)); | 2489 __ testl(EBX, Immediate(kSmiTagMask)); |
| 2388 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. | 2490 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. |
| 2389 __ SmiUntag(EBX); | 2491 __ SmiUntag(EBX); |
| 2390 __ cvtsi2sd(XMM0, EBX); | 2492 __ cvtsi2sd(XMM0, EBX); |
| 2391 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 2493 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 2392 return true; | 2494 return true; |
| 2393 } | 2495 } |
| 2394 | 2496 |
| 2395 if ((recognized == Recognizer::kDoubleToDouble) && | 2497 if ((recognized == Recognizer::kDoubleToDouble) && |
| 2396 AtIdNodeHasOnlyClass(node, node->id(), double_class_)) { | 2498 AtIdNodeHasOnlyClass(node, node->id(), double_class_)) { |
| 2397 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX); | 2499 DeoptimizationBlob* deopt_blob = |
| 2500 AddDeoptimizationBlob(node, EAX, kDeoptDoubleToDouble); | |
| 2398 __ popl(EAX); | 2501 __ popl(EAX); |
| 2399 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); | 2502 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); |
| 2400 return true; | 2503 return true; |
| 2401 } | 2504 } |
| 2402 } | 2505 } |
| 2403 return false; | 2506 return false; |
| 2404 } | 2507 } |
| 2405 | 2508 |
| 2406 | 2509 |
| 2407 // TODO(srdjan): For Math.sqrt read type feedback in Math.sqrt and decide | 2510 // TODO(srdjan): For Math.sqrt read type feedback in Math.sqrt and decide |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2447 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); | 2550 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); |
| 2448 // Result is in EAX. | 2551 // Result is in EAX. |
| 2449 if (IsResultNeeded(node)) { | 2552 if (IsResultNeeded(node)) { |
| 2450 __ pushl(EAX); | 2553 __ pushl(EAX); |
| 2451 } | 2554 } |
| 2452 } | 2555 } |
| 2453 | 2556 |
| 2454 } // namespace dart | 2557 } // namespace dart |
| 2455 | 2558 |
| 2456 #endif // defined TARGET_ARCH_IA32 | 2559 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |