Chromium Code Reviews| Index: runtime/vm/flow_graph_optimizer.cc |
| =================================================================== |
| --- runtime/vm/flow_graph_optimizer.cc (revision 27433) |
| +++ runtime/vm/flow_graph_optimizer.cc (working copy) |
| @@ -160,6 +160,7 @@ |
| Object::empty_array(), // Dummy argument descriptor. |
| ic_data.deopt_id(), |
| ic_data.num_args_tested())); |
| + new_ic_data.set_deopt_reason(ic_data.deopt_reason()); |
| const Function& function = |
| Function::Handle(ic_data.GetTargetForReceiverClassId(cid)); |
| @@ -789,7 +790,6 @@ |
| call->env(), |
| Definition::kEffect); |
| - |
| if (class_id == kGrowableObjectArrayCid) { |
| // Insert data elements load. |
| LoadFieldInstr* elements = |
| @@ -996,11 +996,171 @@ |
| } |
| +static intptr_t MethodKindToCid(MethodRecognizer::Kind kind) { |
| + switch (kind) { |
| + case MethodRecognizer::kImmutableArrayGetIndexed: |
| + return kImmutableArrayCid; |
| + case MethodRecognizer::kObjectArrayGetIndexed: |
| + return kArrayCid; |
| + |
| + case MethodRecognizer::kGrowableArrayGetIndexed: |
| + return kGrowableObjectArrayCid; |
| + |
| + case MethodRecognizer::kFloat32ArrayGetIndexed: |
| + return kTypedDataFloat32ArrayCid; |
| + |
| + case MethodRecognizer::kFloat64ArrayGetIndexed: |
| + return kTypedDataFloat64ArrayCid; |
| + |
| + case MethodRecognizer::kInt8ArrayGetIndexed: |
| + return kTypedDataInt8ArrayCid; |
| + |
| + case MethodRecognizer::kUint8ArrayGetIndexed: |
| + return kTypedDataUint8ArrayCid; |
| + |
| + case MethodRecognizer::kUint8ClampedArrayGetIndexed: |
| + return kTypedDataUint8ClampedArrayCid; |
| + |
| + case MethodRecognizer::kExternalUint8ArrayGetIndexed: |
| + return kExternalTypedDataUint8ArrayCid; |
| + |
| + case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed: |
| + return kExternalTypedDataUint8ClampedArrayCid; |
| + |
| + case MethodRecognizer::kInt16ArrayGetIndexed: |
| + return kTypedDataInt16ArrayCid; |
| + |
| + case MethodRecognizer::kUint16ArrayGetIndexed: |
| + return kTypedDataUint16ArrayCid; |
| + |
| + case MethodRecognizer::kInt32ArrayGetIndexed: |
| + return kTypedDataInt32ArrayCid; |
| + |
| + case MethodRecognizer::kUint32ArrayGetIndexed: |
| + return kTypedDataUint32ArrayCid; |
| + |
| + case MethodRecognizer::kFloat32x4ArrayGetIndexed: |
| + return kTypedDataFloat32x4ArrayCid; |
| + |
| + default: |
| + break; |
| + } |
| + return kIllegalCid; |
| +} |
| + |
| + |
| +// Explicit instantiation because this variant used in flow_graph_inliner.cc. |
| +template bool FlowGraphOptimizer:: |
| +TryInlineRecognizedMethod<PolymorphicInstanceCallInstr*>( |
| + const Function&, |
| + PolymorphicInstanceCallInstr*, |
| + const ICData&, |
| + TargetEntryInstr**, |
| + Definition**); |
| + |
| + |
| +template <typename T> |
| +bool FlowGraphOptimizer::TryInlineRecognizedMethod(const Function& target, |
| + T call, |
| + const ICData& ic_data, |
| + TargetEntryInstr** entry, |
| + Definition** last) { |
| + // TODO(fschneider): Extend to other recognized methods. |
|
Cutch
2013/09/17 16:08:47
The below code is specific to preparing an indexed
Florian Schneider
2013/09/18 14:00:36
Yes, I'd have to do that for the next CL anyway.
|
| + MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target); |
| + intptr_t array_cid = MethodKindToCid(kind); |
| + if (array_cid == kIllegalCid) return false; |
| + |
| + // Insert index smi checks and attach a copy of the |
| + // original environment because the operation can still deoptimize. |
| + Definition* array = call->ArgumentAt(0); |
| + Definition* index = call->ArgumentAt(1); |
| + *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(), |
| + call->GetBlock()->try_index()); |
| + (*entry)->InheritDeoptTarget(call); |
| + |
| + Instruction* cursor = *entry; |
| + cursor = flow_graph()->AppendTo(cursor, |
| + new CheckSmiInstr(new Value(index), |
| + call->deopt_id()), |
| + call->env(), |
| + Definition::kEffect); |
| + |
| + // Insert array length load and bounds check. |
| + const bool is_immutable = |
| + CheckArrayBoundInstr::IsFixedLengthArrayType(array_cid); |
| + LoadFieldInstr* length = |
| + new LoadFieldInstr(new Value(array), |
| + CheckArrayBoundInstr::LengthOffsetFor(array_cid), |
| + Type::ZoneHandle(Type::SmiType()), |
| + is_immutable); |
| + length->set_result_cid(kSmiCid); |
| + length->set_recognized_kind( |
| + LoadFieldInstr::RecognizedKindFromArrayCid(array_cid)); |
| + cursor = flow_graph()->AppendTo(cursor, |
| + length, |
| + NULL, |
| + Definition::kValue); |
| + |
| + cursor = flow_graph()->AppendTo(cursor, |
| + new CheckArrayBoundInstr( |
| + new Value(length), |
| + new Value(index), |
| + call->deopt_id()), |
| + call->env(), |
| + Definition::kEffect); |
| + |
| + if (array_cid == kGrowableObjectArrayCid) { |
| + // Insert data elements load. |
| + LoadFieldInstr* elements = |
| + new LoadFieldInstr(new Value(array), |
| + GrowableObjectArray::data_offset(), |
| + Type::ZoneHandle(Type::DynamicType())); |
| + elements->set_result_cid(kArrayCid); |
| + cursor = flow_graph()->AppendTo(cursor, |
| + elements, |
| + NULL, |
| + Definition::kValue); |
| + // Load from the data from backing store which is a fixed-length array. |
| + array = elements; |
| + array_cid = kArrayCid; |
| + } else if (RawObject::IsExternalTypedDataClassId(array_cid)) { |
| + LoadUntaggedInstr* elements = |
| + new LoadUntaggedInstr(new Value(array), |
| + ExternalTypedData::data_offset()); |
| + cursor = flow_graph()->AppendTo(cursor, |
| + elements, |
| + NULL, |
| + Definition::kValue); |
| + array = elements; |
| + } |
| + |
| + intptr_t deopt_id = Isolate::kNoDeoptId; |
| + if ((array_cid == kTypedDataInt32ArrayCid) || |
| + (array_cid == kTypedDataUint32ArrayCid)) { |
| + // Set deopt_id if we can optimistically assume that the result is Smi. |
| + // Assume mixed Mint/Smi if this instruction caused deoptimization once. |
|
Cutch
2013/09/17 16:08:47
Shouldn't this include kTypedDataInt64ArrayCid and
|
| + deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? |
| + call->deopt_id() : Isolate::kNoDeoptId; |
| + } |
| + |
| + // Array load and return. |
| + intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid); |
| + *last = new LoadIndexedInstr(new Value(array), |
| + new Value(index), |
| + index_scale, |
| + array_cid, |
| + deopt_id); |
| + flow_graph()->AppendTo(cursor, |
| + *last, |
| + deopt_id != Isolate::kNoDeoptId ? call->env() : NULL, |
| + Definition::kValue); |
| + return true; |
| +} |
| + |
| + |
| bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { |
| const intptr_t class_id = ReceiverClassId(call); |
| - // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt. |
| - intptr_t deopt_id = Isolate::kNoDeoptId; |
| switch (class_id) { |
| case kArrayCid: |
| case kImmutableArrayCid: |
| @@ -1021,31 +1181,43 @@ |
| } |
| break; |
| case kTypedDataInt32ArrayCid: |
| - case kTypedDataUint32ArrayCid: { |
| + case kTypedDataUint32ArrayCid: |
|
Cutch
2013/09/17 16:08:47
Ahh, I see we never supported unboxed loads from 6
|
| if (!CanUnboxInt32()) return false; |
| - |
| - // Set deopt_id if we can optimistically assume that the result is Smi. |
| - // Assume mixed Mint/Smi if this instruction caused deoptimization once. |
| - ASSERT(call->HasICData()); |
| - const ICData& ic_data = *call->ic_data(); |
| - deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? |
| - call->deopt_id() : Isolate::kNoDeoptId; |
| - } |
| break; |
| default: |
| return false; |
| } |
| - Definition* array = call->ArgumentAt(0); |
| - Definition* index = call->ArgumentAt(1); |
| - intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); |
| - intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid); |
| - Definition* array_op = |
| - new LoadIndexedInstr(new Value(array), |
| - new Value(index), |
| - index_scale, |
| - array_cid, |
| - deopt_id); |
| - ReplaceCall(call, array_op); |
| + |
| + const Function& target = |
| + Function::Handle(call->ic_data()->GetTargetAt(0)); |
| + TargetEntryInstr* entry; |
| + Definition* last; |
| + ASSERT(class_id == MethodKindToCid(MethodRecognizer::RecognizeKind(target))); |
| + bool success = TryInlineRecognizedMethod(target, |
| + call, |
| + *call->ic_data(), |
| + &entry, &last); |
| + ASSERT(success); |
| + // Insert receiver class check. |
| + AddReceiverCheck(call); |
| + // Remove the original push arguments. |
| + for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| + PushArgumentInstr* push = call->PushArgumentAt(i); |
| + push->ReplaceUsesWith(push->value()->definition()); |
| + push->RemoveFromGraph(); |
| + } |
| + // Replace all uses of this definition with the result. |
| + call->ReplaceUsesWith(last); |
| + // Finally insert the sequence other definition in place of this one in the |
| + // graph. |
| + call->previous()->LinkTo(entry->next()); |
| + entry->UnuseAllInputs(); // Entry block is not in the graph. |
| + last->LinkTo(call); |
| + // Remove through the iterator. |
| + ASSERT(current_iterator()->Current() == call); |
| + current_iterator()->RemoveCurrentFromGraph(); |
| + call->set_previous(NULL); |
| + call->set_next(NULL); |
| return true; |
| } |