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

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

Issue 2974233002: VM: Re-format to use at most one newline between functions (Closed)
Patch Set: Rebase and merge Created 3 years, 5 months 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
« no previous file with comments | « runtime/vm/jit_optimizer.h ('k') | runtime/vm/json_parser.h » ('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) 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/jit_optimizer.h ('k') | runtime/vm/json_parser.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698