Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(138)

Side by Side Diff: runtime/vm/opt_code_generator_ia32.cc

Issue 8588002: Better tracing of deoptimization (added a reason id and printing of source). Fix a bug with exces... (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/opt_code_generator_ia32.h ('k') | runtime/vm/stub_code_ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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, &not_smi); 2388 __ j(NOT_ZERO, &not_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(&not_smi); // Continue with other test below. 2395 __ Bind(&not_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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/opt_code_generator_ia32.h ('k') | runtime/vm/stub_code_ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698