| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 #ifndef DART_PRECOMPILED_RUNTIME | 4 #ifndef DART_PRECOMPILED_RUNTIME |
| 5 #include "vm/jit_optimizer.h" | 5 #include "vm/jit_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/branch_optimizer.h" | 8 #include "vm/branch_optimizer.h" |
| 9 #include "vm/cha.h" | 9 #include "vm/cha.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 namespace dart { | 29 namespace dart { |
| 30 | 30 |
| 31 // Quick access to the current isolate and zone. | 31 // Quick access to the current isolate and zone. |
| 32 #define I (isolate()) | 32 #define I (isolate()) |
| 33 #define Z (zone()) | 33 #define Z (zone()) |
| 34 | 34 |
| 35 static bool ShouldInlineSimd() { | 35 static bool ShouldInlineSimd() { |
| 36 return FlowGraphCompiler::SupportsUnboxedSimd128(); | 36 return FlowGraphCompiler::SupportsUnboxedSimd128(); |
| 37 } | 37 } |
| 38 | 38 |
| 39 | |
| 40 static bool CanUnboxDouble() { | 39 static bool CanUnboxDouble() { |
| 41 return FlowGraphCompiler::SupportsUnboxedDoubles(); | 40 return FlowGraphCompiler::SupportsUnboxedDoubles(); |
| 42 } | 41 } |
| 43 | 42 |
| 44 | |
| 45 static bool CanConvertUnboxedMintToDouble() { | 43 static bool CanConvertUnboxedMintToDouble() { |
| 46 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); | 44 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); |
| 47 } | 45 } |
| 48 | 46 |
| 49 | |
| 50 // Optimize instance calls using ICData. | 47 // Optimize instance calls using ICData. |
| 51 void JitOptimizer::ApplyICData() { | 48 void JitOptimizer::ApplyICData() { |
| 52 VisitBlocks(); | 49 VisitBlocks(); |
| 53 } | 50 } |
| 54 | 51 |
| 55 | |
| 56 // Optimize instance calls using cid. This is called after optimizer | 52 // Optimize instance calls using cid. This is called after optimizer |
| 57 // converted instance calls to instructions. Any remaining | 53 // converted instance calls to instructions. Any remaining |
| 58 // instance calls are either megamorphic calls, cannot be optimized or | 54 // instance calls are either megamorphic calls, cannot be optimized or |
| 59 // have no runtime type feedback collected. | 55 // have no runtime type feedback collected. |
| 60 // Attempts to convert an instance call (IC call) using propagated class-ids, | 56 // Attempts to convert an instance call (IC call) using propagated class-ids, |
| 61 // e.g., receiver class id, guarded-cid, or by guessing cid-s. | 57 // e.g., receiver class id, guarded-cid, or by guessing cid-s. |
| 62 void JitOptimizer::ApplyClassIds() { | 58 void JitOptimizer::ApplyClassIds() { |
| 63 ASSERT(current_iterator_ == NULL); | 59 ASSERT(current_iterator_ == NULL); |
| 64 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 60 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 65 !block_it.Done(); block_it.Advance()) { | 61 !block_it.Done(); block_it.Advance()) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 76 } | 72 } |
| 77 } | 73 } |
| 78 } else if (instr->IsPolymorphicInstanceCall()) { | 74 } else if (instr->IsPolymorphicInstanceCall()) { |
| 79 SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall()); | 75 SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall()); |
| 80 } | 76 } |
| 81 } | 77 } |
| 82 current_iterator_ = NULL; | 78 current_iterator_ = NULL; |
| 83 } | 79 } |
| 84 } | 80 } |
| 85 | 81 |
| 86 | |
| 87 // TODO(srdjan): Test/support other number types as well. | 82 // TODO(srdjan): Test/support other number types as well. |
| 88 static bool IsNumberCid(intptr_t cid) { | 83 static bool IsNumberCid(intptr_t cid) { |
| 89 return (cid == kSmiCid) || (cid == kDoubleCid); | 84 return (cid == kSmiCid) || (cid == kDoubleCid); |
| 90 } | 85 } |
| 91 | 86 |
| 92 | |
| 93 bool JitOptimizer::TryCreateICData(InstanceCallInstr* call) { | 87 bool JitOptimizer::TryCreateICData(InstanceCallInstr* call) { |
| 94 ASSERT(call->HasICData()); | 88 ASSERT(call->HasICData()); |
| 95 if (call->ic_data()->NumberOfUsedChecks() > 0) { | 89 if (call->ic_data()->NumberOfUsedChecks() > 0) { |
| 96 // This occurs when an instance call has too many checks, will be converted | 90 // This occurs when an instance call has too many checks, will be converted |
| 97 // to megamorphic call. | 91 // to megamorphic call. |
| 98 return false; | 92 return false; |
| 99 } | 93 } |
| 100 | 94 |
| 101 const intptr_t receiver_index = call->FirstParamIndex(); | 95 const intptr_t receiver_index = call->FirstParamIndex(); |
| 102 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); | 96 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 ic_data.AddReceiverCheck(owner_class.id(), function); | 183 ic_data.AddReceiverCheck(owner_class.id(), function); |
| 190 call->set_ic_data(&ic_data); | 184 call->set_ic_data(&ic_data); |
| 191 return true; | 185 return true; |
| 192 } | 186 } |
| 193 } | 187 } |
| 194 } | 188 } |
| 195 | 189 |
| 196 return false; | 190 return false; |
| 197 } | 191 } |
| 198 | 192 |
| 199 | |
| 200 void JitOptimizer::SpecializePolymorphicInstanceCall( | 193 void JitOptimizer::SpecializePolymorphicInstanceCall( |
| 201 PolymorphicInstanceCallInstr* call) { | 194 PolymorphicInstanceCallInstr* call) { |
| 202 if (!FLAG_polymorphic_with_deopt) { | 195 if (!FLAG_polymorphic_with_deopt) { |
| 203 // Specialization adds receiver checks which can lead to deoptimization. | 196 // Specialization adds receiver checks which can lead to deoptimization. |
| 204 return; | 197 return; |
| 205 } | 198 } |
| 206 | 199 |
| 207 const intptr_t receiver_cid = | 200 const intptr_t receiver_cid = |
| 208 call->PushArgumentAt(0)->value()->Type()->ToCid(); | 201 call->PushArgumentAt(0)->value()->Type()->ToCid(); |
| 209 if (receiver_cid == kDynamicCid) { | 202 if (receiver_cid == kDynamicCid) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 220 // No specialization. | 213 // No specialization. |
| 221 return; | 214 return; |
| 222 } | 215 } |
| 223 | 216 |
| 224 ASSERT(targets->HasSingleTarget()); | 217 ASSERT(targets->HasSingleTarget()); |
| 225 const Function& target = targets->FirstTarget(); | 218 const Function& target = targets->FirstTarget(); |
| 226 StaticCallInstr* specialized = StaticCallInstr::FromCall(Z, call, target); | 219 StaticCallInstr* specialized = StaticCallInstr::FromCall(Z, call, target); |
| 227 call->ReplaceWith(specialized, current_iterator()); | 220 call->ReplaceWith(specialized, current_iterator()); |
| 228 } | 221 } |
| 229 | 222 |
| 230 | |
| 231 static bool ClassIdIsOneOf(intptr_t class_id, | 223 static bool ClassIdIsOneOf(intptr_t class_id, |
| 232 const GrowableArray<intptr_t>& class_ids) { | 224 const GrowableArray<intptr_t>& class_ids) { |
| 233 for (intptr_t i = 0; i < class_ids.length(); i++) { | 225 for (intptr_t i = 0; i < class_ids.length(); i++) { |
| 234 ASSERT(class_ids[i] != kIllegalCid); | 226 ASSERT(class_ids[i] != kIllegalCid); |
| 235 if (class_ids[i] == class_id) { | 227 if (class_ids[i] == class_id) { |
| 236 return true; | 228 return true; |
| 237 } | 229 } |
| 238 } | 230 } |
| 239 return false; | 231 return false; |
| 240 } | 232 } |
| 241 | 233 |
| 242 | |
| 243 // Returns true if ICData tests two arguments and all ICData cids are in the | 234 // Returns true if ICData tests two arguments and all ICData cids are in the |
| 244 // required sets 'receiver_class_ids' or 'argument_class_ids', respectively. | 235 // required sets 'receiver_class_ids' or 'argument_class_ids', respectively. |
| 245 static bool ICDataHasOnlyReceiverArgumentClassIds( | 236 static bool ICDataHasOnlyReceiverArgumentClassIds( |
| 246 const ICData& ic_data, | 237 const ICData& ic_data, |
| 247 const GrowableArray<intptr_t>& receiver_class_ids, | 238 const GrowableArray<intptr_t>& receiver_class_ids, |
| 248 const GrowableArray<intptr_t>& argument_class_ids) { | 239 const GrowableArray<intptr_t>& argument_class_ids) { |
| 249 if (ic_data.NumArgsTested() != 2) { | 240 if (ic_data.NumArgsTested() != 2) { |
| 250 return false; | 241 return false; |
| 251 } | 242 } |
| 252 const intptr_t len = ic_data.NumberOfChecks(); | 243 const intptr_t len = ic_data.NumberOfChecks(); |
| 253 GrowableArray<intptr_t> class_ids; | 244 GrowableArray<intptr_t> class_ids; |
| 254 for (intptr_t i = 0; i < len; i++) { | 245 for (intptr_t i = 0; i < len; i++) { |
| 255 if (ic_data.IsUsedAt(i)) { | 246 if (ic_data.IsUsedAt(i)) { |
| 256 ic_data.GetClassIdsAt(i, &class_ids); | 247 ic_data.GetClassIdsAt(i, &class_ids); |
| 257 ASSERT(class_ids.length() == 2); | 248 ASSERT(class_ids.length() == 2); |
| 258 if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) || | 249 if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) || |
| 259 !ClassIdIsOneOf(class_ids[1], argument_class_ids)) { | 250 !ClassIdIsOneOf(class_ids[1], argument_class_ids)) { |
| 260 return false; | 251 return false; |
| 261 } | 252 } |
| 262 } | 253 } |
| 263 } | 254 } |
| 264 return true; | 255 return true; |
| 265 } | 256 } |
| 266 | 257 |
| 267 | |
| 268 static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data, | 258 static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data, |
| 269 intptr_t receiver_class_id, | 259 intptr_t receiver_class_id, |
| 270 intptr_t argument_class_id) { | 260 intptr_t argument_class_id) { |
| 271 if (ic_data.NumArgsTested() != 2) { | 261 if (ic_data.NumArgsTested() != 2) { |
| 272 return false; | 262 return false; |
| 273 } | 263 } |
| 274 const intptr_t len = ic_data.NumberOfChecks(); | 264 const intptr_t len = ic_data.NumberOfChecks(); |
| 275 for (intptr_t i = 0; i < len; i++) { | 265 for (intptr_t i = 0; i < len; i++) { |
| 276 if (ic_data.IsUsedAt(i)) { | 266 if (ic_data.IsUsedAt(i)) { |
| 277 GrowableArray<intptr_t> class_ids; | 267 GrowableArray<intptr_t> class_ids; |
| 278 ic_data.GetClassIdsAt(i, &class_ids); | 268 ic_data.GetClassIdsAt(i, &class_ids); |
| 279 ASSERT(class_ids.length() == 2); | 269 ASSERT(class_ids.length() == 2); |
| 280 if ((class_ids[0] == receiver_class_id) && | 270 if ((class_ids[0] == receiver_class_id) && |
| 281 (class_ids[1] == argument_class_id)) { | 271 (class_ids[1] == argument_class_id)) { |
| 282 return true; | 272 return true; |
| 283 } | 273 } |
| 284 } | 274 } |
| 285 } | 275 } |
| 286 return false; | 276 return false; |
| 287 } | 277 } |
| 288 | 278 |
| 289 | |
| 290 static bool HasOnlyOneSmi(const ICData& ic_data) { | 279 static bool HasOnlyOneSmi(const ICData& ic_data) { |
| 291 return (ic_data.NumberOfUsedChecks() == 1) && | 280 return (ic_data.NumberOfUsedChecks() == 1) && |
| 292 ic_data.HasReceiverClassId(kSmiCid); | 281 ic_data.HasReceiverClassId(kSmiCid); |
| 293 } | 282 } |
| 294 | 283 |
| 295 | |
| 296 static bool HasOnlySmiOrMint(const ICData& ic_data) { | 284 static bool HasOnlySmiOrMint(const ICData& ic_data) { |
| 297 if (ic_data.NumberOfUsedChecks() == 1) { | 285 if (ic_data.NumberOfUsedChecks() == 1) { |
| 298 return ic_data.HasReceiverClassId(kSmiCid) || | 286 return ic_data.HasReceiverClassId(kSmiCid) || |
| 299 ic_data.HasReceiverClassId(kMintCid); | 287 ic_data.HasReceiverClassId(kMintCid); |
| 300 } | 288 } |
| 301 return (ic_data.NumberOfUsedChecks() == 2) && | 289 return (ic_data.NumberOfUsedChecks() == 2) && |
| 302 ic_data.HasReceiverClassId(kSmiCid) && | 290 ic_data.HasReceiverClassId(kSmiCid) && |
| 303 ic_data.HasReceiverClassId(kMintCid); | 291 ic_data.HasReceiverClassId(kMintCid); |
| 304 } | 292 } |
| 305 | 293 |
| 306 | |
| 307 static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) { | 294 static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) { |
| 308 if (ic_data.NumberOfUsedChecks() != 1) { | 295 if (ic_data.NumberOfUsedChecks() != 1) { |
| 309 return false; | 296 return false; |
| 310 } | 297 } |
| 311 GrowableArray<intptr_t> first; | 298 GrowableArray<intptr_t> first; |
| 312 GrowableArray<intptr_t> second; | 299 GrowableArray<intptr_t> second; |
| 313 ic_data.GetUsedCidsForTwoArgs(&first, &second); | 300 ic_data.GetUsedCidsForTwoArgs(&first, &second); |
| 314 return (first[0] == cid) && (second[0] == cid); | 301 return (first[0] == cid) && (second[0] == cid); |
| 315 } | 302 } |
| 316 | 303 |
| 317 // Returns false if the ICData contains anything other than the 4 combinations | 304 // Returns false if the ICData contains anything other than the 4 combinations |
| 318 // of Mint and Smi for the receiver and argument classes. | 305 // of Mint and Smi for the receiver and argument classes. |
| 319 static bool HasTwoMintOrSmi(const ICData& ic_data) { | 306 static bool HasTwoMintOrSmi(const ICData& ic_data) { |
| 320 GrowableArray<intptr_t> first; | 307 GrowableArray<intptr_t> first; |
| 321 GrowableArray<intptr_t> second; | 308 GrowableArray<intptr_t> second; |
| 322 ic_data.GetUsedCidsForTwoArgs(&first, &second); | 309 ic_data.GetUsedCidsForTwoArgs(&first, &second); |
| 323 for (intptr_t i = 0; i < first.length(); i++) { | 310 for (intptr_t i = 0; i < first.length(); i++) { |
| 324 if ((first[i] != kSmiCid) && (first[i] != kMintCid)) { | 311 if ((first[i] != kSmiCid) && (first[i] != kMintCid)) { |
| 325 return false; | 312 return false; |
| 326 } | 313 } |
| 327 if ((second[i] != kSmiCid) && (second[i] != kMintCid)) { | 314 if ((second[i] != kSmiCid) && (second[i] != kMintCid)) { |
| 328 return false; | 315 return false; |
| 329 } | 316 } |
| 330 } | 317 } |
| 331 return true; | 318 return true; |
| 332 } | 319 } |
| 333 | 320 |
| 334 | |
| 335 // Returns false if the ICData contains anything other than the 4 combinations | 321 // Returns false if the ICData contains anything other than the 4 combinations |
| 336 // of Double and Smi for the receiver and argument classes. | 322 // of Double and Smi for the receiver and argument classes. |
| 337 static bool HasTwoDoubleOrSmi(const ICData& ic_data) { | 323 static bool HasTwoDoubleOrSmi(const ICData& ic_data) { |
| 338 GrowableArray<intptr_t> class_ids(2); | 324 GrowableArray<intptr_t> class_ids(2); |
| 339 class_ids.Add(kSmiCid); | 325 class_ids.Add(kSmiCid); |
| 340 class_ids.Add(kDoubleCid); | 326 class_ids.Add(kDoubleCid); |
| 341 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); | 327 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); |
| 342 } | 328 } |
| 343 | 329 |
| 344 | |
| 345 static bool HasOnlyOneDouble(const ICData& ic_data) { | 330 static bool HasOnlyOneDouble(const ICData& ic_data) { |
| 346 return (ic_data.NumberOfUsedChecks() == 1) && | 331 return (ic_data.NumberOfUsedChecks() == 1) && |
| 347 ic_data.HasReceiverClassId(kDoubleCid); | 332 ic_data.HasReceiverClassId(kDoubleCid); |
| 348 } | 333 } |
| 349 | 334 |
| 350 | |
| 351 static bool ShouldSpecializeForDouble(const ICData& ic_data) { | 335 static bool ShouldSpecializeForDouble(const ICData& ic_data) { |
| 352 // Don't specialize for double if we can't unbox them. | 336 // Don't specialize for double if we can't unbox them. |
| 353 if (!CanUnboxDouble()) { | 337 if (!CanUnboxDouble()) { |
| 354 return false; | 338 return false; |
| 355 } | 339 } |
| 356 | 340 |
| 357 // Unboxed double operation can't handle case of two smis. | 341 // Unboxed double operation can't handle case of two smis. |
| 358 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | 342 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
| 359 return false; | 343 return false; |
| 360 } | 344 } |
| 361 | 345 |
| 362 // Check that it have seen only smis and doubles. | 346 // Check that it have seen only smis and doubles. |
| 363 return HasTwoDoubleOrSmi(ic_data); | 347 return HasTwoDoubleOrSmi(ic_data); |
| 364 } | 348 } |
| 365 | 349 |
| 366 | |
| 367 void JitOptimizer::ReplaceCall(Definition* call, Definition* replacement) { | 350 void JitOptimizer::ReplaceCall(Definition* call, Definition* replacement) { |
| 368 // Remove the original push arguments. | 351 // Remove the original push arguments. |
| 369 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 352 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 370 PushArgumentInstr* push = call->PushArgumentAt(i); | 353 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 371 push->ReplaceUsesWith(push->value()->definition()); | 354 push->ReplaceUsesWith(push->value()->definition()); |
| 372 push->RemoveFromGraph(); | 355 push->RemoveFromGraph(); |
| 373 } | 356 } |
| 374 call->ReplaceWith(replacement, current_iterator()); | 357 call->ReplaceWith(replacement, current_iterator()); |
| 375 } | 358 } |
| 376 | 359 |
| 377 | |
| 378 void JitOptimizer::AddCheckSmi(Definition* to_check, | 360 void JitOptimizer::AddCheckSmi(Definition* to_check, |
| 379 intptr_t deopt_id, | 361 intptr_t deopt_id, |
| 380 Environment* deopt_environment, | 362 Environment* deopt_environment, |
| 381 Instruction* insert_before) { | 363 Instruction* insert_before) { |
| 382 if (to_check->Type()->ToCid() != kSmiCid) { | 364 if (to_check->Type()->ToCid() != kSmiCid) { |
| 383 InsertBefore(insert_before, | 365 InsertBefore(insert_before, |
| 384 new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id, | 366 new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id, |
| 385 insert_before->token_pos()), | 367 insert_before->token_pos()), |
| 386 deopt_environment, FlowGraph::kEffect); | 368 deopt_environment, FlowGraph::kEffect); |
| 387 } | 369 } |
| 388 } | 370 } |
| 389 | 371 |
| 390 | |
| 391 void JitOptimizer::AddCheckClass(Definition* to_check, | 372 void JitOptimizer::AddCheckClass(Definition* to_check, |
| 392 const Cids& cids, | 373 const Cids& cids, |
| 393 intptr_t deopt_id, | 374 intptr_t deopt_id, |
| 394 Environment* deopt_environment, | 375 Environment* deopt_environment, |
| 395 Instruction* insert_before) { | 376 Instruction* insert_before) { |
| 396 // Type propagation has not run yet, we cannot eliminate the check. | 377 // Type propagation has not run yet, we cannot eliminate the check. |
| 397 Instruction* check = flow_graph_->CreateCheckClass( | 378 Instruction* check = flow_graph_->CreateCheckClass( |
| 398 to_check, cids, deopt_id, insert_before->token_pos()); | 379 to_check, cids, deopt_id, insert_before->token_pos()); |
| 399 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); | 380 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); |
| 400 } | 381 } |
| 401 | 382 |
| 402 | |
| 403 void JitOptimizer::AddChecksForArgNr(InstanceCallInstr* call, | 383 void JitOptimizer::AddChecksForArgNr(InstanceCallInstr* call, |
| 404 Definition* instr, | 384 Definition* instr, |
| 405 int argument_number) { | 385 int argument_number) { |
| 406 const Cids* cids = Cids::Create(Z, *call->ic_data(), argument_number); | 386 const Cids* cids = Cids::Create(Z, *call->ic_data(), argument_number); |
| 407 AddCheckClass(instr, *cids, call->deopt_id(), call->env(), call); | 387 AddCheckClass(instr, *cids, call->deopt_id(), call->env(), call); |
| 408 } | 388 } |
| 409 | 389 |
| 410 | |
| 411 static bool ArgIsAlways(intptr_t cid, | 390 static bool ArgIsAlways(intptr_t cid, |
| 412 const ICData& ic_data, | 391 const ICData& ic_data, |
| 413 intptr_t arg_number) { | 392 intptr_t arg_number) { |
| 414 ASSERT(ic_data.NumArgsTested() > arg_number); | 393 ASSERT(ic_data.NumArgsTested() > arg_number); |
| 415 if (ic_data.NumberOfUsedChecks() == 0) { | 394 if (ic_data.NumberOfUsedChecks() == 0) { |
| 416 return false; | 395 return false; |
| 417 } | 396 } |
| 418 const intptr_t num_checks = ic_data.NumberOfChecks(); | 397 const intptr_t num_checks = ic_data.NumberOfChecks(); |
| 419 for (intptr_t i = 0; i < num_checks; i++) { | 398 for (intptr_t i = 0; i < num_checks; i++) { |
| 420 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { | 399 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { |
| 421 return false; | 400 return false; |
| 422 } | 401 } |
| 423 } | 402 } |
| 424 return true; | 403 return true; |
| 425 } | 404 } |
| 426 | 405 |
| 427 | |
| 428 bool JitOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { | 406 bool JitOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { |
| 429 // Check for monomorphic IC data. | 407 // Check for monomorphic IC data. |
| 430 if (!call->HasICData()) return false; | 408 if (!call->HasICData()) return false; |
| 431 const ICData& ic_data = | 409 const ICData& ic_data = |
| 432 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); | 410 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); |
| 433 if (!ic_data.NumberOfChecksIs(1)) { | 411 if (!ic_data.NumberOfChecksIs(1)) { |
| 434 return false; | 412 return false; |
| 435 } | 413 } |
| 436 return FlowGraphInliner::TryReplaceInstanceCallWithInline( | 414 return FlowGraphInliner::TryReplaceInstanceCallWithInline( |
| 437 flow_graph_, current_iterator(), call); | 415 flow_graph_, current_iterator(), call); |
| 438 } | 416 } |
| 439 | 417 |
| 440 | |
| 441 // Return true if d is a string of length one (a constant or result from | 418 // Return true if d is a string of length one (a constant or result from |
| 442 // from string-from-char-code instruction. | 419 // from string-from-char-code instruction. |
| 443 static bool IsLengthOneString(Definition* d) { | 420 static bool IsLengthOneString(Definition* d) { |
| 444 if (d->IsConstant()) { | 421 if (d->IsConstant()) { |
| 445 const Object& obj = d->AsConstant()->value(); | 422 const Object& obj = d->AsConstant()->value(); |
| 446 if (obj.IsString()) { | 423 if (obj.IsString()) { |
| 447 return String::Cast(obj).Length() == 1; | 424 return String::Cast(obj).Length() == 1; |
| 448 } else { | 425 } else { |
| 449 return false; | 426 return false; |
| 450 } | 427 } |
| 451 } else { | 428 } else { |
| 452 return d->IsOneByteStringFromCharCode(); | 429 return d->IsOneByteStringFromCharCode(); |
| 453 } | 430 } |
| 454 } | 431 } |
| 455 | 432 |
| 456 | |
| 457 // Returns true if the string comparison was converted into char-code | 433 // Returns true if the string comparison was converted into char-code |
| 458 // comparison. Conversion is only possible for strings of length one. | 434 // comparison. Conversion is only possible for strings of length one. |
| 459 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. | 435 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. |
| 460 // TODO(srdjan): Expand for two-byte and external strings. | 436 // TODO(srdjan): Expand for two-byte and external strings. |
| 461 bool JitOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, | 437 bool JitOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, |
| 462 Token::Kind op_kind) { | 438 Token::Kind op_kind) { |
| 463 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); | 439 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); |
| 464 // Check that left and right are length one strings (either string constants | 440 // Check that left and right are length one strings (either string constants |
| 465 // or results of string-from-char-code. | 441 // or results of string-from-char-code. |
| 466 Definition* left = call->ArgumentAt(0); | 442 Definition* left = call->ArgumentAt(0); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 if ((to_remove_right != NULL) && | 503 if ((to_remove_right != NULL) && |
| 528 (to_remove_right->input_use_list() == NULL)) { | 504 (to_remove_right->input_use_list() == NULL)) { |
| 529 to_remove_right->ReplaceUsesWith(flow_graph()->constant_null()); | 505 to_remove_right->ReplaceUsesWith(flow_graph()->constant_null()); |
| 530 to_remove_right->RemoveFromGraph(); | 506 to_remove_right->RemoveFromGraph(); |
| 531 } | 507 } |
| 532 return true; | 508 return true; |
| 533 } | 509 } |
| 534 return false; | 510 return false; |
| 535 } | 511 } |
| 536 | 512 |
| 537 | |
| 538 static bool SmiFitsInDouble() { | 513 static bool SmiFitsInDouble() { |
| 539 return kSmiBits < 53; | 514 return kSmiBits < 53; |
| 540 } | 515 } |
| 541 | 516 |
| 542 bool JitOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, | 517 bool JitOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
| 543 Token::Kind op_kind) { | 518 Token::Kind op_kind) { |
| 544 const ICData& ic_data = *call->ic_data(); | 519 const ICData& ic_data = *call->ic_data(); |
| 545 ASSERT(ic_data.NumArgsTested() == 2); | 520 ASSERT(ic_data.NumArgsTested() == 2); |
| 546 | 521 |
| 547 ASSERT(call->ArgumentCount() == 2); | 522 ASSERT(call->ArgumentCount() == 2); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 571 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { | 546 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { |
| 572 // Use double comparison. | 547 // Use double comparison. |
| 573 if (SmiFitsInDouble()) { | 548 if (SmiFitsInDouble()) { |
| 574 cid = kDoubleCid; | 549 cid = kDoubleCid; |
| 575 } else { | 550 } else { |
| 576 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | 551 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
| 577 // We cannot use double comparison on two smis. Need polymorphic | 552 // We cannot use double comparison on two smis. Need polymorphic |
| 578 // call. | 553 // call. |
| 579 return false; | 554 return false; |
| 580 } else { | 555 } else { |
| 581 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left), | 556 InsertBefore( |
| 582 new (Z) Value(right), | 557 call, |
| 583 call->deopt_id()), | 558 new (Z) CheckEitherNonSmiInstr( |
| 584 call->env(), FlowGraph::kEffect); | 559 new (Z) Value(left), new (Z) Value(right), call->deopt_id()), |
| 560 call->env(), FlowGraph::kEffect); |
| 585 cid = kDoubleCid; | 561 cid = kDoubleCid; |
| 586 } | 562 } |
| 587 } | 563 } |
| 588 } else { | 564 } else { |
| 589 // Check if ICDData contains checks with Smi/Null combinations. In that case | 565 // Check if ICDData contains checks with Smi/Null combinations. In that case |
| 590 // we can still emit the optimized Smi equality operation but need to add | 566 // we can still emit the optimized Smi equality operation but need to add |
| 591 // checks for null or Smi. | 567 // checks for null or Smi. |
| 592 GrowableArray<intptr_t> smi_or_null(2); | 568 GrowableArray<intptr_t> smi_or_null(2); |
| 593 smi_or_null.Add(kSmiCid); | 569 smi_or_null.Add(kSmiCid); |
| 594 smi_or_null.Add(kNullCid); | 570 smi_or_null.Add(kNullCid); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 614 } | 590 } |
| 615 } | 591 } |
| 616 ASSERT(cid != kIllegalCid); | 592 ASSERT(cid != kIllegalCid); |
| 617 EqualityCompareInstr* comp = new (Z) | 593 EqualityCompareInstr* comp = new (Z) |
| 618 EqualityCompareInstr(call->token_pos(), op_kind, new (Z) Value(left), | 594 EqualityCompareInstr(call->token_pos(), op_kind, new (Z) Value(left), |
| 619 new (Z) Value(right), cid, call->deopt_id()); | 595 new (Z) Value(right), cid, call->deopt_id()); |
| 620 ReplaceCall(call, comp); | 596 ReplaceCall(call, comp); |
| 621 return true; | 597 return true; |
| 622 } | 598 } |
| 623 | 599 |
| 624 | |
| 625 bool JitOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, | 600 bool JitOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, |
| 626 Token::Kind op_kind) { | 601 Token::Kind op_kind) { |
| 627 const ICData& ic_data = *call->ic_data(); | 602 const ICData& ic_data = *call->ic_data(); |
| 628 ASSERT(ic_data.NumArgsTested() == 2); | 603 ASSERT(ic_data.NumArgsTested() == 2); |
| 629 | 604 |
| 630 ASSERT(call->ArgumentCount() == 2); | 605 ASSERT(call->ArgumentCount() == 2); |
| 631 Definition* left = call->ArgumentAt(0); | 606 Definition* left = call->ArgumentAt(0); |
| 632 Definition* right = call->ArgumentAt(1); | 607 Definition* right = call->ArgumentAt(1); |
| 633 | 608 |
| 634 intptr_t cid = kIllegalCid; | 609 intptr_t cid = kIllegalCid; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 648 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { | 623 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { |
| 649 // Use double comparison. | 624 // Use double comparison. |
| 650 if (SmiFitsInDouble()) { | 625 if (SmiFitsInDouble()) { |
| 651 cid = kDoubleCid; | 626 cid = kDoubleCid; |
| 652 } else { | 627 } else { |
| 653 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | 628 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
| 654 // We cannot use double comparison on two smis. Need polymorphic | 629 // We cannot use double comparison on two smis. Need polymorphic |
| 655 // call. | 630 // call. |
| 656 return false; | 631 return false; |
| 657 } else { | 632 } else { |
| 658 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left), | 633 InsertBefore( |
| 659 new (Z) Value(right), | 634 call, |
| 660 call->deopt_id()), | 635 new (Z) CheckEitherNonSmiInstr( |
| 661 call->env(), FlowGraph::kEffect); | 636 new (Z) Value(left), new (Z) Value(right), call->deopt_id()), |
| 637 call->env(), FlowGraph::kEffect); |
| 662 cid = kDoubleCid; | 638 cid = kDoubleCid; |
| 663 } | 639 } |
| 664 } | 640 } |
| 665 } else { | 641 } else { |
| 666 return false; | 642 return false; |
| 667 } | 643 } |
| 668 ASSERT(cid != kIllegalCid); | 644 ASSERT(cid != kIllegalCid); |
| 669 RelationalOpInstr* comp = | 645 RelationalOpInstr* comp = |
| 670 new (Z) RelationalOpInstr(call->token_pos(), op_kind, new (Z) Value(left), | 646 new (Z) RelationalOpInstr(call->token_pos(), op_kind, new (Z) Value(left), |
| 671 new (Z) Value(right), cid, call->deopt_id()); | 647 new (Z) Value(right), cid, call->deopt_id()); |
| 672 ReplaceCall(call, comp); | 648 ReplaceCall(call, comp); |
| 673 return true; | 649 return true; |
| 674 } | 650 } |
| 675 | 651 |
| 676 | |
| 677 bool JitOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, | 652 bool JitOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, |
| 678 Token::Kind op_kind) { | 653 Token::Kind op_kind) { |
| 679 intptr_t operands_type = kIllegalCid; | 654 intptr_t operands_type = kIllegalCid; |
| 680 ASSERT(call->HasICData()); | 655 ASSERT(call->HasICData()); |
| 681 const ICData& ic_data = *call->ic_data(); | 656 const ICData& ic_data = *call->ic_data(); |
| 682 switch (op_kind) { | 657 switch (op_kind) { |
| 683 case Token::kADD: | 658 case Token::kADD: |
| 684 case Token::kSUB: | 659 case Token::kSUB: |
| 685 case Token::kMUL: | 660 case Token::kMUL: |
| 686 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 661 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 780 Definition* left = call->ArgumentAt(0); | 755 Definition* left = call->ArgumentAt(0); |
| 781 Definition* right = call->ArgumentAt(1); | 756 Definition* right = call->ArgumentAt(1); |
| 782 if (operands_type == kDoubleCid) { | 757 if (operands_type == kDoubleCid) { |
| 783 if (!CanUnboxDouble()) { | 758 if (!CanUnboxDouble()) { |
| 784 return false; | 759 return false; |
| 785 } | 760 } |
| 786 // Check that either left or right are not a smi. Result of a | 761 // Check that either left or right are not a smi. Result of a |
| 787 // binary operation with two smis is a smi not a double, except '/' which | 762 // binary operation with two smis is a smi not a double, except '/' which |
| 788 // returns a double for two smis. | 763 // returns a double for two smis. |
| 789 if (op_kind != Token::kDIV) { | 764 if (op_kind != Token::kDIV) { |
| 790 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left), | 765 InsertBefore( |
| 791 new (Z) Value(right), | 766 call, |
| 792 call->deopt_id()), | 767 new (Z) CheckEitherNonSmiInstr( |
| 793 call->env(), FlowGraph::kEffect); | 768 new (Z) Value(left), new (Z) Value(right), call->deopt_id()), |
| 769 call->env(), FlowGraph::kEffect); |
| 794 } | 770 } |
| 795 | 771 |
| 796 BinaryDoubleOpInstr* double_bin_op = new (Z) | 772 BinaryDoubleOpInstr* double_bin_op = new (Z) |
| 797 BinaryDoubleOpInstr(op_kind, new (Z) Value(left), new (Z) Value(right), | 773 BinaryDoubleOpInstr(op_kind, new (Z) Value(left), new (Z) Value(right), |
| 798 call->deopt_id(), call->token_pos()); | 774 call->deopt_id(), call->token_pos()); |
| 799 ReplaceCall(call, double_bin_op); | 775 ReplaceCall(call, double_bin_op); |
| 800 } else if (operands_type == kMintCid) { | 776 } else if (operands_type == kMintCid) { |
| 801 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false; | 777 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false; |
| 802 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { | 778 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { |
| 803 ShiftMintOpInstr* shift_op = new (Z) ShiftMintOpInstr( | 779 ShiftMintOpInstr* shift_op = new (Z) ShiftMintOpInstr( |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 854 left = right; | 830 left = right; |
| 855 right = temp; | 831 right = temp; |
| 856 } | 832 } |
| 857 BinarySmiOpInstr* bin_op = new (Z) BinarySmiOpInstr( | 833 BinarySmiOpInstr* bin_op = new (Z) BinarySmiOpInstr( |
| 858 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 834 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
| 859 ReplaceCall(call, bin_op); | 835 ReplaceCall(call, bin_op); |
| 860 } | 836 } |
| 861 return true; | 837 return true; |
| 862 } | 838 } |
| 863 | 839 |
| 864 | |
| 865 bool JitOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, | 840 bool JitOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, |
| 866 Token::Kind op_kind) { | 841 Token::Kind op_kind) { |
| 867 ASSERT(call->ArgumentCount() == 1); | 842 ASSERT(call->ArgumentCount() == 1); |
| 868 Definition* input = call->ArgumentAt(0); | 843 Definition* input = call->ArgumentAt(0); |
| 869 Definition* unary_op = NULL; | 844 Definition* unary_op = NULL; |
| 870 if (HasOnlyOneSmi(*call->ic_data())) { | 845 if (HasOnlyOneSmi(*call->ic_data())) { |
| 871 InsertBefore(call, | 846 InsertBefore(call, |
| 872 new (Z) CheckSmiInstr(new (Z) Value(input), call->deopt_id(), | 847 new (Z) CheckSmiInstr(new (Z) Value(input), call->deopt_id(), |
| 873 call->token_pos()), | 848 call->token_pos()), |
| 874 call->env(), FlowGraph::kEffect); | 849 call->env(), FlowGraph::kEffect); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 885 unary_op = new (Z) UnaryDoubleOpInstr(Token::kNEGATE, new (Z) Value(input), | 860 unary_op = new (Z) UnaryDoubleOpInstr(Token::kNEGATE, new (Z) Value(input), |
| 886 call->deopt_id()); | 861 call->deopt_id()); |
| 887 } else { | 862 } else { |
| 888 return false; | 863 return false; |
| 889 } | 864 } |
| 890 ASSERT(unary_op != NULL); | 865 ASSERT(unary_op != NULL); |
| 891 ReplaceCall(call, unary_op); | 866 ReplaceCall(call, unary_op); |
| 892 return true; | 867 return true; |
| 893 } | 868 } |
| 894 | 869 |
| 895 | |
| 896 // Using field class. | 870 // Using field class. |
| 897 RawField* JitOptimizer::GetField(intptr_t class_id, const String& field_name) { | 871 RawField* JitOptimizer::GetField(intptr_t class_id, const String& field_name) { |
| 898 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); | 872 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); |
| 899 Field& field = Field::Handle(Z); | 873 Field& field = Field::Handle(Z); |
| 900 while (!cls.IsNull()) { | 874 while (!cls.IsNull()) { |
| 901 field = cls.LookupInstanceField(field_name); | 875 field = cls.LookupInstanceField(field_name); |
| 902 if (!field.IsNull()) { | 876 if (!field.IsNull()) { |
| 903 if (Compiler::IsBackgroundCompilation() || | 877 if (Compiler::IsBackgroundCompilation() || |
| 904 FLAG_force_clone_compiler_objects) { | 878 FLAG_force_clone_compiler_objects) { |
| 905 return field.CloneFromOriginal(); | 879 return field.CloneFromOriginal(); |
| 906 } else { | 880 } else { |
| 907 return field.raw(); | 881 return field.raw(); |
| 908 } | 882 } |
| 909 } | 883 } |
| 910 cls = cls.SuperClass(); | 884 cls = cls.SuperClass(); |
| 911 } | 885 } |
| 912 return Field::null(); | 886 return Field::null(); |
| 913 } | 887 } |
| 914 | 888 |
| 915 | |
| 916 bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { | 889 bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { |
| 917 ASSERT(call->HasICData()); | 890 ASSERT(call->HasICData()); |
| 918 const ICData& ic_data = *call->ic_data(); | 891 const ICData& ic_data = *call->ic_data(); |
| 919 ASSERT(ic_data.HasOneTarget()); | 892 ASSERT(ic_data.HasOneTarget()); |
| 920 GrowableArray<intptr_t> class_ids; | 893 GrowableArray<intptr_t> class_ids; |
| 921 ic_data.GetClassIdsAt(0, &class_ids); | 894 ic_data.GetClassIdsAt(0, &class_ids); |
| 922 ASSERT(class_ids.length() == 1); | 895 ASSERT(class_ids.length() == 1); |
| 923 // Inline implicit instance getter. | 896 // Inline implicit instance getter. |
| 924 const String& field_name = | 897 const String& field_name = |
| 925 String::Handle(Z, Field::NameFromGetter(call->function_name())); | 898 String::Handle(Z, Field::NameFromGetter(call->function_name())); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 943 | 916 |
| 944 if (load->result_cid() != kDynamicCid) { | 917 if (load->result_cid() != kDynamicCid) { |
| 945 // Reset value types if guarded_cid was used. | 918 // Reset value types if guarded_cid was used. |
| 946 for (Value::Iterator it(load->input_use_list()); !it.Done(); it.Advance()) { | 919 for (Value::Iterator it(load->input_use_list()); !it.Done(); it.Advance()) { |
| 947 it.Current()->SetReachingType(NULL); | 920 it.Current()->SetReachingType(NULL); |
| 948 } | 921 } |
| 949 } | 922 } |
| 950 return true; | 923 return true; |
| 951 } | 924 } |
| 952 | 925 |
| 953 | |
| 954 bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, | 926 bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, |
| 955 Token::Kind op_kind) { | 927 Token::Kind op_kind) { |
| 956 if (!ShouldInlineSimd()) { | 928 if (!ShouldInlineSimd()) { |
| 957 return false; | 929 return false; |
| 958 } | 930 } |
| 959 ASSERT(call->ArgumentCount() == 2); | 931 ASSERT(call->ArgumentCount() == 2); |
| 960 Definition* left = call->ArgumentAt(0); | 932 Definition* left = call->ArgumentAt(0); |
| 961 Definition* right = call->ArgumentAt(1); | 933 Definition* right = call->ArgumentAt(1); |
| 962 // Type check left and right. | 934 // Type check left and right. |
| 963 AddChecksForArgNr(call, left, 0); | 935 AddChecksForArgNr(call, left, 0); |
| 964 AddChecksForArgNr(call, right, 1); | 936 AddChecksForArgNr(call, right, 1); |
| 965 // Replace call. | 937 // Replace call. |
| 966 BinaryFloat32x4OpInstr* float32x4_bin_op = new (Z) BinaryFloat32x4OpInstr( | 938 BinaryFloat32x4OpInstr* float32x4_bin_op = new (Z) BinaryFloat32x4OpInstr( |
| 967 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 939 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
| 968 ReplaceCall(call, float32x4_bin_op); | 940 ReplaceCall(call, float32x4_bin_op); |
| 969 | 941 |
| 970 return true; | 942 return true; |
| 971 } | 943 } |
| 972 | 944 |
| 973 | |
| 974 bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, | 945 bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, |
| 975 Token::Kind op_kind) { | 946 Token::Kind op_kind) { |
| 976 if (!ShouldInlineSimd()) { | 947 if (!ShouldInlineSimd()) { |
| 977 return false; | 948 return false; |
| 978 } | 949 } |
| 979 ASSERT(call->ArgumentCount() == 2); | 950 ASSERT(call->ArgumentCount() == 2); |
| 980 Definition* left = call->ArgumentAt(0); | 951 Definition* left = call->ArgumentAt(0); |
| 981 Definition* right = call->ArgumentAt(1); | 952 Definition* right = call->ArgumentAt(1); |
| 982 // Type check left and right. | 953 // Type check left and right. |
| 983 AddChecksForArgNr(call, left, 0); | 954 AddChecksForArgNr(call, left, 0); |
| 984 AddChecksForArgNr(call, right, 1); | 955 AddChecksForArgNr(call, right, 1); |
| 985 // Replace call. | 956 // Replace call. |
| 986 BinaryInt32x4OpInstr* int32x4_bin_op = new (Z) BinaryInt32x4OpInstr( | 957 BinaryInt32x4OpInstr* int32x4_bin_op = new (Z) BinaryInt32x4OpInstr( |
| 987 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 958 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
| 988 ReplaceCall(call, int32x4_bin_op); | 959 ReplaceCall(call, int32x4_bin_op); |
| 989 return true; | 960 return true; |
| 990 } | 961 } |
| 991 | 962 |
| 992 | |
| 993 bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, | 963 bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, |
| 994 Token::Kind op_kind) { | 964 Token::Kind op_kind) { |
| 995 if (!ShouldInlineSimd()) { | 965 if (!ShouldInlineSimd()) { |
| 996 return false; | 966 return false; |
| 997 } | 967 } |
| 998 ASSERT(call->ArgumentCount() == 2); | 968 ASSERT(call->ArgumentCount() == 2); |
| 999 Definition* left = call->ArgumentAt(0); | 969 Definition* left = call->ArgumentAt(0); |
| 1000 Definition* right = call->ArgumentAt(1); | 970 Definition* right = call->ArgumentAt(1); |
| 1001 // Type check left and right. | 971 // Type check left and right. |
| 1002 AddChecksForArgNr(call, left, 0); | 972 AddChecksForArgNr(call, left, 0); |
| 1003 AddChecksForArgNr(call, right, 1); | 973 AddChecksForArgNr(call, right, 1); |
| 1004 // Replace call. | 974 // Replace call. |
| 1005 BinaryFloat64x2OpInstr* float64x2_bin_op = new (Z) BinaryFloat64x2OpInstr( | 975 BinaryFloat64x2OpInstr* float64x2_bin_op = new (Z) BinaryFloat64x2OpInstr( |
| 1006 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 976 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
| 1007 ReplaceCall(call, float64x2_bin_op); | 977 ReplaceCall(call, float64x2_bin_op); |
| 1008 return true; | 978 return true; |
| 1009 } | 979 } |
| 1010 | 980 |
| 1011 | |
| 1012 // Only unique implicit instance getters can be currently handled. | 981 // Only unique implicit instance getters can be currently handled. |
| 1013 bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { | 982 bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { |
| 1014 ASSERT(call->HasICData()); | 983 ASSERT(call->HasICData()); |
| 1015 const ICData& ic_data = *call->ic_data(); | 984 const ICData& ic_data = *call->ic_data(); |
| 1016 if (ic_data.NumberOfUsedChecks() == 0) { | 985 if (ic_data.NumberOfUsedChecks() == 0) { |
| 1017 // No type feedback collected. | 986 // No type feedback collected. |
| 1018 return false; | 987 return false; |
| 1019 } | 988 } |
| 1020 | 989 |
| 1021 if (!ic_data.HasOneTarget()) { | 990 if (!ic_data.HasOneTarget()) { |
| 1022 // Polymorphic sites are inlined like normal methods by conventional | 991 // Polymorphic sites are inlined like normal methods by conventional |
| 1023 // inlining in FlowGraphInliner. | 992 // inlining in FlowGraphInliner. |
| 1024 return false; | 993 return false; |
| 1025 } | 994 } |
| 1026 | 995 |
| 1027 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); | 996 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); |
| 1028 if (target.kind() != RawFunction::kImplicitGetter) { | 997 if (target.kind() != RawFunction::kImplicitGetter) { |
| 1029 // Non-implicit getters are inlined like normal methods by conventional | 998 // Non-implicit getters are inlined like normal methods by conventional |
| 1030 // inlining in FlowGraphInliner. | 999 // inlining in FlowGraphInliner. |
| 1031 return false; | 1000 return false; |
| 1032 } | 1001 } |
| 1033 return InlineImplicitInstanceGetter(call); | 1002 return InlineImplicitInstanceGetter(call); |
| 1034 } | 1003 } |
| 1035 | 1004 |
| 1036 | |
| 1037 void JitOptimizer::ReplaceWithMathCFunction( | 1005 void JitOptimizer::ReplaceWithMathCFunction( |
| 1038 InstanceCallInstr* call, | 1006 InstanceCallInstr* call, |
| 1039 MethodRecognizer::Kind recognized_kind) { | 1007 MethodRecognizer::Kind recognized_kind) { |
| 1040 AddReceiverCheck(call); | 1008 AddReceiverCheck(call); |
| 1041 ZoneGrowableArray<Value*>* args = | 1009 ZoneGrowableArray<Value*>* args = |
| 1042 new (Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | 1010 new (Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); |
| 1043 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 1011 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
| 1044 args->Add(new (Z) Value(call->ArgumentAt(i))); | 1012 args->Add(new (Z) Value(call->ArgumentAt(i))); |
| 1045 } | 1013 } |
| 1046 InvokeMathCFunctionInstr* invoke = new (Z) InvokeMathCFunctionInstr( | 1014 InvokeMathCFunctionInstr* invoke = new (Z) InvokeMathCFunctionInstr( |
| 1047 args, call->deopt_id(), recognized_kind, call->token_pos()); | 1015 args, call->deopt_id(), recognized_kind, call->token_pos()); |
| 1048 ReplaceCall(call, invoke); | 1016 ReplaceCall(call, invoke); |
| 1049 } | 1017 } |
| 1050 | 1018 |
| 1051 | |
| 1052 // Inline only simple, frequently called core library methods. | 1019 // Inline only simple, frequently called core library methods. |
| 1053 bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { | 1020 bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { |
| 1054 ASSERT(call->HasICData()); | 1021 ASSERT(call->HasICData()); |
| 1055 const ICData& ic_data = *call->ic_data(); | 1022 const ICData& ic_data = *call->ic_data(); |
| 1056 if (ic_data.NumberOfUsedChecks() != 1) { | 1023 if (ic_data.NumberOfUsedChecks() != 1) { |
| 1057 // No type feedback collected or multiple targets found. | 1024 // No type feedback collected or multiple targets found. |
| 1058 return false; | 1025 return false; |
| 1059 } | 1026 } |
| 1060 | 1027 |
| 1061 Function& target = Function::Handle(Z); | 1028 Function& target = Function::Handle(Z); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1122 return true; | 1089 return true; |
| 1123 default: | 1090 default: |
| 1124 break; | 1091 break; |
| 1125 } | 1092 } |
| 1126 } | 1093 } |
| 1127 | 1094 |
| 1128 return FlowGraphInliner::TryReplaceInstanceCallWithInline( | 1095 return FlowGraphInliner::TryReplaceInstanceCallWithInline( |
| 1129 flow_graph_, current_iterator(), call); | 1096 flow_graph_, current_iterator(), call); |
| 1130 } | 1097 } |
| 1131 | 1098 |
| 1132 | |
| 1133 // If type tests specified by 'ic_data' do not depend on type arguments, | 1099 // If type tests specified by 'ic_data' do not depend on type arguments, |
| 1134 // return mapping cid->result in 'results' (i : cid; i + 1: result). | 1100 // return mapping cid->result in 'results' (i : cid; i + 1: result). |
| 1135 // If all tests yield the same result, return it otherwise return Bool::null. | 1101 // If all tests yield the same result, return it otherwise return Bool::null. |
| 1136 // If no mapping is possible, 'results' is empty. | 1102 // If no mapping is possible, 'results' is empty. |
| 1137 // An instance-of test returning all same results can be converted to a class | 1103 // An instance-of test returning all same results can be converted to a class |
| 1138 // check. | 1104 // check. |
| 1139 RawBool* JitOptimizer::InstanceOfAsBool( | 1105 RawBool* JitOptimizer::InstanceOfAsBool( |
| 1140 const ICData& ic_data, | 1106 const ICData& ic_data, |
| 1141 const AbstractType& type, | 1107 const AbstractType& type, |
| 1142 ZoneGrowableArray<intptr_t>* results) const { | 1108 ZoneGrowableArray<intptr_t>* results) const { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1190 prev = Bool::Get(is_subtype).raw(); | 1156 prev = Bool::Get(is_subtype).raw(); |
| 1191 } else { | 1157 } else { |
| 1192 if (is_subtype != prev.value()) { | 1158 if (is_subtype != prev.value()) { |
| 1193 results_differ = true; | 1159 results_differ = true; |
| 1194 } | 1160 } |
| 1195 } | 1161 } |
| 1196 } | 1162 } |
| 1197 return results_differ ? Bool::null() : prev.raw(); | 1163 return results_differ ? Bool::null() : prev.raw(); |
| 1198 } | 1164 } |
| 1199 | 1165 |
| 1200 | |
| 1201 // Returns true if checking against this type is a direct class id comparison. | 1166 // Returns true if checking against this type is a direct class id comparison. |
| 1202 bool JitOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { | 1167 bool JitOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { |
| 1203 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); | 1168 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); |
| 1204 // Requires CHA. | 1169 // Requires CHA. |
| 1205 if (!type.IsInstantiated()) return false; | 1170 if (!type.IsInstantiated()) return false; |
| 1206 // Function types have different type checking rules. | 1171 // Function types have different type checking rules. |
| 1207 if (type.IsFunctionType()) return false; | 1172 if (type.IsFunctionType()) return false; |
| 1208 const Class& type_class = Class::Handle(type.type_class()); | 1173 const Class& type_class = Class::Handle(type.type_class()); |
| 1209 // Could be an interface check? | 1174 // Could be an interface check? |
| 1210 if (CHA::IsImplemented(type_class)) return false; | 1175 if (CHA::IsImplemented(type_class)) return false; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1237 const intptr_t from_index = num_type_args - num_type_params; | 1202 const intptr_t from_index = num_type_args - num_type_params; |
| 1238 const TypeArguments& type_arguments = | 1203 const TypeArguments& type_arguments = |
| 1239 TypeArguments::Handle(type.arguments()); | 1204 TypeArguments::Handle(type.arguments()); |
| 1240 const bool is_raw_type = type_arguments.IsNull() || | 1205 const bool is_raw_type = type_arguments.IsNull() || |
| 1241 type_arguments.IsRaw(from_index, num_type_params); | 1206 type_arguments.IsRaw(from_index, num_type_params); |
| 1242 return is_raw_type; | 1207 return is_raw_type; |
| 1243 } | 1208 } |
| 1244 return true; | 1209 return true; |
| 1245 } | 1210 } |
| 1246 | 1211 |
| 1247 | |
| 1248 // TODO(srdjan): Use ICData to check if always true or false. | 1212 // TODO(srdjan): Use ICData to check if always true or false. |
| 1249 void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 1213 void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
| 1250 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 1214 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
| 1251 Definition* left = call->ArgumentAt(0); | 1215 Definition* left = call->ArgumentAt(0); |
| 1252 Definition* instantiator_type_args = NULL; | 1216 Definition* instantiator_type_args = NULL; |
| 1253 Definition* function_type_args = NULL; | 1217 Definition* function_type_args = NULL; |
| 1254 AbstractType& type = AbstractType::ZoneHandle(Z); | 1218 AbstractType& type = AbstractType::ZoneHandle(Z); |
| 1255 if (call->ArgumentCount() == 2) { | 1219 if (call->ArgumentCount() == 2) { |
| 1256 instantiator_type_args = flow_graph()->constant_null(); | 1220 instantiator_type_args = flow_graph()->constant_null(); |
| 1257 function_type_args = flow_graph()->constant_null(); | 1221 function_type_args = flow_graph()->constant_null(); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1314 } | 1278 } |
| 1315 } | 1279 } |
| 1316 | 1280 |
| 1317 InstanceOfInstr* instance_of = new (Z) InstanceOfInstr( | 1281 InstanceOfInstr* instance_of = new (Z) InstanceOfInstr( |
| 1318 call->token_pos(), new (Z) Value(left), | 1282 call->token_pos(), new (Z) Value(left), |
| 1319 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args), | 1283 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args), |
| 1320 type, call->deopt_id()); | 1284 type, call->deopt_id()); |
| 1321 ReplaceCall(call, instance_of); | 1285 ReplaceCall(call, instance_of); |
| 1322 } | 1286 } |
| 1323 | 1287 |
| 1324 | |
| 1325 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). | 1288 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). |
| 1326 void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { | 1289 void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { |
| 1327 ASSERT(Token::IsTypeCastOperator(call->token_kind())); | 1290 ASSERT(Token::IsTypeCastOperator(call->token_kind())); |
| 1328 Definition* left = call->ArgumentAt(0); | 1291 Definition* left = call->ArgumentAt(0); |
| 1329 Definition* instantiator_type_args = call->ArgumentAt(1); | 1292 Definition* instantiator_type_args = call->ArgumentAt(1); |
| 1330 Definition* function_type_args = call->ArgumentAt(2); | 1293 Definition* function_type_args = call->ArgumentAt(2); |
| 1331 const AbstractType& type = | 1294 const AbstractType& type = |
| 1332 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); | 1295 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); |
| 1333 ASSERT(!type.IsMalformedOrMalbounded()); | 1296 ASSERT(!type.IsMalformedOrMalbounded()); |
| 1334 const ICData& unary_checks = | 1297 const ICData& unary_checks = |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1355 return; | 1318 return; |
| 1356 } | 1319 } |
| 1357 } | 1320 } |
| 1358 AssertAssignableInstr* assert_as = new (Z) AssertAssignableInstr( | 1321 AssertAssignableInstr* assert_as = new (Z) AssertAssignableInstr( |
| 1359 call->token_pos(), new (Z) Value(left), | 1322 call->token_pos(), new (Z) Value(left), |
| 1360 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args), | 1323 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args), |
| 1361 type, Symbols::InTypeCast(), call->deopt_id()); | 1324 type, Symbols::InTypeCast(), call->deopt_id()); |
| 1362 ReplaceCall(call, assert_as); | 1325 ReplaceCall(call, assert_as); |
| 1363 } | 1326 } |
| 1364 | 1327 |
| 1365 | |
| 1366 // Tries to optimize instance call by replacing it with a faster instruction | 1328 // Tries to optimize instance call by replacing it with a faster instruction |
| 1367 // (e.g, binary op, field load, ..). | 1329 // (e.g, binary op, field load, ..). |
| 1368 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 1330 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
| 1369 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { | 1331 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { |
| 1370 return; | 1332 return; |
| 1371 } | 1333 } |
| 1372 const Token::Kind op_kind = instr->token_kind(); | 1334 const Token::Kind op_kind = instr->token_kind(); |
| 1373 | 1335 |
| 1374 // Type test is special as it always gets converted into inlined code. | 1336 // Type test is special as it always gets converted into inlined code. |
| 1375 if (Token::IsTypeTestOperator(op_kind)) { | 1337 if (Token::IsTypeTestOperator(op_kind)) { |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1472 StaticCallInstr* call = StaticCallInstr::FromCall(Z, instr, target); | 1434 StaticCallInstr* call = StaticCallInstr::FromCall(Z, instr, target); |
| 1473 instr->ReplaceWith(call, current_iterator()); | 1435 instr->ReplaceWith(call, current_iterator()); |
| 1474 } else { | 1436 } else { |
| 1475 PolymorphicInstanceCallInstr* call = | 1437 PolymorphicInstanceCallInstr* call = |
| 1476 new (Z) PolymorphicInstanceCallInstr(instr, targets, | 1438 new (Z) PolymorphicInstanceCallInstr(instr, targets, |
| 1477 /* complete = */ false); | 1439 /* complete = */ false); |
| 1478 instr->ReplaceWith(call, current_iterator()); | 1440 instr->ReplaceWith(call, current_iterator()); |
| 1479 } | 1441 } |
| 1480 } | 1442 } |
| 1481 | 1443 |
| 1482 | |
| 1483 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { | 1444 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { |
| 1484 MethodRecognizer::Kind recognized_kind = | 1445 MethodRecognizer::Kind recognized_kind = |
| 1485 MethodRecognizer::RecognizeKind(call->function()); | 1446 MethodRecognizer::RecognizeKind(call->function()); |
| 1486 switch (recognized_kind) { | 1447 switch (recognized_kind) { |
| 1487 case MethodRecognizer::kObjectConstructor: | 1448 case MethodRecognizer::kObjectConstructor: |
| 1488 case MethodRecognizer::kObjectArrayAllocate: | 1449 case MethodRecognizer::kObjectArrayAllocate: |
| 1489 case MethodRecognizer::kFloat32x4Zero: | 1450 case MethodRecognizer::kFloat32x4Zero: |
| 1490 case MethodRecognizer::kFloat32x4Splat: | 1451 case MethodRecognizer::kFloat32x4Splat: |
| 1491 case MethodRecognizer::kFloat32x4Constructor: | 1452 case MethodRecognizer::kFloat32x4Constructor: |
| 1492 case MethodRecognizer::kFloat32x4FromFloat64x2: | 1453 case MethodRecognizer::kFloat32x4FromFloat64x2: |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1555 } | 1516 } |
| 1556 } | 1517 } |
| 1557 } | 1518 } |
| 1558 break; | 1519 break; |
| 1559 } | 1520 } |
| 1560 default: | 1521 default: |
| 1561 break; | 1522 break; |
| 1562 } | 1523 } |
| 1563 } | 1524 } |
| 1564 | 1525 |
| 1565 | |
| 1566 void JitOptimizer::VisitStoreInstanceField(StoreInstanceFieldInstr* instr) { | 1526 void JitOptimizer::VisitStoreInstanceField(StoreInstanceFieldInstr* instr) { |
| 1567 if (instr->IsUnboxedStore()) { | 1527 if (instr->IsUnboxedStore()) { |
| 1568 // Determine if this field should be unboxed based on the usage of getter | 1528 // Determine if this field should be unboxed based on the usage of getter |
| 1569 // and setter functions: The heuristic requires that the setter has a | 1529 // and setter functions: The heuristic requires that the setter has a |
| 1570 // usage count of at least 1/kGetterSetterRatio of the getter usage count. | 1530 // usage count of at least 1/kGetterSetterRatio of the getter usage count. |
| 1571 // This is to avoid unboxing fields where the setter is never or rarely | 1531 // This is to avoid unboxing fields where the setter is never or rarely |
| 1572 // executed. | 1532 // executed. |
| 1573 const Field& field = instr->field(); | 1533 const Field& field = instr->field(); |
| 1574 const String& field_name = String::Handle(Z, field.name()); | 1534 const String& field_name = String::Handle(Z, field.name()); |
| 1575 const Class& owner = Class::Handle(Z, field.Owner()); | 1535 const Class& owner = Class::Handle(Z, field.Owner()); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1609 } | 1569 } |
| 1610 ASSERT(field.IsOriginal()); | 1570 ASSERT(field.IsOriginal()); |
| 1611 field.set_is_unboxing_candidate(false); | 1571 field.set_is_unboxing_candidate(false); |
| 1612 field.DeoptimizeDependentCode(); | 1572 field.DeoptimizeDependentCode(); |
| 1613 } else { | 1573 } else { |
| 1614 flow_graph()->parsed_function().AddToGuardedFields(&field); | 1574 flow_graph()->parsed_function().AddToGuardedFields(&field); |
| 1615 } | 1575 } |
| 1616 } | 1576 } |
| 1617 } | 1577 } |
| 1618 | 1578 |
| 1619 | |
| 1620 void JitOptimizer::VisitAllocateContext(AllocateContextInstr* instr) { | 1579 void JitOptimizer::VisitAllocateContext(AllocateContextInstr* instr) { |
| 1621 // Replace generic allocation with a sequence of inlined allocation and | 1580 // Replace generic allocation with a sequence of inlined allocation and |
| 1622 // explicit initializing stores. | 1581 // explicit initializing stores. |
| 1623 AllocateUninitializedContextInstr* replacement = | 1582 AllocateUninitializedContextInstr* replacement = |
| 1624 new AllocateUninitializedContextInstr(instr->token_pos(), | 1583 new AllocateUninitializedContextInstr(instr->token_pos(), |
| 1625 instr->num_context_variables()); | 1584 instr->num_context_variables()); |
| 1626 instr->ReplaceWith(replacement, current_iterator()); | 1585 instr->ReplaceWith(replacement, current_iterator()); |
| 1627 | 1586 |
| 1628 StoreInstanceFieldInstr* store = new (Z) | 1587 StoreInstanceFieldInstr* store = new (Z) |
| 1629 StoreInstanceFieldInstr(Context::parent_offset(), new Value(replacement), | 1588 StoreInstanceFieldInstr(Context::parent_offset(), new Value(replacement), |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1640 new Value(flow_graph_->constant_null()), kNoStoreBarrier, | 1599 new Value(flow_graph_->constant_null()), kNoStoreBarrier, |
| 1641 instr->token_pos()); | 1600 instr->token_pos()); |
| 1642 // Storing into uninitialized memory; remember to prevent dead store | 1601 // Storing into uninitialized memory; remember to prevent dead store |
| 1643 // elimination and ensure proper GC barrier. | 1602 // elimination and ensure proper GC barrier. |
| 1644 store->set_is_initialization(true); | 1603 store->set_is_initialization(true); |
| 1645 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect); | 1604 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect); |
| 1646 cursor = store; | 1605 cursor = store; |
| 1647 } | 1606 } |
| 1648 } | 1607 } |
| 1649 | 1608 |
| 1650 | |
| 1651 void JitOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { | 1609 void JitOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { |
| 1652 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. | 1610 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. |
| 1653 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) | 1611 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) |
| 1654 if (!instr->can_pack_into_smi()) instr->set_representation(kUnboxedMint); | 1612 if (!instr->can_pack_into_smi()) instr->set_representation(kUnboxedMint); |
| 1655 #endif | 1613 #endif |
| 1656 } | 1614 } |
| 1657 | 1615 |
| 1658 | |
| 1659 bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, | 1616 bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, |
| 1660 const ICData& unary_ic_data) { | 1617 const ICData& unary_ic_data) { |
| 1661 ASSERT(!unary_ic_data.NumberOfChecksIs(0) && | 1618 ASSERT(!unary_ic_data.NumberOfChecksIs(0) && |
| 1662 (unary_ic_data.NumArgsTested() == 1)); | 1619 (unary_ic_data.NumArgsTested() == 1)); |
| 1663 if (I->type_checks()) { | 1620 if (I->type_checks()) { |
| 1664 // Checked mode setters are inlined like normal methods by conventional | 1621 // Checked mode setters are inlined like normal methods by conventional |
| 1665 // inlining. | 1622 // inlining. |
| 1666 return false; | 1623 return false; |
| 1667 } | 1624 } |
| 1668 | 1625 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1688 String::Handle(Z, Field::NameFromSetter(instr->function_name())); | 1645 String::Handle(Z, Field::NameFromSetter(instr->function_name())); |
| 1689 const Field& field = Field::ZoneHandle(Z, GetField(class_id, field_name)); | 1646 const Field& field = Field::ZoneHandle(Z, GetField(class_id, field_name)); |
| 1690 ASSERT(!field.IsNull()); | 1647 ASSERT(!field.IsNull()); |
| 1691 | 1648 |
| 1692 if (flow_graph()->InstanceCallNeedsClassCheck(instr, | 1649 if (flow_graph()->InstanceCallNeedsClassCheck(instr, |
| 1693 RawFunction::kImplicitSetter)) { | 1650 RawFunction::kImplicitSetter)) { |
| 1694 AddReceiverCheck(instr); | 1651 AddReceiverCheck(instr); |
| 1695 } | 1652 } |
| 1696 if (field.guarded_cid() != kDynamicCid) { | 1653 if (field.guarded_cid() != kDynamicCid) { |
| 1697 ASSERT(I->use_field_guards()); | 1654 ASSERT(I->use_field_guards()); |
| 1698 InsertBefore( | 1655 InsertBefore(instr, |
| 1699 instr, new (Z) GuardFieldClassInstr(new (Z) Value(instr->ArgumentAt(1)), | 1656 new (Z) |
| 1700 field, instr->deopt_id()), | 1657 GuardFieldClassInstr(new (Z) Value(instr->ArgumentAt(1)), |
| 1701 instr->env(), FlowGraph::kEffect); | 1658 field, instr->deopt_id()), |
| 1659 instr->env(), FlowGraph::kEffect); |
| 1702 } | 1660 } |
| 1703 | 1661 |
| 1704 if (field.needs_length_check()) { | 1662 if (field.needs_length_check()) { |
| 1705 ASSERT(I->use_field_guards()); | 1663 ASSERT(I->use_field_guards()); |
| 1706 InsertBefore(instr, new (Z) GuardFieldLengthInstr( | 1664 InsertBefore(instr, |
| 1707 new (Z) Value(instr->ArgumentAt(1)), field, | 1665 new (Z) |
| 1708 instr->deopt_id()), | 1666 GuardFieldLengthInstr(new (Z) Value(instr->ArgumentAt(1)), |
| 1667 field, instr->deopt_id()), |
| 1709 instr->env(), FlowGraph::kEffect); | 1668 instr->env(), FlowGraph::kEffect); |
| 1710 } | 1669 } |
| 1711 | 1670 |
| 1712 // Field guard was detached. | 1671 // Field guard was detached. |
| 1713 StoreInstanceFieldInstr* store = new (Z) | 1672 StoreInstanceFieldInstr* store = new (Z) |
| 1714 StoreInstanceFieldInstr(field, new (Z) Value(instr->ArgumentAt(0)), | 1673 StoreInstanceFieldInstr(field, new (Z) Value(instr->ArgumentAt(0)), |
| 1715 new (Z) Value(instr->ArgumentAt(1)), | 1674 new (Z) Value(instr->ArgumentAt(1)), |
| 1716 kEmitStoreBarrier, instr->token_pos()); | 1675 kEmitStoreBarrier, instr->token_pos()); |
| 1717 | 1676 |
| 1718 if (store->IsUnboxedStore()) { | 1677 if (store->IsUnboxedStore()) { |
| 1719 flow_graph()->parsed_function().AddToGuardedFields(&field); | 1678 flow_graph()->parsed_function().AddToGuardedFields(&field); |
| 1720 } | 1679 } |
| 1721 | 1680 |
| 1722 // Discard the environment from the original instruction because the store | 1681 // Discard the environment from the original instruction because the store |
| 1723 // can't deoptimize. | 1682 // can't deoptimize. |
| 1724 instr->RemoveEnvironment(); | 1683 instr->RemoveEnvironment(); |
| 1725 ReplaceCall(instr, store); | 1684 ReplaceCall(instr, store); |
| 1726 return true; | 1685 return true; |
| 1727 } | 1686 } |
| 1728 | 1687 |
| 1729 | |
| 1730 } // namespace dart | 1688 } // namespace dart |
| 1731 #endif // DART_PRECOMPILED_RUNTIME | 1689 #endif // DART_PRECOMPILED_RUNTIME |
| OLD | NEW |