| 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) {
|
|
|