| 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 1343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1354 case MethodRecognizer::kByteArrayBaseGetFloat32x4: | 1354 case MethodRecognizer::kByteArrayBaseGetFloat32x4: |
| 1355 if (!ShouldInlineSimd()) return false; | 1355 if (!ShouldInlineSimd()) return false; |
| 1356 return InlineByteArrayViewLoad(call, receiver, receiver_cid, | 1356 return InlineByteArrayViewLoad(call, receiver, receiver_cid, |
| 1357 kTypedDataFloat32x4ArrayCid, | 1357 kTypedDataFloat32x4ArrayCid, |
| 1358 ic_data, entry, last); | 1358 ic_data, entry, last); |
| 1359 case MethodRecognizer::kByteArrayBaseGetInt32x4: | 1359 case MethodRecognizer::kByteArrayBaseGetInt32x4: |
| 1360 if (!ShouldInlineSimd()) return false; | 1360 if (!ShouldInlineSimd()) return false; |
| 1361 return InlineByteArrayViewLoad(call, receiver, receiver_cid, | 1361 return InlineByteArrayViewLoad(call, receiver, receiver_cid, |
| 1362 kTypedDataInt32x4ArrayCid, | 1362 kTypedDataInt32x4ArrayCid, |
| 1363 ic_data, entry, last); | 1363 ic_data, entry, last); |
| 1364 case MethodRecognizer::kByteArrayBaseSetInt8: |
| 1365 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
| 1366 kTypedDataInt8ArrayCid, |
| 1367 ic_data, entry, last); |
| 1368 case MethodRecognizer::kByteArrayBaseSetUint8: |
| 1369 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
| 1370 kTypedDataUint8ArrayCid, |
| 1371 ic_data, entry, last); |
| 1372 case MethodRecognizer::kByteArrayBaseSetInt16: |
| 1373 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
| 1374 kTypedDataInt16ArrayCid, |
| 1375 ic_data, entry, last); |
| 1376 case MethodRecognizer::kByteArrayBaseSetUint16: |
| 1377 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
| 1378 kTypedDataUint16ArrayCid, |
| 1379 ic_data, entry, last); |
| 1380 case MethodRecognizer::kByteArrayBaseSetInt32: |
| 1381 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
| 1382 kTypedDataInt32ArrayCid, |
| 1383 ic_data, entry, last); |
| 1384 case MethodRecognizer::kByteArrayBaseSetUint32: |
| 1385 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
| 1386 kTypedDataUint32ArrayCid, |
| 1387 ic_data, entry, last); |
| 1388 case MethodRecognizer::kByteArrayBaseSetFloat32: |
| 1389 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
| 1390 kTypedDataFloat32ArrayCid, |
| 1391 ic_data, entry, last); |
| 1392 case MethodRecognizer::kByteArrayBaseSetFloat64: |
| 1393 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
| 1394 kTypedDataFloat64ArrayCid, |
| 1395 ic_data, entry, last); |
| 1396 case MethodRecognizer::kByteArrayBaseSetFloat32x4: |
| 1397 if (!ShouldInlineSimd()) return false; |
| 1398 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
| 1399 kTypedDataFloat32x4ArrayCid, |
| 1400 ic_data, entry, last); |
| 1401 case MethodRecognizer::kByteArrayBaseSetInt32x4: |
| 1402 if (!ShouldInlineSimd()) return false; |
| 1403 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
| 1404 kTypedDataInt32x4ArrayCid, |
| 1405 ic_data, entry, last); |
| 1364 default: | 1406 default: |
| 1365 return false; | 1407 return false; |
| 1366 } | 1408 } |
| 1367 } | 1409 } |
| 1368 | 1410 |
| 1369 | 1411 |
| 1370 intptr_t FlowGraphOptimizer::PrepareInlineIndexedOp(Instruction* call, | 1412 intptr_t FlowGraphOptimizer::PrepareInlineIndexedOp(Instruction* call, |
| 1371 intptr_t array_cid, | 1413 intptr_t array_cid, |
| 1372 Definition** array, | 1414 Definition** array, |
| 1373 Definition* index, | 1415 Definition* index, |
| (...skipping 1658 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3032 view_cid, | 3074 view_cid, |
| 3033 deopt_id); | 3075 deopt_id); |
| 3034 flow_graph()->AppendTo(cursor, | 3076 flow_graph()->AppendTo(cursor, |
| 3035 *last, | 3077 *last, |
| 3036 deopt_id != Isolate::kNoDeoptId ? call->env() : NULL, | 3078 deopt_id != Isolate::kNoDeoptId ? call->env() : NULL, |
| 3037 Definition::kValue); | 3079 Definition::kValue); |
| 3038 return true; | 3080 return true; |
| 3039 } | 3081 } |
| 3040 | 3082 |
| 3041 | 3083 |
| 3084 bool FlowGraphOptimizer::InlineByteArrayViewStore(const Function& target, |
| 3085 Instruction* call, |
| 3086 Definition* receiver, |
| 3087 intptr_t array_cid, |
| 3088 intptr_t view_cid, |
| 3089 const ICData& ic_data, |
| 3090 TargetEntryInstr** entry, |
| 3091 Definition** last) { |
| 3092 ASSERT(array_cid != kIllegalCid); |
| 3093 Definition* array = receiver; |
| 3094 Definition* index = call->ArgumentAt(1); |
| 3095 *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(), |
| 3096 call->GetBlock()->try_index()); |
| 3097 (*entry)->InheritDeoptTarget(call); |
| 3098 Instruction* cursor = *entry; |
| 3099 |
| 3100 array_cid = PrepareInlineByteArrayViewOp(call, |
| 3101 array_cid, |
| 3102 view_cid, |
| 3103 &array, |
| 3104 index, |
| 3105 &cursor); |
| 3106 |
| 3107 // Extract the instance call so we can use the function_name in the stored |
| 3108 // value check ICData. |
| 3109 InstanceCallInstr* i_call = NULL; |
| 3110 if (call->IsPolymorphicInstanceCall()) { |
| 3111 i_call = call->AsPolymorphicInstanceCall()->instance_call(); |
| 3112 } else { |
| 3113 ASSERT(call->IsInstanceCall()); |
| 3114 i_call = call->AsInstanceCall(); |
| 3115 } |
| 3116 ASSERT(i_call != NULL); |
| 3117 ICData& value_check = ICData::ZoneHandle(); |
| 3118 switch (view_cid) { |
| 3119 case kTypedDataInt8ArrayCid: |
| 3120 case kTypedDataUint8ArrayCid: |
| 3121 case kTypedDataUint8ClampedArrayCid: |
| 3122 case kExternalTypedDataUint8ArrayCid: |
| 3123 case kExternalTypedDataUint8ClampedArrayCid: |
| 3124 case kTypedDataInt16ArrayCid: |
| 3125 case kTypedDataUint16ArrayCid: { |
| 3126 // Check that value is always smi. |
| 3127 value_check = ICData::New(flow_graph_->parsed_function().function(), |
| 3128 i_call->function_name(), |
| 3129 Object::empty_array(), // Dummy args. descr. |
| 3130 Isolate::kNoDeoptId, |
| 3131 1); |
| 3132 value_check.AddReceiverCheck(kSmiCid, target); |
| 3133 break; |
| 3134 } |
| 3135 case kTypedDataInt32ArrayCid: |
| 3136 case kTypedDataUint32ArrayCid: |
| 3137 // We don't have ICData for the value stored, so we optimistically assume |
| 3138 // smis first. If we ever deoptimized here, we require to unbox the value |
| 3139 // before storing to handle the mint case, too. |
| 3140 if (i_call->ic_data()->deopt_reason() == kDeoptUnknown) { |
| 3141 value_check = ICData::New(flow_graph_->parsed_function().function(), |
| 3142 i_call->function_name(), |
| 3143 Object::empty_array(), // Dummy args. descr. |
| 3144 Isolate::kNoDeoptId, |
| 3145 1); |
| 3146 value_check.AddReceiverCheck(kSmiCid, target); |
| 3147 } |
| 3148 break; |
| 3149 case kTypedDataFloat32ArrayCid: |
| 3150 case kTypedDataFloat64ArrayCid: { |
| 3151 // Check that value is always double. |
| 3152 value_check = ICData::New(flow_graph_->parsed_function().function(), |
| 3153 i_call->function_name(), |
| 3154 Object::empty_array(), // Dummy args. descr. |
| 3155 Isolate::kNoDeoptId, |
| 3156 1); |
| 3157 value_check.AddReceiverCheck(kDoubleCid, target); |
| 3158 break; |
| 3159 } |
| 3160 case kTypedDataInt32x4ArrayCid: { |
| 3161 // Check that value is always Int32x4. |
| 3162 value_check = ICData::New(flow_graph_->parsed_function().function(), |
| 3163 i_call->function_name(), |
| 3164 Object::empty_array(), // Dummy args. descr. |
| 3165 Isolate::kNoDeoptId, |
| 3166 1); |
| 3167 value_check.AddReceiverCheck(kInt32x4Cid, target); |
| 3168 break; |
| 3169 } |
| 3170 case kTypedDataFloat32x4ArrayCid: { |
| 3171 // Check that value is always Float32x4. |
| 3172 value_check = ICData::New(flow_graph_->parsed_function().function(), |
| 3173 i_call->function_name(), |
| 3174 Object::empty_array(), // Dummy args. descr. |
| 3175 Isolate::kNoDeoptId, |
| 3176 1); |
| 3177 value_check.AddReceiverCheck(kFloat32x4Cid, target); |
| 3178 break; |
| 3179 } |
| 3180 default: |
| 3181 // Array cids are already checked in the caller. |
| 3182 UNREACHABLE(); |
| 3183 } |
| 3184 |
| 3185 Definition* stored_value = call->ArgumentAt(2); |
| 3186 if (!value_check.IsNull()) { |
| 3187 AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(), |
| 3188 call); |
| 3189 } |
| 3190 StoreBarrierType needs_store_barrier = kNoStoreBarrier; |
| 3191 *last = new StoreIndexedInstr(new Value(array), |
| 3192 new Value(index), |
| 3193 new Value(stored_value), |
| 3194 needs_store_barrier, |
| 3195 1, // Index scale |
| 3196 view_cid, |
| 3197 call->deopt_id()); |
| 3198 |
| 3199 flow_graph()->AppendTo(cursor, |
| 3200 *last, |
| 3201 call->deopt_id() != Isolate::kNoDeoptId ? |
| 3202 call->env() : NULL, |
| 3203 Definition::kEffect); |
| 3204 return true; |
| 3205 } |
| 3206 |
| 3207 |
| 3208 |
| 3042 intptr_t FlowGraphOptimizer::PrepareInlineByteArrayViewOp( | 3209 intptr_t FlowGraphOptimizer::PrepareInlineByteArrayViewOp( |
| 3043 Instruction* call, | 3210 Instruction* call, |
| 3044 intptr_t array_cid, | 3211 intptr_t array_cid, |
| 3045 intptr_t view_cid, | 3212 intptr_t view_cid, |
| 3046 Definition** array, | 3213 Definition** array, |
| 3047 Definition* byte_index, | 3214 Definition* byte_index, |
| 3048 Instruction** cursor) { | 3215 Instruction** cursor) { |
| 3049 // Insert byte_index smi check. | 3216 // Insert byte_index smi check. |
| 3050 *cursor = flow_graph()->AppendTo(*cursor, | 3217 *cursor = flow_graph()->AppendTo(*cursor, |
| 3051 new CheckSmiInstr(new Value(byte_index), | 3218 new CheckSmiInstr(new Value(byte_index), |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3178 (view_cid == kTypedDataInt32x4ArrayCid); | 3345 (view_cid == kTypedDataInt32x4ArrayCid); |
| 3179 if (simd_view && !ShouldInlineSimd()) { | 3346 if (simd_view && !ShouldInlineSimd()) { |
| 3180 return false; | 3347 return false; |
| 3181 } | 3348 } |
| 3182 ASSERT(call->HasICData()); | 3349 ASSERT(call->HasICData()); |
| 3183 Function& target = Function::Handle(); | 3350 Function& target = Function::Handle(); |
| 3184 GrowableArray<intptr_t> class_ids; | 3351 GrowableArray<intptr_t> class_ids; |
| 3185 call->ic_data()->GetCheckAt(0, &class_ids, &target); | 3352 call->ic_data()->GetCheckAt(0, &class_ids, &target); |
| 3186 const intptr_t receiver_cid = class_ids[0]; | 3353 const intptr_t receiver_cid = class_ids[0]; |
| 3187 | 3354 |
| 3188 Definition* array = call->ArgumentAt(0); | 3355 TargetEntryInstr* entry; |
| 3189 PrepareByteArrayViewOp(call, receiver_cid, view_cid, &array); | 3356 Definition* last; |
| 3190 ICData& value_check = ICData::ZoneHandle(); | 3357 if (!TryInlineRecognizedMethod(receiver_cid, |
| 3191 switch (view_cid) { | 3358 target, |
| 3192 case kTypedDataInt8ArrayCid: | 3359 call, |
| 3193 case kTypedDataUint8ArrayCid: | 3360 call->ArgumentAt(0), |
| 3194 case kTypedDataUint8ClampedArrayCid: | 3361 call->token_pos(), |
| 3195 case kExternalTypedDataUint8ArrayCid: | 3362 *call->ic_data(), |
| 3196 case kExternalTypedDataUint8ClampedArrayCid: | 3363 &entry, &last)) { |
| 3197 case kTypedDataInt16ArrayCid: | 3364 return false; |
| 3198 case kTypedDataUint16ArrayCid: { | |
| 3199 // Check that value is always smi. | |
| 3200 value_check = ICData::New(flow_graph_->parsed_function().function(), | |
| 3201 call->function_name(), | |
| 3202 Object::empty_array(), // Dummy args. descr. | |
| 3203 Isolate::kNoDeoptId, | |
| 3204 1); | |
| 3205 value_check.AddReceiverCheck(kSmiCid, target); | |
| 3206 break; | |
| 3207 } | |
| 3208 case kTypedDataInt32ArrayCid: | |
| 3209 case kTypedDataUint32ArrayCid: | |
| 3210 // We don't have ICData for the value stored, so we optimistically assume | |
| 3211 // smis first. If we ever deoptimized here, we require to unbox the value | |
| 3212 // before storing to handle the mint case, too. | |
| 3213 if (call->ic_data()->deopt_reason() == kDeoptUnknown) { | |
| 3214 value_check = ICData::New(flow_graph_->parsed_function().function(), | |
| 3215 call->function_name(), | |
| 3216 Object::empty_array(), // Dummy args. descr. | |
| 3217 Isolate::kNoDeoptId, | |
| 3218 1); | |
| 3219 value_check.AddReceiverCheck(kSmiCid, target); | |
| 3220 } | |
| 3221 break; | |
| 3222 case kTypedDataFloat32ArrayCid: | |
| 3223 case kTypedDataFloat64ArrayCid: { | |
| 3224 // Check that value is always double. | |
| 3225 value_check = ICData::New(flow_graph_->parsed_function().function(), | |
| 3226 call->function_name(), | |
| 3227 Object::empty_array(), // Dummy args. descr. | |
| 3228 Isolate::kNoDeoptId, | |
| 3229 1); | |
| 3230 value_check.AddReceiverCheck(kDoubleCid, target); | |
| 3231 break; | |
| 3232 } | |
| 3233 case kTypedDataInt32x4ArrayCid: { | |
| 3234 // Check that value is always Int32x4. | |
| 3235 value_check = ICData::New(flow_graph_->parsed_function().function(), | |
| 3236 call->function_name(), | |
| 3237 Object::empty_array(), // Dummy args. descr. | |
| 3238 Isolate::kNoDeoptId, | |
| 3239 1); | |
| 3240 value_check.AddReceiverCheck(kInt32x4Cid, target); | |
| 3241 break; | |
| 3242 } | |
| 3243 case kTypedDataFloat32x4ArrayCid: { | |
| 3244 // Check that value is always Float32x4. | |
| 3245 value_check = ICData::New(flow_graph_->parsed_function().function(), | |
| 3246 call->function_name(), | |
| 3247 Object::empty_array(), // Dummy args. descr. | |
| 3248 Isolate::kNoDeoptId, | |
| 3249 1); | |
| 3250 value_check.AddReceiverCheck(kFloat32x4Cid, target); | |
| 3251 break; | |
| 3252 } | |
| 3253 default: | |
| 3254 // Array cids are already checked in the caller. | |
| 3255 UNREACHABLE(); | |
| 3256 } | 3365 } |
| 3257 | 3366 |
| 3258 Definition* index = call->ArgumentAt(1); | 3367 // Insert receiver class check. |
| 3259 Definition* stored_value = call->ArgumentAt(2); | 3368 AddReceiverCheck(call); |
| 3260 if (!value_check.IsNull()) { | 3369 // Remove the original push arguments. |
| 3261 AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(), | 3370 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 3262 call); | 3371 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 3372 push->ReplaceUsesWith(push->value()->definition()); |
| 3373 push->RemoveFromGraph(); |
| 3263 } | 3374 } |
| 3264 StoreBarrierType needs_store_barrier = kNoStoreBarrier; | 3375 // Replace all uses of this definition with the result. |
| 3265 StoreIndexedInstr* array_op = new StoreIndexedInstr(new Value(array), | 3376 call->ReplaceUsesWith(last); |
| 3266 new Value(index), | 3377 // Finally insert the sequence other definition in place of this one in the |
| 3267 new Value(stored_value), | 3378 // graph. |
| 3268 needs_store_barrier, | 3379 call->previous()->LinkTo(entry->next()); |
| 3269 1, // Index scale | 3380 entry->UnuseAllInputs(); // Entry block is not in the graph. |
| 3270 view_cid, | 3381 last->LinkTo(call); |
| 3271 call->deopt_id()); | 3382 // Remove through the iterator. |
| 3272 ReplaceCall(call, array_op); | 3383 ASSERT(current_iterator()->Current() == call); |
| 3384 current_iterator()->RemoveCurrentFromGraph(); |
| 3385 call->set_previous(NULL); |
| 3386 call->set_next(NULL); |
| 3273 return true; | 3387 return true; |
| 3274 } | 3388 } |
| 3275 | 3389 |
| 3276 | 3390 |
| 3277 void FlowGraphOptimizer::PrepareByteArrayViewOp( | 3391 void FlowGraphOptimizer::PrepareByteArrayViewOp( |
| 3278 InstanceCallInstr* call, | 3392 InstanceCallInstr* call, |
| 3279 intptr_t receiver_cid, | 3393 intptr_t receiver_cid, |
| 3280 intptr_t view_cid, | 3394 intptr_t view_cid, |
| 3281 Definition** array) { | 3395 Definition** array) { |
| 3282 Definition* byte_index = call->ArgumentAt(1); | 3396 Definition* byte_index = call->ArgumentAt(1); |
| (...skipping 5213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8496 } | 8610 } |
| 8497 | 8611 |
| 8498 // Insert materializations at environment uses. | 8612 // Insert materializations at environment uses. |
| 8499 for (intptr_t i = 0; i < exits.length(); i++) { | 8613 for (intptr_t i = 0; i < exits.length(); i++) { |
| 8500 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 8614 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
| 8501 } | 8615 } |
| 8502 } | 8616 } |
| 8503 | 8617 |
| 8504 | 8618 |
| 8505 } // namespace dart | 8619 } // namespace dart |
| OLD | NEW |