Chromium Code Reviews| 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 | 4 |
| 5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
| 10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
| (...skipping 766 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 777 call->deopt_id() : Isolate::kNoDeoptId; | 777 call->deopt_id() : Isolate::kNoDeoptId; |
| 778 } | 778 } |
| 779 break; | 779 break; |
| 780 default: | 780 default: |
| 781 return false; | 781 return false; |
| 782 } | 782 } |
| 783 Value* array = NULL; | 783 Value* array = NULL; |
| 784 Value* index = NULL; | 784 Value* index = NULL; |
| 785 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); | 785 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); |
| 786 Definition* array_op = | 786 Definition* array_op = |
| 787 new LoadIndexedInstr(array, index, array_cid, deopt_id); | 787 new LoadIndexedInstr(array, |
| 788 index, | |
| 789 FlowGraphCompiler::ElementSizeFor(array_cid), | |
| 790 array_cid, | |
| 791 deopt_id); | |
| 788 call->ReplaceWith(array_op, current_iterator()); | 792 call->ReplaceWith(array_op, current_iterator()); |
| 789 RemovePushArguments(call); | 793 RemovePushArguments(call); |
| 790 return true; | 794 return true; |
| 791 } | 795 } |
| 792 | 796 |
| 793 | 797 |
| 794 void FlowGraphOptimizer::InsertBefore(Instruction* next, | 798 void FlowGraphOptimizer::InsertBefore(Instruction* next, |
| 795 Instruction* instr, | 799 Instruction* instr, |
| 796 Environment* env, | 800 Environment* env, |
| 797 Definition::UseKind use_kind) { | 801 Definition::UseKind use_kind) { |
| (...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1322 length->set_recognized_kind(MethodRecognizer::kStringBaseLength); | 1326 length->set_recognized_kind(MethodRecognizer::kStringBaseLength); |
| 1323 InsertBefore(call, length, NULL, Definition::kValue); | 1327 InsertBefore(call, length, NULL, Definition::kValue); |
| 1324 InsertBefore(call, | 1328 InsertBefore(call, |
| 1325 new CheckArrayBoundInstr(new Value(length), | 1329 new CheckArrayBoundInstr(new Value(length), |
| 1326 index->Copy(), | 1330 index->Copy(), |
| 1327 cid, | 1331 cid, |
| 1328 call), | 1332 call), |
| 1329 call->env(), | 1333 call->env(), |
| 1330 Definition::kEffect); | 1334 Definition::kEffect); |
| 1331 } | 1335 } |
| 1332 return new LoadIndexedInstr(str, index, cid, Isolate::kNoDeoptId); | 1336 return new LoadIndexedInstr(str, |
| 1337 index, | |
| 1338 FlowGraphCompiler::ElementSizeFor(cid), | |
| 1339 cid, | |
| 1340 Isolate::kNoDeoptId); // Can't deoptimize. | |
| 1333 } | 1341 } |
| 1334 | 1342 |
| 1335 | 1343 |
| 1336 void FlowGraphOptimizer::ReplaceWithMathCFunction( | 1344 void FlowGraphOptimizer::ReplaceWithMathCFunction( |
| 1337 InstanceCallInstr* call, | 1345 InstanceCallInstr* call, |
| 1338 MethodRecognizer::Kind recognized_kind) { | 1346 MethodRecognizer::Kind recognized_kind) { |
| 1339 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | 1347 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); |
| 1340 ZoneGrowableArray<Value*>* args = | 1348 ZoneGrowableArray<Value*>* args = |
| 1341 new ZoneGrowableArray<Value*>(call->ArgumentCount()); | 1349 new ZoneGrowableArray<Value*>(call->ArgumentCount()); |
| 1342 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 1350 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
| 1343 args->Add(call->ArgumentAt(i)->value()); | 1351 args->Add(call->ArgumentAt(i)->value()); |
| 1344 } | 1352 } |
| 1345 InvokeMathCFunctionInstr* invoke = | 1353 InvokeMathCFunctionInstr* invoke = |
| 1346 new InvokeMathCFunctionInstr(args, call, recognized_kind); | 1354 new InvokeMathCFunctionInstr(args, call, recognized_kind); |
| 1347 call->ReplaceWith(invoke, current_iterator()); | 1355 call->ReplaceWith(invoke, current_iterator()); |
| 1348 RemovePushArguments(call); | 1356 RemovePushArguments(call); |
| 1349 } | 1357 } |
| 1350 | 1358 |
| 1351 | 1359 |
| 1360 static bool IsSupportedByteArrayCid(intptr_t cid) { | |
| 1361 switch (cid) { | |
| 1362 case kInt8ArrayCid: | |
| 1363 case kUint8ArrayCid: | |
| 1364 case kUint8ClampedArrayCid: | |
| 1365 case kInt16ArrayCid: | |
| 1366 case kUint16ArrayCid: | |
| 1367 case kInt32ArrayCid: | |
| 1368 case kUint32ArrayCid: | |
| 1369 case kFloat32ArrayCid: | |
| 1370 case kFloat64ArrayCid: | |
|
srdjan
2013/02/06 17:11:16
They may be ordered, i.e., you could check for ran
Florian Schneider
2013/02/14 12:20:51
How can I make sure that they are ordered? It woul
srdjan
2013/02/14 16:36:35
They are ordered but not as we need it, see RawObj
| |
| 1371 return true; | |
| 1372 default: | |
| 1373 return false; | |
| 1374 } | |
| 1375 } | |
| 1376 | |
| 1377 | |
| 1352 // Inline only simple, frequently called core library methods. | 1378 // Inline only simple, frequently called core library methods. |
| 1353 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { | 1379 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { |
| 1354 ASSERT(call->HasICData()); | 1380 ASSERT(call->HasICData()); |
| 1355 const ICData& ic_data = *call->ic_data(); | 1381 const ICData& ic_data = *call->ic_data(); |
| 1356 if ((ic_data.NumberOfChecks() == 0) || !ic_data.HasOneTarget()) { | 1382 if ((ic_data.NumberOfChecks() == 0) || !ic_data.HasOneTarget()) { |
| 1357 // No type feedback collected or multiple targets found. | 1383 // No type feedback collected or multiple targets found. |
| 1358 return false; | 1384 return false; |
| 1359 } | 1385 } |
| 1360 Function& target = Function::Handle(); | 1386 Function& target = Function::Handle(); |
| 1361 GrowableArray<intptr_t> class_ids; | 1387 GrowableArray<intptr_t> class_ids; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1433 call->ReplaceWith(d2d_instr, current_iterator()); | 1459 call->ReplaceWith(d2d_instr, current_iterator()); |
| 1434 RemovePushArguments(call); | 1460 RemovePushArguments(call); |
| 1435 } | 1461 } |
| 1436 return true; | 1462 return true; |
| 1437 default: | 1463 default: |
| 1438 // Unsupported method. | 1464 // Unsupported method. |
| 1439 return false; | 1465 return false; |
| 1440 } | 1466 } |
| 1441 } | 1467 } |
| 1442 | 1468 |
| 1469 if (IsSupportedByteArrayCid(class_ids[0]) && ic_data.NumberOfChecks() == 1) { | |
|
srdjan
2013/02/06 17:11:16
Add Parenthesis
Florian Schneider
2013/02/14 12:20:51
Done.
| |
| 1470 Definition* array_op = NULL; | |
| 1471 switch (recognized_kind) { | |
| 1472 case MethodRecognizer::kByteArrayBaseGetInt8: | |
| 1473 array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt8ArrayCid); | |
| 1474 break; | |
| 1475 case MethodRecognizer::kByteArrayBaseGetUint8: | |
| 1476 array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint8ArrayCid); | |
| 1477 break; | |
| 1478 case MethodRecognizer::kByteArrayBaseGetInt16: | |
| 1479 array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt16ArrayCid); | |
| 1480 break; | |
| 1481 case MethodRecognizer::kByteArrayBaseGetUint16: | |
| 1482 array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint16ArrayCid); | |
| 1483 break; | |
| 1484 case MethodRecognizer::kByteArrayBaseGetInt32: | |
| 1485 array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt32ArrayCid); | |
| 1486 break; | |
| 1487 case MethodRecognizer::kByteArrayBaseGetUint32: | |
| 1488 array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint32ArrayCid); | |
| 1489 break; | |
| 1490 case MethodRecognizer::kByteArrayBaseGetFloat32: | |
| 1491 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat32ArrayCid); | |
| 1492 break; | |
| 1493 case MethodRecognizer::kByteArrayBaseGetFloat64: | |
| 1494 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat64ArrayCid); | |
| 1495 break; | |
| 1496 default: | |
| 1497 // Unsupported method. | |
| 1498 return false; | |
| 1499 } | |
| 1500 ASSERT(array_op != NULL); | |
| 1501 call->ReplaceWith(array_op, current_iterator()); | |
| 1502 RemovePushArguments(call); | |
| 1503 return true; | |
| 1504 } | |
| 1443 return false; | 1505 return false; |
| 1444 } | 1506 } |
| 1445 | 1507 |
| 1446 | 1508 |
| 1509 LoadIndexedInstr* FlowGraphOptimizer::BuildByteArrayViewLoad( | |
| 1510 InstanceCallInstr* call, | |
| 1511 intptr_t receiver_cid, | |
| 1512 intptr_t view_cid) { | |
| 1513 Value* array = call->ArgumentAt(0)->value(); | |
| 1514 Value* byte_index = call->ArgumentAt(1)->value(); | |
| 1515 | |
| 1516 AddCheckClass(call, array->Copy()); | |
| 1517 const bool is_immutable = true; | |
| 1518 LoadFieldInstr* length = new LoadFieldInstr( | |
| 1519 array->Copy(), | |
| 1520 CheckArrayBoundInstr::LengthOffsetFor(receiver_cid), | |
| 1521 Type::ZoneHandle(Type::SmiType()), | |
| 1522 is_immutable); | |
| 1523 length->set_result_cid(kSmiCid); | |
| 1524 length->set_recognized_kind( | |
| 1525 LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid)); | |
| 1526 InsertBefore(call, length, NULL, Definition::kValue); | |
| 1527 | |
| 1528 // len_in_bytes = length * kBytesPerElement(receiver) | |
| 1529 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid); | |
| 1530 ConstantInstr* bytes_per_element = | |
| 1531 new ConstantInstr(Smi::Handle(Smi::New(element_size))); | |
| 1532 InsertBefore(call, bytes_per_element, NULL, Definition::kValue); | |
| 1533 BinarySmiOpInstr* len_in_bytes = | |
| 1534 new BinarySmiOpInstr(Token::kMUL, | |
| 1535 call, | |
| 1536 new Value(length), | |
| 1537 new Value(bytes_per_element)); | |
| 1538 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue); | |
| 1539 | |
| 1540 // Check byte_index < len_in_bytes. | |
| 1541 InsertBefore(call, | |
| 1542 new CheckArrayBoundInstr(new Value(len_in_bytes), | |
| 1543 byte_index->Copy(), | |
| 1544 receiver_cid, | |
| 1545 call), | |
| 1546 call->env(), | |
| 1547 Definition::kEffect); | |
| 1548 | |
| 1549 // TODO(fschneider): Optimistically build smi load for Int32 and Uint32 | |
| 1550 // loads on ia32 like we do for normal array loads, and only revert to | |
| 1551 // mint case after deoptimizing here. | |
| 1552 return new LoadIndexedInstr(array, | |
| 1553 byte_index, | |
| 1554 1, // Index scale. | |
| 1555 view_cid, | |
| 1556 Isolate::kNoDeoptId); // Can't deoptimize. | |
| 1557 } | |
| 1558 | |
| 1559 | |
| 1447 // Returns a Boolean constant if all classes in ic_data yield the same type-test | 1560 // Returns a Boolean constant if all classes in ic_data yield the same type-test |
| 1448 // result and the type tests do not depend on type arguments. Otherwise return | 1561 // result and the type tests do not depend on type arguments. Otherwise return |
| 1449 // Bool::null(). | 1562 // Bool::null(). |
| 1450 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, | 1563 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, |
| 1451 const AbstractType& type) const { | 1564 const AbstractType& type) const { |
| 1452 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. | 1565 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. |
| 1453 if (!type.IsInstantiated() || type.IsMalformed()) return Bool::null(); | 1566 if (!type.IsInstantiated() || type.IsMalformed()) return Bool::null(); |
| 1454 const Class& type_class = Class::Handle(type.type_class()); | 1567 const Class& type_class = Class::Handle(type.type_class()); |
| 1455 if (type_class.HasTypeArguments()) return Bool::null(); | 1568 if (type_class.HasTypeArguments()) return Bool::null(); |
| 1456 const ClassTable& class_table = *Isolate::Current()->class_table(); | 1569 const ClassTable& class_table = *Isolate::Current()->class_table(); |
| (...skipping 3104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4561 | 4674 |
| 4562 if (FLAG_trace_constant_propagation) { | 4675 if (FLAG_trace_constant_propagation) { |
| 4563 OS::Print("\n==== After constant propagation ====\n"); | 4676 OS::Print("\n==== After constant propagation ====\n"); |
| 4564 FlowGraphPrinter printer(*graph_); | 4677 FlowGraphPrinter printer(*graph_); |
| 4565 printer.PrintBlocks(); | 4678 printer.PrintBlocks(); |
| 4566 } | 4679 } |
| 4567 } | 4680 } |
| 4568 | 4681 |
| 4569 | 4682 |
| 4570 } // namespace dart | 4683 } // namespace dart |
| OLD | NEW |