Chromium Code Reviews| Index: runtime/vm/intrinsifier.cc |
| diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc |
| index 15a0fa9275c5e0ae839856f01ee82d33846147c6..8f94fe54450f08b6c539f7cc40108ab65dfc7730 100644 |
| --- a/runtime/vm/intrinsifier.cc |
| +++ b/runtime/vm/intrinsifier.cc |
| @@ -384,35 +384,8 @@ static void PrepareIndexedOp(BlockBuilder* builder, |
| Thread::kNoDeoptId)); |
| } |
| - |
| -bool Intrinsifier::Build_ObjectArrayGetIndexed(FlowGraph* flow_graph) { |
| - GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| - TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| - BlockBuilder builder(flow_graph, normal_entry); |
| - |
| - Definition* index = builder.AddParameter(1); |
| - Definition* array = builder.AddParameter(2); |
| - |
| - PrepareIndexedOp(&builder, array, index, Array::length_offset()); |
| - |
| - Definition* result = builder.AddDefinition( |
| - new LoadIndexedInstr(new Value(array), |
| - new Value(index), |
| - Instance::ElementSizeFor(kArrayCid), // index scale |
| - kArrayCid, |
| - Thread::kNoDeoptId, |
| - builder.TokenPos())); |
| - builder.AddIntrinsicReturn(new Value(result)); |
| - return true; |
| -} |
| - |
| - |
| -bool Intrinsifier::Build_ImmutableArrayGetIndexed(FlowGraph* flow_graph) { |
| - return Build_ObjectArrayGetIndexed(flow_graph); |
| -} |
| - |
| - |
| -bool Intrinsifier::Build_Uint8ArrayGetIndexed(FlowGraph* flow_graph) { |
| +static bool IntrinsifyArrayGetIndexed(FlowGraph* flow_graph, |
| + intptr_t array_cid) { |
| GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| BlockBuilder builder(flow_graph, normal_entry); |
| @@ -420,46 +393,70 @@ bool Intrinsifier::Build_Uint8ArrayGetIndexed(FlowGraph* flow_graph) { |
| Definition* index = builder.AddParameter(1); |
| Definition* array = builder.AddParameter(2); |
| - PrepareIndexedOp(&builder, array, index, TypedData::length_offset()); |
| - |
| - Definition* result = builder.AddDefinition( |
| - new LoadIndexedInstr(new Value(array), |
| - new Value(index), |
| - 1, // index scale |
| - kTypedDataUint8ArrayCid, |
| - Thread::kNoDeoptId, |
| - builder.TokenPos())); |
| - builder.AddIntrinsicReturn(new Value(result)); |
| - return true; |
| -} |
| - |
| - |
| -bool Intrinsifier::Build_ExternalUint8ArrayGetIndexed(FlowGraph* flow_graph) { |
| - GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| - TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| - BlockBuilder builder(flow_graph, normal_entry); |
| - |
| - Definition* index = builder.AddParameter(1); |
| - Definition* array = builder.AddParameter(2); |
| + intptr_t length_offset = Array::length_offset(); |
| + if (RawObject::IsTypedDataClassId(array_cid)) { |
| + length_offset = TypedData::length_offset(); |
| + } else if (RawObject::IsExternalTypedDataClassId(array_cid)) { |
| + length_offset = ExternalTypedData::length_offset(); |
| + } |
| - PrepareIndexedOp(&builder, array, index, ExternalTypedData::length_offset()); |
| + PrepareIndexedOp(&builder, array, index, length_offset); |
| - Definition* elements = builder.AddDefinition( |
| + if (RawObject::IsExternalTypedDataClassId(array_cid)) { |
| + array = builder.AddDefinition( |
| new LoadUntaggedInstr(new Value(array), |
| ExternalTypedData::data_offset())); |
| + } |
| + |
| Definition* result = builder.AddDefinition( |
| - new LoadIndexedInstr(new Value(elements), |
| + new LoadIndexedInstr(new Value(array), |
| new Value(index), |
| - 1, // index scale |
| - kExternalTypedDataUint8ArrayCid, |
| + Instance::ElementSizeFor(array_cid), // index scale |
| + array_cid, |
| Thread::kNoDeoptId, |
| builder.TokenPos())); |
| + // Box and/or convert result if necessary. |
| + switch (array_cid) { |
| + case kTypedDataInt32ArrayCid: |
| + case kExternalTypedDataInt32ArrayCid: |
| + result = builder.AddDefinition( |
| + BoxInstr::Create(kUnboxedInt32, new Value(result))); |
| + break; |
| + case kTypedDataUint32ArrayCid: |
| + case kExternalTypedDataUint32ArrayCid: |
| + result = builder.AddDefinition( |
| + BoxInstr::Create(kUnboxedUint32, new Value(result))); |
| + break; |
| + case kTypedDataFloat32ArrayCid: |
| + result = builder.AddDefinition( |
| + new FloatToDoubleInstr(new Value(result), Thread::kNoDeoptId)); |
| + // Fall through. |
| + case kTypedDataFloat64ArrayCid: |
| + result = builder.AddDefinition( |
| + BoxInstr::Create(kUnboxedDouble, new Value(result))); |
| + break; |
| + case kArrayCid: |
| + case kImmutableArrayCid: |
| + case kTypedDataInt8ArrayCid: |
| + case kTypedDataUint8ArrayCid: |
| + case kExternalTypedDataUint8ArrayCid: |
| + case kTypedDataUint8ClampedArrayCid: |
| + case kExternalTypedDataUint8ClampedArrayCid: |
| + case kTypedDataInt16ArrayCid: |
| + case kTypedDataUint16ArrayCid: |
| + // Nothing to do. |
|
rmacnak
2016/08/10 00:01:42
It's weird that LoadIndexedInstr doesn't consisten
Florian Schneider
2016/08/10 00:17:36
We could change it for the smi-sized typed data ar
|
| + break; |
| + default: |
| + UNREACHABLE(); |
| + break; |
| + } |
| builder.AddIntrinsicReturn(new Value(result)); |
| return true; |
| } |
| -bool Intrinsifier::Build_Uint8ArraySetIndexed(FlowGraph* flow_graph) { |
| +static bool IntrinsifyArraySetIndexed(FlowGraph* flow_graph, |
| + intptr_t array_cid) { |
| GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| BlockBuilder builder(flow_graph, normal_entry); |
| @@ -468,54 +465,82 @@ bool Intrinsifier::Build_Uint8ArraySetIndexed(FlowGraph* flow_graph) { |
| Definition* index = builder.AddParameter(2); |
| Definition* array = builder.AddParameter(3); |
| - PrepareIndexedOp(&builder, array, index, TypedData::length_offset()); |
| - |
| - builder.AddInstruction( |
| - new CheckSmiInstr(new Value(value), |
| - Thread::kNoDeoptId, |
| - builder.TokenPos())); |
| - |
| - builder.AddInstruction( |
| - new StoreIndexedInstr(new Value(array), |
| - new Value(index), |
| - new Value(value), |
| - kNoStoreBarrier, |
| - 1, // index scale |
| - kTypedDataUint8ArrayCid, |
| - Thread::kNoDeoptId, |
| - builder.TokenPos())); |
| - // Return null. |
| - Definition* null_def = builder.AddNullDefinition(); |
| - builder.AddIntrinsicReturn(new Value(null_def)); |
| - return true; |
| -} |
| - |
| - |
| -bool Intrinsifier::Build_ExternalUint8ArraySetIndexed(FlowGraph* flow_graph) { |
| - GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| - TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| - BlockBuilder builder(flow_graph, normal_entry); |
| - |
| - Definition* value = builder.AddParameter(1); |
| - Definition* index = builder.AddParameter(2); |
| - Definition* array = builder.AddParameter(3); |
| + intptr_t length_offset = Array::length_offset(); |
| + if (RawObject::IsTypedDataClassId(array_cid)) { |
| + length_offset = TypedData::length_offset(); |
| + } else if (RawObject::IsExternalTypedDataClassId(array_cid)) { |
| + length_offset = ExternalTypedData::length_offset(); |
| + } |
| - PrepareIndexedOp(&builder, array, index, ExternalTypedData::length_offset()); |
| + PrepareIndexedOp(&builder, array, index, length_offset); |
| + |
| + // Value check/conversion. |
| + switch (array_cid) { |
| + case kTypedDataInt8ArrayCid: |
| + case kTypedDataUint8ArrayCid: |
| + case kExternalTypedDataUint8ArrayCid: |
| + case kTypedDataUint8ClampedArrayCid: |
| + case kExternalTypedDataUint8ClampedArrayCid: |
| + case kTypedDataInt16ArrayCid: |
| + case kTypedDataUint16ArrayCid: |
| + builder.AddInstruction(new CheckSmiInstr(new Value(value), |
| + Thread::kNoDeoptId, |
| + builder.TokenPos())); |
| + break; |
| + case kTypedDataInt32ArrayCid: |
| + case kExternalTypedDataInt32ArrayCid: |
| + // Use same truncating unbox-instruction for int32 and uint32. |
| + // Fall-through. |
| + case kTypedDataUint32ArrayCid: |
| + case kExternalTypedDataUint32ArrayCid: |
| + // Supports smi and mint, slow-case for bigints. |
| + value = builder.AddUnboxInstr(kUnboxedUint32, |
| + new Value(value), |
| + /* is_checked = */ false); |
| + break; |
| + case kTypedDataFloat32ArrayCid: |
| + case kTypedDataFloat64ArrayCid: { |
| + const ICData& value_check = ICData::ZoneHandle(ICData::New( |
| + flow_graph->function(), |
| + Symbols::Empty(), // Dummy function name. |
| + Object::empty_array(), // Dummy args. descr. |
| + Thread::kNoDeoptId, |
| + 1, |
| + false)); |
| + value_check.AddReceiverCheck(kDoubleCid, flow_graph->function()); |
| + builder.AddInstruction( |
| + new CheckClassInstr(new Value(value), |
| + Thread::kNoDeoptId, |
| + value_check, |
| + builder.TokenPos())); |
| + value = builder.AddUnboxInstr(kUnboxedDouble, |
| + new Value(value), |
| + /* is_checked = */ true); |
| + if (array_cid == kTypedDataFloat32ArrayCid) { |
| + value = builder.AddDefinition( |
| + new DoubleToFloatInstr(new Value(value), Thread::kNoDeoptId)); |
| + } |
| + break; |
| + } |
| + default: |
| + UNREACHABLE(); |
| + } |
| - builder.AddInstruction( |
| - new CheckSmiInstr(new Value(value), |
| - Thread::kNoDeoptId, |
| - builder.TokenPos())); |
| - Definition* elements = builder.AddDefinition( |
| + if (RawObject::IsExternalTypedDataClassId(array_cid)) { |
| + array = builder.AddDefinition( |
| new LoadUntaggedInstr(new Value(array), |
| ExternalTypedData::data_offset())); |
| + } |
| + // No store barrier. |
| + ASSERT(RawObject::IsExternalTypedDataClassId(array_cid) || |
| + RawObject::IsTypedDataClassId(array_cid)); |
|
rmacnak
2016/08/10 00:01:42
Why no kArrayCid? It's handled for the read case.
Florian Schneider
2016/08/10 00:17:36
The List.[]= is still in assembly (see comment bel
rmacnak
2016/08/10 00:23:30
Acknowledged.
|
| builder.AddInstruction( |
| - new StoreIndexedInstr(new Value(elements), |
| + new StoreIndexedInstr(new Value(array), |
| new Value(index), |
| new Value(value), |
| kNoStoreBarrier, |
| - 1, // index scale |
| - kExternalTypedDataUint8ArrayCid, |
| + Instance::ElementSizeFor(array_cid), // index scale |
| + array_cid, |
| Thread::kNoDeoptId, |
| builder.TokenPos())); |
| // Return null. |
| @@ -525,137 +550,78 @@ bool Intrinsifier::Build_ExternalUint8ArraySetIndexed(FlowGraph* flow_graph) { |
| } |
| -bool Intrinsifier::Build_Uint32ArraySetIndexed(FlowGraph* flow_graph) { |
| - GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| - TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| - BlockBuilder builder(flow_graph, normal_entry); |
| - |
| - Definition* value = builder.AddParameter(1); |
| - Definition* index = builder.AddParameter(2); |
| - Definition* array = builder.AddParameter(3); |
| - |
| - PrepareIndexedOp(&builder, array, index, TypedData::length_offset()); |
| - |
| - Definition* unboxed_value = |
| - builder.AddUnboxInstr(kUnboxedUint32, |
| - new Value(value), |
| - /* is_checked = */ true); |
| - |
| - builder.AddInstruction( |
| - new StoreIndexedInstr(new Value(array), |
| - new Value(index), |
| - new Value(unboxed_value), |
| - kNoStoreBarrier, |
| - 4, // index scale |
| - kTypedDataUint32ArrayCid, |
| - Thread::kNoDeoptId, |
| - builder.TokenPos())); |
| - // Return null. |
| - Definition* null_def = builder.AddNullDefinition(); |
| - builder.AddIntrinsicReturn(new Value(null_def)); |
| - return true; |
| +#define DEFINE_ARRAY_GETTER_INTRINSIC(enum_name) \ |
| +bool Intrinsifier::Build_##enum_name##GetIndexed(FlowGraph* flow_graph) { \ |
| + return IntrinsifyArrayGetIndexed( \ |
| + flow_graph, \ |
| + MethodRecognizer::MethodKindToCid( \ |
| + MethodRecognizer::k##enum_name##GetIndexed)); \ |
| } |
| -bool Intrinsifier::Build_Uint32ArrayGetIndexed(FlowGraph* flow_graph) { |
| - GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| - TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| - BlockBuilder builder(flow_graph, normal_entry); |
| - |
| - Definition* index = builder.AddParameter(1); |
| - Definition* array = builder.AddParameter(2); |
| - |
| - PrepareIndexedOp(&builder, array, index, TypedData::length_offset()); |
| - |
| - Definition* unboxed_value = builder.AddDefinition( |
| - new LoadIndexedInstr(new Value(array), |
| - new Value(index), |
| - 4, // index scale |
| - kTypedDataUint32ArrayCid, |
| - Thread::kNoDeoptId, |
| - builder.TokenPos())); |
| - Definition* result = builder.AddDefinition( |
| - BoxInstr::Create(kUnboxedUint32, new Value(unboxed_value))); |
| - builder.AddIntrinsicReturn(new Value(result)); |
| - return true; |
| +#define DEFINE_ARRAY_SETTER_INTRINSIC(enum_name) \ |
| +bool Intrinsifier::Build_##enum_name##SetIndexed(FlowGraph* flow_graph) { \ |
| + return IntrinsifyArraySetIndexed( \ |
| + flow_graph, \ |
| + MethodRecognizer::MethodKindToCid( \ |
| + MethodRecognizer::k##enum_name##SetIndexed)); \ |
| } |
| +DEFINE_ARRAY_GETTER_INTRINSIC(ObjectArray) // Setter in intrinsifier_<arch>.cc. |
| +DEFINE_ARRAY_GETTER_INTRINSIC(ImmutableArray) |
| -bool Intrinsifier::Build_Float64ArraySetIndexed(FlowGraph* flow_graph) { |
| - if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { |
| - return false; |
| - } |
| +#define DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(enum_name) \ |
| +DEFINE_ARRAY_GETTER_INTRINSIC(enum_name) \ |
| +DEFINE_ARRAY_SETTER_INTRINSIC(enum_name) |
| - GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| - TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| - BlockBuilder builder(flow_graph, normal_entry); |
| - |
| - Definition* value = builder.AddParameter(1); |
| - Definition* index = builder.AddParameter(2); |
| - Definition* array = builder.AddParameter(3); |
| +DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Int8Array) |
| +DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint8Array) |
| +DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(ExternalUint8Array) |
| +DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint8ClampedArray) |
| +DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(ExternalUint8ClampedArray) |
| +DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Int16Array) |
| +DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint16Array) |
| +DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Int32Array) |
| +DEFINE_ARRAY_GETTER_SETTER_INTRINSICS(Uint32Array) |
| - PrepareIndexedOp(&builder, array, index, TypedData::length_offset()); |
| +#undef DEFINE_ARRAY_GETTER_SETTER_INTRINSICS |
| +#undef DEFINE_ARRAY_GETTER_INTRINSIC |
| +#undef DEFINE_ARRAY_SETTER_INTRINSIC |
| - const ICData& value_check = ICData::ZoneHandle(ICData::New( |
| - flow_graph->function(), |
| - String::Handle(flow_graph->function().name()), |
| - Object::empty_array(), // Dummy args. descr. |
| - Thread::kNoDeoptId, |
| - 1, |
| - false)); |
| - value_check.AddReceiverCheck(kDoubleCid, flow_graph->function()); |
| - builder.AddInstruction( |
| - new CheckClassInstr(new Value(value), |
| - Thread::kNoDeoptId, |
| - value_check, |
| - builder.TokenPos())); |
| - Definition* double_value = |
| - builder.AddUnboxInstr(kUnboxedDouble, |
| - new Value(value), |
| - /* is_checked = */ true); |
| - builder.AddInstruction( |
| - new StoreIndexedInstr(new Value(array), |
| - new Value(index), |
| - new Value(double_value), |
| - kNoStoreBarrier, |
| - 8, // index scale |
| - kTypedDataFloat64ArrayCid, |
| - Thread::kNoDeoptId, |
| - builder.TokenPos())); |
| - // Return null. |
| - Definition* null_def = builder.AddNullDefinition(); |
| - builder.AddIntrinsicReturn(new Value(null_def)); |
| - return true; |
| +#define DEFINE_FLOAT_ARRAY_GETTER_INTRINSIC(enum_name) \ |
| +bool Intrinsifier::Build_##enum_name##GetIndexed(FlowGraph* flow_graph) { \ |
| + if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { \ |
| + return false; \ |
| + } \ |
| + return IntrinsifyArrayGetIndexed( \ |
| + flow_graph, \ |
| + MethodRecognizer::MethodKindToCid( \ |
| + MethodRecognizer::k##enum_name##GetIndexed)); \ |
| } |
| -bool Intrinsifier::Build_Float64ArrayGetIndexed(FlowGraph* flow_graph) { |
| - if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { |
| - return false; |
| - } |
| - |
| - GraphEntryInstr* graph_entry = flow_graph->graph_entry(); |
| - TargetEntryInstr* normal_entry = graph_entry->normal_entry(); |
| - BlockBuilder builder(flow_graph, normal_entry); |
| +#define DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC(enum_name) \ |
| +bool Intrinsifier::Build_##enum_name##SetIndexed(FlowGraph* flow_graph) { \ |
| + if (!FlowGraphCompiler::SupportsUnboxedDoubles()) { \ |
| + return false; \ |
| + } \ |
| + return IntrinsifyArraySetIndexed( \ |
| + flow_graph, \ |
| + MethodRecognizer::MethodKindToCid( \ |
| + MethodRecognizer::k##enum_name##SetIndexed)); \ |
| +} |
| - Definition* index = builder.AddParameter(1); |
| - Definition* array = builder.AddParameter(2); |
| +#define DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS(enum_name) \ |
| +DEFINE_FLOAT_ARRAY_GETTER_INTRINSIC(enum_name) \ |
| +DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC(enum_name) |
| - PrepareIndexedOp(&builder, array, index, TypedData::length_offset()); |
| +DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS(Float64Array) |
| +DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS(Float32Array) |
| - Definition* unboxed_value = builder.AddDefinition( |
| - new LoadIndexedInstr(new Value(array), |
| - new Value(index), |
| - 8, // index scale |
| - kTypedDataFloat64ArrayCid, |
| - Thread::kNoDeoptId, |
| - builder.TokenPos())); |
| - Definition* result = builder.AddDefinition( |
| - BoxInstr::Create(kUnboxedDouble, new Value(unboxed_value))); |
| - builder.AddIntrinsicReturn(new Value(result)); |
| - return true; |
| -} |
| +#undef DEFINE_FLOAT_ARRAY_GETTER_SETTER_INTRINSICS |
| +#undef DEFINE_FLOAT_ARRAY_GETTER_INTRINSIC |
| +#undef DEFINE_FLOAT_ARRAY_SETTER_INTRINSIC |
| static bool BuildCodeUnitAt(FlowGraph* flow_graph, intptr_t cid) { |