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/dart_entry.h" | 9 #include "vm/dart_entry.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 811 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 822 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { | 822 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { |
| 823 // Check for monomorphic IC data. | 823 // Check for monomorphic IC data. |
| 824 if (!call->HasICData()) return false; | 824 if (!call->HasICData()) return false; |
| 825 const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks()); | 825 const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks()); |
| 826 if (ic_data.NumberOfChecks() != 1) return false; | 826 if (ic_data.NumberOfChecks() != 1) return false; |
| 827 ASSERT(ic_data.HasOneTarget()); | 827 ASSERT(ic_data.HasOneTarget()); |
| 828 | 828 |
| 829 const Function& target = Function::Handle(ic_data.GetTargetAt(0)); | 829 const Function& target = Function::Handle(ic_data.GetTargetAt(0)); |
| 830 TargetEntryInstr* entry; | 830 TargetEntryInstr* entry; |
| 831 Definition* last; | 831 Definition* last; |
| 832 if (!TryInlineRecognizedMethod(target, | 832 if (!TryInlineRecognizedMethod(ic_data.GetReceiverClassIdAt(0), |
| 833 target, | |
| 833 call, | 834 call, |
| 834 call->token_pos(), | 835 call->token_pos(), |
| 835 *call->ic_data(), | 836 *call->ic_data(), |
| 836 &entry, &last)) { | 837 &entry, &last)) { |
| 837 return false; | 838 return false; |
| 838 } | 839 } |
| 839 // Insert receiver class check. | 840 // Insert receiver class check. |
| 840 AddReceiverCheck(call); | 841 AddReceiverCheck(call); |
| 841 // Remove the original push arguments. | 842 // Remove the original push arguments. |
| 842 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 843 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 988 array_cid, | 989 array_cid, |
| 989 call->deopt_id()); | 990 call->deopt_id()); |
| 990 flow_graph()->AppendTo(cursor, | 991 flow_graph()->AppendTo(cursor, |
| 991 *last, | 992 *last, |
| 992 call->env(), | 993 call->env(), |
| 993 Definition::kEffect); | 994 Definition::kEffect); |
| 994 return true; | 995 return true; |
| 995 } | 996 } |
| 996 | 997 |
| 997 | 998 |
| 998 bool FlowGraphOptimizer::TryInlineRecognizedMethod(const Function& target, | 999 bool FlowGraphOptimizer::TryInlineRecognizedMethod(intptr_t receiver_cid, |
| 1000 const Function& target, | |
| 999 Instruction* call, | 1001 Instruction* call, |
| 1000 intptr_t token_pos, | 1002 intptr_t token_pos, |
| 1001 const ICData& ic_data, | 1003 const ICData& ic_data, |
| 1002 TargetEntryInstr** entry, | 1004 TargetEntryInstr** entry, |
| 1003 Definition** last) { | 1005 Definition** last) { |
| 1004 ICData& value_check = ICData::ZoneHandle(); | 1006 ICData& value_check = ICData::ZoneHandle(); |
| 1005 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target); | 1007 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target); |
| 1006 switch (kind) { | 1008 switch (kind) { |
| 1007 // Recognized [] operators. | 1009 // Recognized [] operators. |
| 1008 case MethodRecognizer::kImmutableArrayGetIndexed: | 1010 case MethodRecognizer::kImmutableArrayGetIndexed: |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1067 value_check = ic_data.AsUnaryClassChecksForArgNr(2); | 1069 value_check = ic_data.AsUnaryClassChecksForArgNr(2); |
| 1068 return InlineSetIndexed(kind, target, call, token_pos, | 1070 return InlineSetIndexed(kind, target, call, token_pos, |
| 1069 &ic_data, value_check, entry, last); | 1071 &ic_data, value_check, entry, last); |
| 1070 case MethodRecognizer::kFloat32x4ArraySetIndexed: | 1072 case MethodRecognizer::kFloat32x4ArraySetIndexed: |
| 1071 if (!ShouldInlineSimd()) return false; | 1073 if (!ShouldInlineSimd()) return false; |
| 1072 // Check that value is always a Float32x4. | 1074 // Check that value is always a Float32x4. |
| 1073 if (!ArgIsAlways(kFloat32x4Cid, ic_data, 2)) return false; | 1075 if (!ArgIsAlways(kFloat32x4Cid, ic_data, 2)) return false; |
| 1074 value_check = ic_data.AsUnaryClassChecksForArgNr(2); | 1076 value_check = ic_data.AsUnaryClassChecksForArgNr(2); |
| 1075 return InlineSetIndexed(kind, target, call, token_pos, | 1077 return InlineSetIndexed(kind, target, call, token_pos, |
| 1076 &ic_data, value_check, entry, last); | 1078 &ic_data, value_check, entry, last); |
| 1079 case MethodRecognizer::kByteArrayBaseGetInt8: | |
|
Cutch
2013/10/22 03:46:16
We now support polymorphic inlining loads on byte
| |
| 1080 return InlineByteArrayViewLoad(call, receiver_cid, | |
| 1081 kTypedDataInt8ArrayCid, | |
| 1082 ic_data, entry, last); | |
| 1083 case MethodRecognizer::kByteArrayBaseGetUint8: | |
| 1084 return InlineByteArrayViewLoad(call, receiver_cid, | |
| 1085 kTypedDataUint8ArrayCid, | |
| 1086 ic_data, entry, last); | |
| 1087 case MethodRecognizer::kByteArrayBaseGetInt16: | |
| 1088 return InlineByteArrayViewLoad(call, receiver_cid, | |
| 1089 kTypedDataInt16ArrayCid, | |
| 1090 ic_data, entry, last); | |
| 1091 case MethodRecognizer::kByteArrayBaseGetUint16: | |
| 1092 return InlineByteArrayViewLoad(call, receiver_cid, | |
| 1093 kTypedDataUint16ArrayCid, | |
| 1094 ic_data, entry, last); | |
| 1095 case MethodRecognizer::kByteArrayBaseGetInt32: | |
| 1096 if (!CanUnboxInt32()) return false; | |
| 1097 return InlineByteArrayViewLoad(call, receiver_cid, | |
| 1098 kTypedDataInt32ArrayCid, | |
| 1099 ic_data, entry, last); | |
| 1100 case MethodRecognizer::kByteArrayBaseGetUint32: | |
| 1101 if (!CanUnboxInt32()) return false; | |
| 1102 return InlineByteArrayViewLoad(call, receiver_cid, | |
| 1103 kTypedDataUint32ArrayCid, | |
| 1104 ic_data, entry, last); | |
| 1105 case MethodRecognizer::kByteArrayBaseGetFloat32: | |
| 1106 return InlineByteArrayViewLoad(call, receiver_cid, | |
| 1107 kTypedDataFloat32ArrayCid, | |
| 1108 ic_data, entry, last); | |
| 1109 case MethodRecognizer::kByteArrayBaseGetFloat64: | |
| 1110 return InlineByteArrayViewLoad(call, receiver_cid, | |
| 1111 kTypedDataFloat64ArrayCid, | |
| 1112 ic_data, entry, last); | |
| 1113 case MethodRecognizer::kByteArrayBaseGetFloat32x4: | |
|
Florian Schneider
2013/10/22 15:57:33
Do you need to check for ShouldInlineSimd() here?
Cutch
2013/10/23 09:19:52
Done.
| |
| 1114 return InlineByteArrayViewLoad(call, receiver_cid, | |
| 1115 kTypedDataFloat32x4ArrayCid, | |
| 1116 ic_data, entry, last); | |
| 1077 default: | 1117 default: |
| 1078 return false; | 1118 return false; |
| 1079 } | 1119 } |
| 1080 } | 1120 } |
| 1081 | 1121 |
| 1082 | 1122 |
| 1083 intptr_t FlowGraphOptimizer::PrepareInlineIndexedOp(Instruction* call, | 1123 intptr_t FlowGraphOptimizer::PrepareInlineIndexedOp(Instruction* call, |
| 1084 intptr_t array_cid, | 1124 intptr_t array_cid, |
| 1085 Definition** array, | 1125 Definition** array, |
| 1086 Definition* index, | 1126 Definition* index, |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1191 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { | 1231 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { |
| 1192 // Check for monomorphic IC data. | 1232 // Check for monomorphic IC data. |
| 1193 if (!call->HasICData()) return false; | 1233 if (!call->HasICData()) return false; |
| 1194 const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks()); | 1234 const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks()); |
| 1195 if (ic_data.NumberOfChecks() != 1) return false; | 1235 if (ic_data.NumberOfChecks() != 1) return false; |
| 1196 ASSERT(ic_data.HasOneTarget()); | 1236 ASSERT(ic_data.HasOneTarget()); |
| 1197 | 1237 |
| 1198 const Function& target = Function::Handle(ic_data.GetTargetAt(0)); | 1238 const Function& target = Function::Handle(ic_data.GetTargetAt(0)); |
| 1199 TargetEntryInstr* entry; | 1239 TargetEntryInstr* entry; |
| 1200 Definition* last; | 1240 Definition* last; |
| 1201 if (!TryInlineRecognizedMethod(target, | 1241 if (!TryInlineRecognizedMethod(ic_data.GetReceiverClassIdAt(0), |
| 1242 target, | |
| 1202 call, | 1243 call, |
| 1203 call->token_pos(), | 1244 call->token_pos(), |
| 1204 *call->ic_data(), | 1245 *call->ic_data(), |
| 1205 &entry, &last)) { | 1246 &entry, &last)) { |
| 1206 return false; | 1247 return false; |
| 1207 } | 1248 } |
| 1208 | 1249 |
| 1209 // Insert receiver class check. | 1250 // Insert receiver class check. |
| 1210 AddReceiverCheck(call); | 1251 AddReceiverCheck(call); |
| 1211 // Remove the original push arguments. | 1252 // Remove the original push arguments. |
| (...skipping 807 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2019 if ((recognized_kind == MethodRecognizer::kByteArrayBaseGetInt32) || | 2060 if ((recognized_kind == MethodRecognizer::kByteArrayBaseGetInt32) || |
| 2020 (recognized_kind == MethodRecognizer::kByteArrayBaseGetUint32) || | 2061 (recognized_kind == MethodRecognizer::kByteArrayBaseGetUint32) || |
| 2021 (recognized_kind == MethodRecognizer::kByteArrayBaseSetInt32) || | 2062 (recognized_kind == MethodRecognizer::kByteArrayBaseSetInt32) || |
| 2022 (recognized_kind == MethodRecognizer::kByteArrayBaseSetUint32)) { | 2063 (recognized_kind == MethodRecognizer::kByteArrayBaseSetUint32)) { |
| 2023 if (!CanUnboxInt32()) return false; | 2064 if (!CanUnboxInt32()) return false; |
| 2024 } | 2065 } |
| 2025 | 2066 |
| 2026 switch (recognized_kind) { | 2067 switch (recognized_kind) { |
| 2027 // ByteArray getters. | 2068 // ByteArray getters. |
| 2028 case MethodRecognizer::kByteArrayBaseGetInt8: | 2069 case MethodRecognizer::kByteArrayBaseGetInt8: |
| 2029 return BuildByteArrayViewLoad( | 2070 return BuildByteArrayViewLoad(call, kTypedDataInt8ArrayCid); |
| 2030 call, class_ids[0], kTypedDataInt8ArrayCid); | |
| 2031 case MethodRecognizer::kByteArrayBaseGetUint8: | 2071 case MethodRecognizer::kByteArrayBaseGetUint8: |
| 2032 return BuildByteArrayViewLoad( | 2072 return BuildByteArrayViewLoad(call, kTypedDataUint8ArrayCid); |
|
Cutch
2013/10/22 03:46:16
Cleanup so that signatures of BuildByteArrayViewLo
| |
| 2033 call, class_ids[0], kTypedDataUint8ArrayCid); | |
| 2034 case MethodRecognizer::kByteArrayBaseGetInt16: | 2073 case MethodRecognizer::kByteArrayBaseGetInt16: |
| 2035 return BuildByteArrayViewLoad( | 2074 return BuildByteArrayViewLoad(call, kTypedDataInt16ArrayCid); |
| 2036 call, class_ids[0], kTypedDataInt16ArrayCid); | |
| 2037 case MethodRecognizer::kByteArrayBaseGetUint16: | 2075 case MethodRecognizer::kByteArrayBaseGetUint16: |
| 2038 return BuildByteArrayViewLoad( | 2076 return BuildByteArrayViewLoad(call, kTypedDataUint16ArrayCid); |
| 2039 call, class_ids[0], kTypedDataUint16ArrayCid); | |
| 2040 case MethodRecognizer::kByteArrayBaseGetInt32: | 2077 case MethodRecognizer::kByteArrayBaseGetInt32: |
| 2041 return BuildByteArrayViewLoad( | 2078 return BuildByteArrayViewLoad(call, kTypedDataInt32ArrayCid); |
| 2042 call, class_ids[0], kTypedDataInt32ArrayCid); | |
| 2043 case MethodRecognizer::kByteArrayBaseGetUint32: | 2079 case MethodRecognizer::kByteArrayBaseGetUint32: |
| 2044 return BuildByteArrayViewLoad( | 2080 return BuildByteArrayViewLoad(call, kTypedDataUint32ArrayCid); |
| 2045 call, class_ids[0], kTypedDataUint32ArrayCid); | |
| 2046 case MethodRecognizer::kByteArrayBaseGetFloat32: | 2081 case MethodRecognizer::kByteArrayBaseGetFloat32: |
| 2047 return BuildByteArrayViewLoad( | 2082 return BuildByteArrayViewLoad(call, kTypedDataFloat32ArrayCid); |
| 2048 call, class_ids[0], kTypedDataFloat32ArrayCid); | |
| 2049 case MethodRecognizer::kByteArrayBaseGetFloat64: | 2083 case MethodRecognizer::kByteArrayBaseGetFloat64: |
| 2050 return BuildByteArrayViewLoad( | 2084 return BuildByteArrayViewLoad(call, kTypedDataFloat64ArrayCid); |
| 2051 call, class_ids[0], kTypedDataFloat64ArrayCid); | |
| 2052 case MethodRecognizer::kByteArrayBaseGetFloat32x4: | 2085 case MethodRecognizer::kByteArrayBaseGetFloat32x4: |
| 2053 return BuildByteArrayViewLoad( | 2086 return BuildByteArrayViewLoad(call, kTypedDataFloat32x4ArrayCid); |
| 2054 call, class_ids[0], kTypedDataFloat32x4ArrayCid); | |
| 2055 | 2087 |
| 2056 // ByteArray setters. | 2088 // ByteArray setters. |
| 2057 case MethodRecognizer::kByteArrayBaseSetInt8: | 2089 case MethodRecognizer::kByteArrayBaseSetInt8: |
| 2058 return BuildByteArrayViewStore(call, kTypedDataInt8ArrayCid); | 2090 return BuildByteArrayViewStore(call, kTypedDataInt8ArrayCid); |
| 2059 case MethodRecognizer::kByteArrayBaseSetUint8: | 2091 case MethodRecognizer::kByteArrayBaseSetUint8: |
| 2060 return BuildByteArrayViewStore(call, kTypedDataUint8ArrayCid); | 2092 return BuildByteArrayViewStore(call, kTypedDataUint8ArrayCid); |
| 2061 case MethodRecognizer::kByteArrayBaseSetInt16: | 2093 case MethodRecognizer::kByteArrayBaseSetInt16: |
| 2062 return BuildByteArrayViewStore(call, kTypedDataInt16ArrayCid); | 2094 return BuildByteArrayViewStore(call, kTypedDataInt16ArrayCid); |
| 2063 case MethodRecognizer::kByteArrayBaseSetUint16: | 2095 case MethodRecognizer::kByteArrayBaseSetUint16: |
| 2064 return BuildByteArrayViewStore(call, kTypedDataUint16ArrayCid); | 2096 return BuildByteArrayViewStore(call, kTypedDataUint16ArrayCid); |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2442 call->deopt_id()); | 2474 call->deopt_id()); |
| 2443 ReplaceCall(call, setFlag); | 2475 ReplaceCall(call, setFlag); |
| 2444 return true; | 2476 return true; |
| 2445 } | 2477 } |
| 2446 default: | 2478 default: |
| 2447 return false; | 2479 return false; |
| 2448 } | 2480 } |
| 2449 } | 2481 } |
| 2450 | 2482 |
| 2451 | 2483 |
| 2452 bool FlowGraphOptimizer::BuildByteArrayViewLoad( | 2484 bool FlowGraphOptimizer::InlineByteArrayViewLoad(Instruction* call, |
| 2453 InstanceCallInstr* call, | 2485 intptr_t array_cid, |
| 2454 intptr_t receiver_cid, | 2486 intptr_t view_cid, |
| 2455 intptr_t view_cid) { | 2487 const ICData& ic_data, |
| 2488 TargetEntryInstr** entry, | |
| 2489 Definition** last) { | |
| 2490 ASSERT(array_cid != kIllegalCid); | |
| 2491 Definition* array = call->ArgumentAt(0); | |
| 2492 Definition* index = call->ArgumentAt(1); | |
| 2493 *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(), | |
| 2494 call->GetBlock()->try_index()); | |
| 2495 (*entry)->InheritDeoptTarget(call); | |
| 2496 Instruction* cursor = *entry; | |
| 2497 | |
| 2498 array_cid = PrepareInlineByteArrayViewOp(call, | |
| 2499 array_cid, | |
| 2500 view_cid, | |
| 2501 &array, | |
| 2502 index, | |
| 2503 &cursor); | |
| 2504 | |
| 2505 intptr_t deopt_id = Isolate::kNoDeoptId; | |
| 2506 if ((array_cid == kTypedDataInt32ArrayCid) || | |
| 2507 (array_cid == kTypedDataUint32ArrayCid)) { | |
| 2508 // Set deopt_id if we can optimistically assume that the result is Smi. | |
| 2509 // Assume mixed Mint/Smi if this instruction caused deoptimization once. | |
| 2510 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? | |
| 2511 call->deopt_id() : Isolate::kNoDeoptId; | |
| 2512 } | |
| 2513 | |
| 2514 *last = new LoadIndexedInstr(new Value(array), | |
| 2515 new Value(index), | |
| 2516 1, | |
| 2517 view_cid, | |
| 2518 deopt_id); | |
| 2519 flow_graph()->AppendTo(cursor, | |
| 2520 *last, | |
| 2521 deopt_id != Isolate::kNoDeoptId ? call->env() : NULL, | |
| 2522 Definition::kValue); | |
| 2523 return true; | |
| 2524 } | |
| 2525 | |
| 2526 | |
| 2527 intptr_t FlowGraphOptimizer::PrepareInlineByteArrayViewOp( | |
| 2528 Instruction* call, | |
| 2529 intptr_t array_cid, | |
| 2530 intptr_t view_cid, | |
| 2531 Definition** array, | |
| 2532 Definition* byte_index, | |
| 2533 Instruction** cursor) { | |
| 2534 // Insert byte_index smi check. | |
| 2535 *cursor = flow_graph()->AppendTo(*cursor, | |
| 2536 new CheckSmiInstr(new Value(byte_index), | |
| 2537 call->deopt_id()), | |
| 2538 call->env(), | |
| 2539 Definition::kEffect); | |
| 2540 | |
| 2541 const bool is_immutable = true; | |
| 2542 LoadFieldInstr* length = | |
| 2543 new LoadFieldInstr(new Value(*array), | |
| 2544 CheckArrayBoundInstr::LengthOffsetFor(array_cid), | |
| 2545 Type::ZoneHandle(Type::SmiType()), | |
| 2546 is_immutable); | |
| 2547 length->set_result_cid(kSmiCid); | |
| 2548 length->set_recognized_kind( | |
| 2549 LoadFieldInstr::RecognizedKindFromArrayCid(array_cid)); | |
| 2550 *cursor = flow_graph()->AppendTo(*cursor, | |
| 2551 length, | |
| 2552 NULL, | |
| 2553 Definition::kValue); | |
| 2554 | |
| 2555 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(array_cid); | |
| 2556 ConstantInstr* bytes_per_element = | |
| 2557 flow_graph()->GetConstant(Smi::Handle(Smi::New(element_size))); | |
| 2558 BinarySmiOpInstr* len_in_bytes = | |
| 2559 new BinarySmiOpInstr(Token::kMUL, | |
| 2560 new Value(length), | |
| 2561 new Value(bytes_per_element), | |
| 2562 call->deopt_id()); | |
| 2563 *cursor = flow_graph()->AppendTo(*cursor, len_in_bytes, call->env(), | |
| 2564 Definition::kValue); | |
| 2565 | |
| 2566 ConstantInstr* length_adjustment = | |
| 2567 flow_graph()->GetConstant(Smi::Handle(Smi::New( | |
| 2568 FlowGraphCompiler::ElementSizeFor(view_cid) - 1))); | |
| 2569 // adjusted_length = len_in_bytes - (element_size - 1). | |
| 2570 BinarySmiOpInstr* adjusted_length = | |
| 2571 new BinarySmiOpInstr(Token::kSUB, | |
| 2572 new Value(len_in_bytes), | |
| 2573 new Value(length_adjustment), | |
| 2574 call->deopt_id()); | |
| 2575 *cursor = flow_graph()->AppendTo(*cursor, adjusted_length, call->env(), | |
| 2576 Definition::kValue); | |
| 2577 | |
| 2578 // Check adjusted_length > 0. | |
| 2579 ConstantInstr* zero = flow_graph()->GetConstant(Smi::Handle(Smi::New(0))); | |
| 2580 *cursor = flow_graph()->AppendTo(*cursor, | |
| 2581 new CheckArrayBoundInstr( | |
| 2582 new Value(adjusted_length), | |
| 2583 new Value(zero), | |
| 2584 call->deopt_id()), | |
| 2585 call->env(), | |
| 2586 Definition::kEffect); | |
| 2587 // Check 0 <= byte_index < adjusted_length. | |
| 2588 *cursor = flow_graph()->AppendTo(*cursor, | |
| 2589 new CheckArrayBoundInstr( | |
| 2590 new Value(adjusted_length), | |
| 2591 new Value(byte_index), | |
| 2592 call->deopt_id()), | |
| 2593 call->env(), | |
| 2594 Definition::kEffect); | |
| 2595 | |
| 2596 if (RawObject::IsExternalTypedDataClassId(array_cid)) { | |
| 2597 LoadUntaggedInstr* elements = | |
| 2598 new LoadUntaggedInstr(new Value(*array), | |
| 2599 ExternalTypedData::data_offset()); | |
| 2600 *cursor = flow_graph()->AppendTo(*cursor, | |
| 2601 elements, | |
| 2602 NULL, | |
| 2603 Definition::kValue); | |
| 2604 *array = elements; | |
| 2605 } | |
| 2606 return array_cid; | |
| 2607 } | |
| 2608 | |
| 2609 | |
| 2610 bool FlowGraphOptimizer::BuildByteArrayViewLoad(InstanceCallInstr* call, | |
| 2611 intptr_t view_cid) { | |
| 2456 if ((view_cid == kTypedDataFloat32x4ArrayCid) && !ShouldInlineSimd()) { | 2612 if ((view_cid == kTypedDataFloat32x4ArrayCid) && !ShouldInlineSimd()) { |
| 2457 return false; | 2613 return false; |
| 2458 } | 2614 } |
| 2459 | 2615 |
| 2460 Definition* array = call->ArgumentAt(0); | 2616 ASSERT(call->HasICData()); |
| 2461 PrepareByteArrayViewOp(call, receiver_cid, view_cid, &array); | 2617 Function& target = Function::Handle(); |
| 2618 GrowableArray<intptr_t> class_ids; | |
| 2619 call->ic_data()->GetCheckAt(0, &class_ids, &target); | |
| 2620 const intptr_t receiver_cid = class_ids[0]; | |
| 2462 | 2621 |
| 2463 // Optimistically build a smi-checked load for Int32 and Uint32 | 2622 TargetEntryInstr* entry; |
| 2464 // loads on ia32 like we do for normal array loads, and only revert to | 2623 Definition* last; |
| 2465 // mint case after deoptimizing here. | 2624 if (!TryInlineRecognizedMethod(receiver_cid, |
| 2466 intptr_t deopt_id = Isolate::kNoDeoptId; | 2625 target, |
| 2467 if ((view_cid == kTypedDataInt32ArrayCid || | 2626 call, |
| 2468 view_cid == kTypedDataUint32ArrayCid) && | 2627 call->token_pos(), |
| 2469 call->ic_data()->deopt_reason() == kDeoptUnknown) { | 2628 *call->ic_data(), |
| 2470 deopt_id = call->deopt_id(); | 2629 &entry, &last)) { |
| 2630 return false; | |
| 2471 } | 2631 } |
| 2472 Definition* byte_index = call->ArgumentAt(1); | 2632 |
| 2473 LoadIndexedInstr* array_op = new LoadIndexedInstr(new Value(array), | 2633 // Insert receiver class check. |
| 2474 new Value(byte_index), | 2634 AddReceiverCheck(call); |
| 2475 1, // Index scale. | 2635 // Remove the original push arguments. |
| 2476 view_cid, | 2636 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 2477 deopt_id); | 2637 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 2478 ReplaceCall(call, array_op); | 2638 push->ReplaceUsesWith(push->value()->definition()); |
| 2639 push->RemoveFromGraph(); | |
| 2640 } | |
| 2641 // Replace all uses of this definition with the result. | |
| 2642 call->ReplaceUsesWith(last); | |
| 2643 // Finally insert the sequence other definition in place of this one in the | |
| 2644 // graph. | |
| 2645 call->previous()->LinkTo(entry->next()); | |
| 2646 entry->UnuseAllInputs(); // Entry block is not in the graph. | |
| 2647 last->LinkTo(call); | |
| 2648 // Remove through the iterator. | |
| 2649 ASSERT(current_iterator()->Current() == call); | |
| 2650 current_iterator()->RemoveCurrentFromGraph(); | |
| 2651 call->set_previous(NULL); | |
| 2652 call->set_next(NULL); | |
| 2479 return true; | 2653 return true; |
| 2480 } | 2654 } |
| 2481 | 2655 |
| 2482 | 2656 |
| 2483 bool FlowGraphOptimizer::BuildByteArrayViewStore(InstanceCallInstr* call, | 2657 bool FlowGraphOptimizer::BuildByteArrayViewStore(InstanceCallInstr* call, |
| 2484 intptr_t view_cid) { | 2658 intptr_t view_cid) { |
| 2485 if ((view_cid == kTypedDataFloat32x4ArrayCid) && !ShouldInlineSimd()) { | 2659 if ((view_cid == kTypedDataFloat32x4ArrayCid) && !ShouldInlineSimd()) { |
| 2486 return false; | 2660 return false; |
| 2487 } | 2661 } |
| 2488 ASSERT(call->HasICData()); | 2662 ASSERT(call->HasICData()); |
| (...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2818 return; | 2992 return; |
| 2819 } | 2993 } |
| 2820 if ((op_kind == Token::kSET) && | 2994 if ((op_kind == Token::kSET) && |
| 2821 TryInlineInstanceSetter(instr, unary_checks)) { | 2995 TryInlineInstanceSetter(instr, unary_checks)) { |
| 2822 return; | 2996 return; |
| 2823 } | 2997 } |
| 2824 if (TryInlineInstanceMethod(instr)) { | 2998 if (TryInlineInstanceMethod(instr)) { |
| 2825 return; | 2999 return; |
| 2826 } | 3000 } |
| 2827 | 3001 |
| 2828 const bool has_one_target = unary_checks.HasOneTarget(); | 3002 bool has_one_target = unary_checks.HasOneTarget(); |
| 3003 | |
| 3004 if (has_one_target) { | |
| 3005 // Check if the single target is a polymorphic target, if it is, | |
| 3006 // we don't have one target. | |
| 3007 const Function& target = Function::Handle(unary_checks.GetTargetAt(0)); | |
| 3008 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target); | |
| 3009 has_one_target = !polymorphic_target; | |
| 3010 } | |
| 2829 | 3011 |
| 2830 if (has_one_target) { | 3012 if (has_one_target) { |
| 2831 const bool is_method_extraction = | 3013 const bool is_method_extraction = |
| 2832 Function::Handle(unary_checks.GetTargetAt(0)).IsMethodExtractor(); | 3014 Function::Handle(unary_checks.GetTargetAt(0)).IsMethodExtractor(); |
| 2833 | 3015 |
| 2834 if ((is_method_extraction && !MethodExtractorNeedsClassCheck(instr)) || | 3016 if ((is_method_extraction && !MethodExtractorNeedsClassCheck(instr)) || |
| 2835 (!is_method_extraction && !InstanceCallNeedsClassCheck(instr))) { | 3017 (!is_method_extraction && !InstanceCallNeedsClassCheck(instr))) { |
| 2836 const bool call_with_checks = false; | 3018 const bool call_with_checks = false; |
| 2837 PolymorphicInstanceCallInstr* call = | 3019 PolymorphicInstanceCallInstr* call = |
| 2838 new PolymorphicInstanceCallInstr(instr, unary_checks, | 3020 new PolymorphicInstanceCallInstr(instr, unary_checks, |
| (...skipping 4914 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7753 } | 7935 } |
| 7754 | 7936 |
| 7755 // Insert materializations at environment uses. | 7937 // Insert materializations at environment uses. |
| 7756 for (intptr_t i = 0; i < exits.length(); i++) { | 7938 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7757 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 7939 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
| 7758 } | 7940 } |
| 7759 } | 7941 } |
| 7760 | 7942 |
| 7761 | 7943 |
| 7762 } // namespace dart | 7944 } // namespace dart |
| OLD | NEW |