Index: runtime/vm/intrinsifier.cc |
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc |
index 15a0fa9275c5e0ae839856f01ee82d33846147c6..93478fc3d866fe8569d7397034f129e31ff5d4ed 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. |
+ 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)); |
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::MethodKindToReceiverCid( \ |
+ 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::MethodKindToReceiverCid( \ |
+ 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::MethodKindToReceiverCid( \ |
+ 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::MethodKindToReceiverCid( \ |
+ 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) { |