[vm/compiler] Perform inlining of _TypedList._getX in AOT.

Before, the inliner only replaced calls to the _TypedList._getX methods
with specialized IL if speculation was allowed. This means that the
inlining would not happen in AOT mode, even though the generated IL
does not require speculation.

In addition, this CL replaces the native functions used for the
base definition of _TypedList._getX and _TypedList._setX with
versions built in the FlowGraphBuilder. With this, the VM avoids
the overhead of going to the runtime for a native call when these
methods are not inlined, which should also reduce the impact of
a failure to inline.

TEST=vm/dart/inline_TypedList_getUint32

Issue: https://github.com/dart-lang/sdk/issues/53513
Cq-Include-Trybots: luci.dart.try:vm-aot-linux-debug-simarm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-kernel-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-aot-linux-release-simarm_x64-try,vm-aot-linux-release-x64-try,vm-aot-mac-release-arm64-try,vm-linux-release-x64-try,vm-mac-release-arm64-try,vm-kernel-precomp-linux-release-x64-try
Change-Id: I66b6b8634b2b9b413fb745f02433eb58f2ff913e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/325703
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Tess Strickland
2023-09-25 16:07:17 +00:00
committed by Commit Queue
parent 2887fe0b2c
commit 6673f84d59
13 changed files with 584 additions and 272 deletions
+62 -20
View File
@@ -53,31 +53,73 @@ class FlowGraph {
return env;
}
void dump() {
String formatOne(Map<String, dynamic> instr) {
void _formatInternal(StringBuffer buffer, Map<String, dynamic> instr) {
buffer.write(instr['o']);
if (instr['f'] != null) {
buffer
..write('<')
..write(instr['f'])
..write('>');
}
final attrs = descriptors[instr['o']]
?.attributeIndex
.entries
.map((e) => '${e.key}: ${instr['d'][e.value]}')
.join(',');
if (attrs != null) {
buffer
..write('[')
..write(attrs)
..write(']');
}
final condition = instr['cc'];
if (condition != null) {
buffer.write(' if ');
_formatInternal(buffer, condition);
buffer.write(' then ');
} else {
final inputs = instr['i']?.map((v) => 'v$v').join(', ') ?? '';
final successors = instr['s'] != null ? ' goto ${instr['s']}' : '';
final attrs = descriptors[instr['o']]
?.attributeIndex
.entries
.map((e) => '${e.key}: ${instr['d'][e.value]}')
.join(',');
final condition = instr['cc'] != null ? formatOne(instr['cc']) : '';
final attrsWrapped = attrs != null ? '[$attrs]' : '';
final inputsWrapped =
condition != '' ? ' if $condition then ' : '($inputs)';
return '${instr['o']}$attrsWrapped$inputsWrapped$successors';
buffer
..write('(')
..write(inputs)
..write(')');
}
if (instr['s'] != null) {
buffer
..write(' goto ')
..write(instr['s']);
}
}
for (var block in blocks) {
print('B${block['b']}[${block['o']}]');
for (var instr in [...?block['d'], ...?block['is']]) {
final v = instr['v'] ?? -1;
final prefix = v != -1 ? 'v$v <- ' : '';
print(' ${prefix}${formatOne(instr)}');
}
void formatInstruction(StringBuffer buffer, Map<String, dynamic> instr) {
final v = instr['v'] ?? -1;
final prefix = v != -1 ? 'v$v <- ' : '';
buffer..write(prefix);
_formatInternal(buffer, instr);
}
void _formatBlock(StringBuffer buffer, Map<String, dynamic> block) {
buffer
..write(blockName(block))
..write('[')
..write(block['o'])
..writeln(']');
for (var instr in [...?block['d'], ...?block['is']]) {
buffer.write(' ');
formatInstruction(buffer, instr);
buffer.writeln();
}
}
String blockName(Map<String, dynamic> block) => 'B${block['b']}';
void dump() {
final buffer = StringBuffer();
for (var block in blocks) {
_formatBlock(buffer, block);
}
print(buffer);
}
}
class InstructionDescriptor {
-65
View File
@@ -15,20 +15,6 @@ namespace dart {
// TypedData.
// Checks to see if offsetInBytes + num_bytes is in the range.
static void RangeCheck(intptr_t offset_in_bytes,
intptr_t access_size,
intptr_t length_in_bytes,
intptr_t element_size_in_bytes) {
if (!Utils::RangeCheck(offset_in_bytes, access_size, length_in_bytes)) {
const intptr_t index =
(offset_in_bytes + access_size) / element_size_in_bytes;
const intptr_t length = length_in_bytes / element_size_in_bytes;
Exceptions::ThrowRangeError("index", Integer::Handle(Integer::New(index)),
0, length);
}
}
static void AlignmentCheck(intptr_t offset_in_bytes, intptr_t element_size) {
if ((offset_in_bytes % element_size) != 0) {
const auto& error = String::Handle(String::NewFormatted(
@@ -209,55 +195,4 @@ TYPED_DATA_VIEW_NEW(TypedDataView_UnmodifiableByteDataView_new,
#undef TYPED_DATA_NEW_NATIVE
#undef TYPED_DATA_VIEW_NEW
#define TYPED_DATA_GETTER(getter, object, ctor, access_size) \
DEFINE_NATIVE_ENTRY(TypedData_##getter, 0, 2) { \
GET_NON_NULL_NATIVE_ARGUMENT(TypedDataBase, array, \
arguments->NativeArgAt(0)); \
GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, \
arguments->NativeArgAt(1)); \
RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(), \
access_size); \
return object::ctor(array.getter(offsetInBytes.Value())); \
}
#define TYPED_DATA_SETTER(setter, object, get_object_value, access_size, \
access_type) \
DEFINE_NATIVE_ENTRY(TypedData_##setter, 0, 3) { \
GET_NON_NULL_NATIVE_ARGUMENT(TypedDataBase, array, \
arguments->NativeArgAt(0)); \
GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, \
arguments->NativeArgAt(1)); \
GET_NON_NULL_NATIVE_ARGUMENT(object, value, arguments->NativeArgAt(2)); \
RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(), \
access_size); \
array.setter(offsetInBytes.Value(), \
static_cast<access_type>(value.get_object_value())); \
return Object::null(); \
}
#define TYPED_DATA_NATIVES(type_name, object, ctor, get_object_value, \
access_size, access_type) \
TYPED_DATA_GETTER(Get##type_name, object, ctor, access_size) \
TYPED_DATA_SETTER(Set##type_name, object, get_object_value, access_size, \
access_type)
TYPED_DATA_NATIVES(Int8, Integer, New, AsTruncatedUint32Value, 1, int8_t)
TYPED_DATA_NATIVES(Uint8, Integer, New, AsTruncatedUint32Value, 1, uint8_t)
TYPED_DATA_NATIVES(Int16, Integer, New, AsTruncatedUint32Value, 2, int16_t)
TYPED_DATA_NATIVES(Uint16, Integer, New, AsTruncatedUint32Value, 2, uint16_t)
TYPED_DATA_NATIVES(Int32, Integer, New, AsTruncatedUint32Value, 4, int32_t)
TYPED_DATA_NATIVES(Uint32, Integer, New, AsTruncatedUint32Value, 4, uint32_t)
TYPED_DATA_NATIVES(Int64, Integer, New, AsTruncatedInt64Value, 8, int64_t)
TYPED_DATA_NATIVES(Uint64,
Integer,
NewFromUint64,
AsTruncatedInt64Value,
8,
uint64_t)
TYPED_DATA_NATIVES(Float32, Double, New, value, 4, float)
TYPED_DATA_NATIVES(Float64, Double, New, value, 8, double)
TYPED_DATA_NATIVES(Float32x4, Float32x4, New, value, 16, simd128_value_t)
TYPED_DATA_NATIVES(Int32x4, Int32x4, New, value, 16, simd128_value_t)
TYPED_DATA_NATIVES(Float64x2, Float64x2, New, value, 16, simd128_value_t)
} // namespace dart
@@ -0,0 +1,206 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Verifies that compiler inlines _TypedList._getX when indexing into views
// using a trimmed version of runtime/tools/heapsnapshot/lib/src/analysis.dart.
// See dartbug.com/53513.
import 'dart:typed_data';
import 'package:expect/expect.dart';
import 'package:vm/testing/il_matchers.dart';
import 'package:vm_service/vm_service.dart';
import '../../../tools/heapsnapshot/lib/src/format.dart';
import '../../../tools/heapsnapshot/lib/src/intset.dart';
const int _invalidIdx = 0;
const int _rootObjectIdx = 1;
class Analysis {
final HeapSnapshotGraph graph;
late final reachableObjects = transitiveGraph(roots);
late final Uint32List _retainers = _calculateRetainers();
late final _oneByteStringCid = _findClassId('_OneByteString');
late final _twoByteStringCid = _findClassId('_TwoByteString');
late final _nonGrowableListCid = _findClassId('_List');
late final _immutableListCid = _findClassId('_ImmutableList');
late final _weakPropertyCid = _findClassId('_WeakProperty');
late final _weakReferenceCid = _findClassId('_WeakReference');
late final _patchClassCid = _findClassId('PatchClass');
late final _finalizerEntryCid = _findClassId('FinalizerEntry');
late final _weakPropertyKeyIdx = _findFieldIndex(_weakPropertyCid, 'key_');
late final _weakPropertyValueIdx =
_findFieldIndex(_weakPropertyCid, 'value_');
late final _finalizerEntryDetachIdx =
_findFieldIndex(_finalizerEntryCid, 'detach_');
late final _finalizerEntryValueIdx =
_findFieldIndex(_finalizerEntryCid, 'value_');
late final int _headerSize = 4;
late final int _wordSize = 4;
Analysis(this.graph) {}
/// The roots from which alive data can be discovered.
final IntSet roots = IntSet()..add(_rootObjectIdx);
/// Calculates the set of objects transitively reachable by [roots].
IntSet transitiveGraph(IntSet roots) {
final objects = graph.objects;
final reachable = SpecializedIntSet(objects.length);
final worklist = <int>[];
reachable.addAll(roots);
worklist.addAll(roots);
final weakProperties = IntSet();
while (worklist.isNotEmpty) {
while (worklist.isNotEmpty) {
final objectIdToExpand = worklist.removeLast();
final objectToExpand = objects[objectIdToExpand];
final cid = objectToExpand.classId;
// Weak references don't keep their value alive.
if (cid == _weakReferenceCid) continue;
// Weak properties keep their value alive if the key is alive.
if (cid == _weakPropertyCid) {
weakProperties.add(objectIdToExpand);
continue;
}
// Normal object (or FinalizerEntry).
final references = objectToExpand.references;
final bool isFinalizerEntry = cid == _finalizerEntryCid;
for (int i = 0; i < references.length; ++i) {
// [FinalizerEntry] objects don't keep their "detach" and "value"
// fields alive.
if (isFinalizerEntry &&
(i == _finalizerEntryDetachIdx || i == _finalizerEntryValueIdx)) {
continue;
}
final successor = references[i];
if (!reachable.contains(successor)) {
reachable.add(successor);
worklist.add(successor);
}
}
}
// Enqueue values of weak properties if their key is alive.
weakProperties.removeWhere((int weakProperty) {
final wpReferences = objects[weakProperty].references;
final keyId = wpReferences[_weakPropertyKeyIdx];
final valueId = wpReferences[_weakPropertyValueIdx];
if (reachable.contains(keyId)) {
if (!reachable.contains(valueId)) {
reachable.add(valueId);
worklist.add(valueId);
}
return true;
}
return false;
});
}
return reachable;
}
int _findClassId(String className) {
return graph.classes
.singleWhere((klass) =>
klass.name == className &&
(klass.libraryUri.scheme == 'dart' ||
klass.libraryUri.toString() == ''))
.classId;
}
int _findFieldIndex(int cid, String fieldName) {
return graph.classes[cid].fields
.singleWhere((f) => f.name == fieldName)
.index;
}
@pragma('vm:testing:print-flow-graph')
Uint32List _calculateRetainers() {
final retainers = Uint32List(graph.objects.length);
var worklist = IntSet()..add(_rootObjectIdx);
while (!worklist.isEmpty) {
final next = IntSet();
for (final objId in worklist) {
final object = graph.objects[objId];
final cid = object.classId;
// Weak references don't keep their value alive.
if (cid == _weakReferenceCid) continue;
// Weak properties keep their value alive if the key is alive.
if (cid == _weakPropertyCid) {
final valueId = object.references[_weakPropertyValueIdx];
if (reachableObjects.contains(valueId)) {
if (retainers[valueId] == 0) {
retainers[valueId] = objId;
next.add(valueId);
}
}
continue;
}
// Normal object (or FinalizerEntry).
final references = object.references;
final bool isFinalizerEntry = cid == _finalizerEntryCid;
for (int i = 0; i < references.length; ++i) {
// [FinalizerEntry] objects don't keep their "detach" and "value"
// fields alive.
if (isFinalizerEntry &&
(i == _finalizerEntryDetachIdx || i == _finalizerEntryValueIdx)) {
continue;
}
final refId = references[i];
if (retainers[refId] == 0) {
retainers[refId] = objId;
next.add(refId);
}
}
}
worklist = next;
}
return retainers;
}
}
void matchIL$_calculateRetainers(FlowGraph graph) {
graph.dump();
for (var block in graph.blocks) {
for (var instr in [...?block['d'], ...?block['is']]) {
final function = instr['f'] as String?;
if (function == null) continue;
if (!function.endsWith('_getUint32')) continue;
final buffer = StringBuffer();
buffer
..write('Found uninlined call to _getUint32 in block ')
..write(graph.blockName(block))
..writeln(':')
..write(' ');
graph.formatInstruction(buffer, instr);
throw buffer;
}
}
}
void main() {
// To ensure _calculateRetainers is compiled.
Expect.throws(() => Analysis(HeapSnapshotGraph.fromChunks(<ByteData>[]))
._retainers[_rootObjectIdx]);
}
-26
View File
@@ -174,32 +174,6 @@ namespace dart {
V(TypedData_Float64x2Array_new, 2) \
V(TypedDataBase_length, 1) \
V(TypedDataBase_setClampedRange, 5) \
V(TypedData_GetInt8, 2) \
V(TypedData_SetInt8, 3) \
V(TypedData_GetUint8, 2) \
V(TypedData_SetUint8, 3) \
V(TypedData_GetInt16, 2) \
V(TypedData_SetInt16, 3) \
V(TypedData_GetUint16, 2) \
V(TypedData_SetUint16, 3) \
V(TypedData_GetInt32, 2) \
V(TypedData_SetInt32, 3) \
V(TypedData_GetUint32, 2) \
V(TypedData_SetUint32, 3) \
V(TypedData_GetInt64, 2) \
V(TypedData_SetInt64, 3) \
V(TypedData_GetUint64, 2) \
V(TypedData_SetUint64, 3) \
V(TypedData_GetFloat32, 2) \
V(TypedData_SetFloat32, 3) \
V(TypedData_GetFloat64, 2) \
V(TypedData_SetFloat64, 3) \
V(TypedData_GetFloat32x4, 2) \
V(TypedData_SetFloat32x4, 3) \
V(TypedData_GetInt32x4, 2) \
V(TypedData_SetInt32x4, 3) \
V(TypedData_GetFloat64x2, 2) \
V(TypedData_SetFloat64x2, 3) \
V(TypedDataView_ByteDataView_new, 4) \
V(TypedDataView_Int8ArrayView_new, 4) \
V(TypedDataView_Uint8ArrayView_new, 4) \
@@ -167,6 +167,10 @@ class IlTestPrinter : public AllStatic {
AttributesSerializer serializer(writer);
instr->Accept(&serializer);
}
if (auto* const call = instr->AsStaticCall()) {
writer->PrintProperty("f",
call->function().QualifiedUserVisibleNameCString());
}
if (instr->SuccessorCount() > 0) {
writer->OpenArray("s");
for (auto succ : instr->successors()) {
+4 -2
View File
@@ -74,7 +74,9 @@ class TestPipeline : public ValueObject {
public:
explicit TestPipeline(const Function& function,
CompilerPass::PipelineMode mode,
bool is_optimizing = true)
bool is_optimizing = true,
bool enable_suppression = false,
intptr_t retry_limit = -1)
: function_(function),
thread_(Thread::Current()),
compiler_state_(thread_,
@@ -82,7 +84,7 @@ class TestPipeline : public ValueObject {
is_optimizing,
CompilerState::ShouldTrace(function)),
speculative_policy_(std::unique_ptr<SpeculativeInliningPolicy>(
new SpeculativeInliningPolicy(/*enable_suppresson=*/false))),
new SpeculativeInliningPolicy(enable_suppression, retry_limit))),
mode_(mode) {}
~TestPipeline() { delete pass_state_; }
+78 -82
View File
@@ -3188,6 +3188,9 @@ static void PrepareInlineByteArrayBaseOp(FlowGraph* flow_graph,
}
}
// Emits the specialized code for a typed getter, using the compile-time type
// information to determine whether the receiver payload must be retrieved
// first or not.
static bool InlineByteArrayBaseLoad(FlowGraph* flow_graph,
Definition* call,
Definition* receiver,
@@ -3244,19 +3247,9 @@ static bool InlineByteArrayBaseLoad(FlowGraph* flow_graph,
return true;
}
static StoreIndexedInstr* NewStore(FlowGraph* flow_graph,
Instruction* call,
Definition* array,
Definition* index,
Definition* stored_value,
intptr_t view_cid) {
return new (Z) StoreIndexedInstr(
new (Z) Value(array), new (Z) Value(index), new (Z) Value(stored_value),
kNoStoreBarrier, /*index_unboxed=*/false,
/*index_scale=*/1, view_cid, kUnalignedAccess, call->deopt_id(),
call->source());
}
// Emits the specialized code for a typed setter, using the compile-time type
// information to determine whether the receiver payload must be retrieved
// first or not.
static bool InlineByteArrayBaseStore(FlowGraph* flow_graph,
const Function& target,
Instruction* call,
@@ -3449,8 +3442,11 @@ static bool InlineByteArrayBaseStore(FlowGraph* flow_graph,
// Fill out the generated template with stores.
{
// Store on either external or internal.
StoreIndexedInstr* store =
NewStore(flow_graph, call, array, index, stored_value, view_cid);
StoreIndexedInstr* store = new (Z) StoreIndexedInstr(
new (Z) Value(array), new (Z) Value(index), new (Z) Value(stored_value),
kNoStoreBarrier, /*index_unboxed=*/false,
/*index_scale=*/1, view_cid, kUnalignedAccess, call->deopt_id(),
call->source());
flow_graph->AppendTo(
cursor, store,
call->deopt_id() != DeoptId::kNone ? call->env() : nullptr,
@@ -4002,6 +3998,73 @@ bool FlowGraphInliner::TryInlineRecognizedMethod(
case MethodRecognizer::kUint64ArrayGetIndexed:
return InlineGetIndexed(flow_graph, can_speculate, is_dynamic_call, kind,
call, receiver, graph_entry, entry, last, result);
case MethodRecognizer::kByteArrayBaseGetInt8:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataInt8ArrayCid, graph_entry, entry,
last, result);
case MethodRecognizer::kByteArrayBaseGetUint8:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataUint8ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetInt16:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataInt16ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetUint16:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataUint16ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetInt32:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataInt32ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetUint32:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataUint32ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetInt64:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataInt64ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetUint64:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataUint64ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetFloat32:
if (!CanUnboxDouble()) {
return false;
}
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataFloat32ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetFloat64:
if (!CanUnboxDouble()) {
return false;
}
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataFloat64ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetFloat32x4:
if (!ShouldInlineSimd()) {
return false;
}
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataFloat32x4ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetFloat64x2:
if (!ShouldInlineSimd()) {
return false;
}
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataFloat64x2ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetInt32x4:
if (!ShouldInlineSimd()) {
return false;
}
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataInt32x4ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kClassIDgetID:
return InlineLoadClassId(flow_graph, call, graph_entry, entry, last,
result);
@@ -4082,73 +4145,6 @@ bool FlowGraphInliner::TryInlineRecognizedMethod(
value_check, exactness, graph_entry, entry, last,
result);
}
case MethodRecognizer::kByteArrayBaseGetInt8:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataInt8ArrayCid, graph_entry, entry,
last, result);
case MethodRecognizer::kByteArrayBaseGetUint8:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataUint8ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetInt16:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataInt16ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetUint16:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataUint16ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetInt32:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataInt32ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetUint32:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataUint32ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetInt64:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataInt64ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetUint64:
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataUint64ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetFloat32:
if (!CanUnboxDouble()) {
return false;
}
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataFloat32ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetFloat64:
if (!CanUnboxDouble()) {
return false;
}
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataFloat64ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetFloat32x4:
if (!ShouldInlineSimd()) {
return false;
}
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataFloat32x4ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetFloat64x2:
if (!ShouldInlineSimd()) {
return false;
}
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataFloat64x2ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseGetInt32x4:
if (!ShouldInlineSimd()) {
return false;
}
return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
kTypedDataInt32x4ArrayCid, graph_entry,
entry, last, result);
case MethodRecognizer::kByteArrayBaseSetInt8:
return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
receiver_cid, kTypedDataInt8ArrayCid,
@@ -920,6 +920,32 @@ bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph(
const MethodRecognizer::Kind kind = function.recognized_kind();
switch (kind) {
case MethodRecognizer::kByteArrayBaseGetInt8:
case MethodRecognizer::kByteArrayBaseGetUint8:
case MethodRecognizer::kByteArrayBaseGetInt16:
case MethodRecognizer::kByteArrayBaseGetUint16:
case MethodRecognizer::kByteArrayBaseGetInt32:
case MethodRecognizer::kByteArrayBaseGetUint32:
case MethodRecognizer::kByteArrayBaseGetInt64:
case MethodRecognizer::kByteArrayBaseGetUint64:
case MethodRecognizer::kByteArrayBaseGetFloat32:
case MethodRecognizer::kByteArrayBaseGetFloat64:
case MethodRecognizer::kByteArrayBaseGetFloat32x4:
case MethodRecognizer::kByteArrayBaseGetFloat64x2:
case MethodRecognizer::kByteArrayBaseGetInt32x4:
case MethodRecognizer::kByteArrayBaseSetInt8:
case MethodRecognizer::kByteArrayBaseSetUint8:
case MethodRecognizer::kByteArrayBaseSetInt16:
case MethodRecognizer::kByteArrayBaseSetUint16:
case MethodRecognizer::kByteArrayBaseSetInt32:
case MethodRecognizer::kByteArrayBaseSetUint32:
case MethodRecognizer::kByteArrayBaseSetInt64:
case MethodRecognizer::kByteArrayBaseSetUint64:
case MethodRecognizer::kByteArrayBaseSetFloat32:
case MethodRecognizer::kByteArrayBaseSetFloat64:
case MethodRecognizer::kByteArrayBaseSetFloat32x4:
case MethodRecognizer::kByteArrayBaseSetFloat64x2:
case MethodRecognizer::kByteArrayBaseSetInt32x4:
case MethodRecognizer::kRecord_fieldAt:
case MethodRecognizer::kRecord_fieldNames:
case MethodRecognizer::kRecord_numFields:
@@ -1098,6 +1124,27 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
const MethodRecognizer::Kind kind = function.recognized_kind();
switch (kind) {
#define BYTE_ARRAY_BASE_OPS(Type) \
case MethodRecognizer::kByteArrayBaseGet##Type: \
body += BuildByteArrayBaseLoad(function, kTypedData##Type##ArrayCid); \
break; \
case MethodRecognizer::kByteArrayBaseSet##Type: \
body += BuildByteArrayBaseStore(function, kTypedData##Type##ArrayCid); \
break;
BYTE_ARRAY_BASE_OPS(Int8)
BYTE_ARRAY_BASE_OPS(Uint8)
BYTE_ARRAY_BASE_OPS(Int16)
BYTE_ARRAY_BASE_OPS(Uint16)
BYTE_ARRAY_BASE_OPS(Int32)
BYTE_ARRAY_BASE_OPS(Uint32)
BYTE_ARRAY_BASE_OPS(Int64)
BYTE_ARRAY_BASE_OPS(Uint64)
BYTE_ARRAY_BASE_OPS(Float32)
BYTE_ARRAY_BASE_OPS(Float64)
BYTE_ARRAY_BASE_OPS(Float32x4)
BYTE_ARRAY_BASE_OPS(Float64x2)
BYTE_ARRAY_BASE_OPS(Int32x4)
#undef BYTE_ARRAY_BASE_OPS
case MethodRecognizer::kRecord_fieldAt:
ASSERT_EQUAL(function.NumParameters(), 2);
body += LoadLocal(parsed_function_->RawParameterVariable(0));
@@ -1753,6 +1800,56 @@ Fragment FlowGraphBuilder::BuildTypedDataViewFactoryConstructor(
return body;
}
Fragment FlowGraphBuilder::BuildByteArrayBaseLoad(const Function& function,
intptr_t view_cid) {
ASSERT_EQUAL(parsed_function_->function().NumParameters(), 2);
// Guaranteed to be non-null since it's only called internally from other
// instance methods.
LocalVariable* arg_receiver = parsed_function_->RawParameterVariable(0);
// Guaranteed to be a non-null Smi due to bounds checks prior to call.
LocalVariable* arg_index = parsed_function_->RawParameterVariable(1);
Fragment body;
body += LoadLocal(arg_receiver);
body += LoadUntagged(compiler::target::PointerBase::data_offset());
body += LoadLocal(arg_index);
body += LoadIndexed(view_cid, /*index_scale=*/1,
/*index_unboxed=*/false, kUnalignedAccess);
body += Box(LoadIndexedInstr::RepresentationOfArrayElement(view_cid));
return body;
}
Fragment FlowGraphBuilder::BuildByteArrayBaseStore(const Function& function,
intptr_t view_cid) {
ASSERT_EQUAL(parsed_function_->function().NumParameters(), 3);
// Guaranteed to be non-null since it's only called internally from other
// instance methods.
LocalVariable* arg_receiver = parsed_function_->RawParameterVariable(0);
// Guaranteed to be a non-null Smi due to bounds checks prior to call.
LocalVariable* arg_index = parsed_function_->RawParameterVariable(1);
LocalVariable* arg_value = parsed_function_->RawParameterVariable(2);
Fragment body;
// We check the argument for null before untagging the receiver to avoid
// the untagged payload address being on the stack during deoptimization,
// so this value needs to be dropped after the StoreIndexed instruction.
body += LoadLocal(arg_value);
body += CheckNullOptimized(Symbols::Value(), CheckNullInstr::kArgumentError);
LocalVariable* checked_value = MakeTemporary("value");
body += LoadLocal(arg_receiver);
body += LoadUntagged(compiler::target::PointerBase::data_offset());
body += LoadLocal(arg_index);
body += LoadLocal(checked_value);
body +=
UnboxTruncate(StoreIndexedInstr::RepresentationOfArrayElement(view_cid));
body += StoreIndexedTypedData(view_cid, /*index_scale=*/1,
/*index_unboxed=*/false, kUnalignedAccess);
body += DropTemporary(&checked_value);
body += NullConstant();
return body;
}
Fragment FlowGraphBuilder::BuildTypedDataMemMove(const Function& function,
intptr_t cid) {
ASSERT_EQUAL(parsed_function_->function().NumParameters(), 5);
@@ -146,6 +146,9 @@ class FlowGraphBuilder : public BaseFlowGraphBuilder {
FlowGraph* BuildGraphOfRecognizedMethod(const Function& function);
Fragment BuildByteArrayBaseLoad(const Function& function, intptr_t view_cid);
Fragment BuildByteArrayBaseStore(const Function& function, intptr_t view_cid);
Fragment BuildTypedDataMemMove(const Function& function, intptr_t cid);
Fragment BuildTypedDataViewFactoryConstructor(const Function& function,
classid_t cid);
+50 -50
View File
@@ -23,32 +23,32 @@ namespace dart {
V(_Record, get:_numFields, Record_numFields, 0x7bb37f73) \
V(_Record, get:_shape, Record_shape, 0x70d29513) \
V(_Record, _fieldAt, Record_fieldAt, 0xb48e2c93) \
V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0x16155054) \
V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0x1771724a) \
V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0x2e320a6f) \
V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 0x2fb36ad9) \
V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 0x1909a12a) \
V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 0x194ee29b) \
V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 0xf652341f) \
V(_TypedList, _getUint64, ByteArrayBaseGetUint64, 0x2c4ced79) \
V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 0xe8e81527) \
V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 0xf81baa54) \
V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 0xaf1e8105) \
V(_TypedList, _getFloat64x2, ByteArrayBaseGetFloat64x2, 0x544ea0e0) \
V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 0x5564e82b) \
V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 0xe17ab7c2) \
V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 0xaf4b2b68) \
V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 0xbad7b447) \
V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 0xce13bc6f) \
V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 0xbdcc1f60) \
V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 0xb95817d2) \
V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 0xc8bec39a) \
V(_TypedList, _setUint64, ByteArrayBaseSetUint64, 0xda38a625) \
V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 0x2f27a200) \
V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0x234b6cf2) \
V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x38b79d7a) \
V(_TypedList, _setFloat64x2, ByteArrayBaseSetFloat64x2, 0xbadc4b5f) \
V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0x5cda767b) \
V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0x16155415) \
V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0x1771760b) \
V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0x2e320e30) \
V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 0x2fb36e9a) \
V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 0x1909a4eb) \
V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 0x194ee65c) \
V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 0xf65237e0) \
V(_TypedList, _getUint64, ByteArrayBaseGetUint64, 0x2c4cf13a) \
V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 0xe8e818e8) \
V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 0xf81bae15) \
V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 0xaf1e84c6) \
V(_TypedList, _getFloat64x2, ByteArrayBaseGetFloat64x2, 0x544ea4a1) \
V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 0x5564ebec) \
V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 0xe17abb83) \
V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 0xaf4b2f29) \
V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 0xbad7b808) \
V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 0xce13c030) \
V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 0xbdcc2321) \
V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 0xb9581b93) \
V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 0xc8bec75b) \
V(_TypedList, _setUint64, ByteArrayBaseSetUint64, 0xda38a9e6) \
V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 0x2f27a5c1) \
V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0x234b70b3) \
V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x38b7a13b) \
V(_TypedList, _setFloat64x2, ByteArrayBaseSetFloat64x2, 0xbadc4f20) \
V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0x5cda7a3c) \
V(ByteData, ., ByteDataFactory, 0x45e89423) \
V(_ByteDataView, get:offsetInBytes, ByteDataViewOffsetInBytes, 0x60c0664c) \
V(_ByteDataView, get:_typedData, ByteDataViewTypedData, 0xb9c2d41a) \
@@ -503,30 +503,30 @@ namespace dart {
// A list of core functions that internally dispatch based on received id.
#define POLYMORPHIC_TARGET_LIST(V) \
V(_StringBase, [], StringBaseCharAt, 0xd0613adf) \
V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0x16155054) \
V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0x1771724a) \
V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0x2e320a6f) \
V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 0x2fb36ad9) \
V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 0x1909a12a) \
V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 0x194ee29b) \
V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 0xf652341f) \
V(_TypedList, _getUint64, ByteArrayBaseGetUint64, 0x2c4ced79) \
V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 0xe8e81527) \
V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 0xf81baa54) \
V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 0xaf1e8105) \
V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 0x5564e82b) \
V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 0xe17ab7c2) \
V(_TypedList, _setUint8, ByteArrayBaseSetInt8, 0xaf4b2b68) \
V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 0xbad7b447) \
V(_TypedList, _setUint16, ByteArrayBaseSetInt16, 0xce13bc6f) \
V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 0xbdcc1f60) \
V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 0xb95817d2) \
V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 0xc8bec39a) \
V(_TypedList, _setUint64, ByteArrayBaseSetUint64, 0xda38a625) \
V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 0x2f27a200) \
V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0x234b6cf2) \
V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x38b79d7a) \
V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0x5cda767b) \
V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0x16155415) \
V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0x1771760b) \
V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0x2e320e30) \
V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 0x2fb36e9a) \
V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 0x1909a4eb) \
V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 0x194ee65c) \
V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 0xf65237e0) \
V(_TypedList, _getUint64, ByteArrayBaseGetUint64, 0x2c4cf13a) \
V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 0xe8e818e8) \
V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 0xf81bae15) \
V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 0xaf1e84c6) \
V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 0x5564ebec) \
V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 0xe17abb83) \
V(_TypedList, _setUint8, ByteArrayBaseSetInt8, 0xaf4b2f29) \
V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 0xbad7b808) \
V(_TypedList, _setUint16, ByteArrayBaseSetInt16, 0xce13c030) \
V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 0xbdcc2321) \
V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 0xb9581b93) \
V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 0xc8bec75b) \
V(_TypedList, _setUint64, ByteArrayBaseSetUint64, 0xda38a9e6) \
V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 0x2f27a5c1) \
V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0x234b70b3) \
V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x38b7a13b) \
V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0x5cda7a3c) \
V(Object, get:runtimeType, ObjectRuntimeType, 0x03733c71)
// List of recognized list factories:
+2 -1
View File
@@ -1140,7 +1140,8 @@ void DeoptInfoBuilder::AddCopy(Value* value,
ToFpuRegisterSource(source_loc, Location::kQuadStackSlot));
break;
default:
UNREACHABLE();
FATAL("Unexpected representation: %s",
Location::RepresentationToCString(rep));
break;
}
}
+26
View File
@@ -9054,6 +9054,32 @@ bool Function::IsIdempotent() const {
bool Function::RecognizedKindForceOptimize() const {
switch (recognized_kind()) {
// Uses unboxed/untagged data not supported in unoptimized.
case MethodRecognizer::kByteArrayBaseGetInt8:
case MethodRecognizer::kByteArrayBaseGetUint8:
case MethodRecognizer::kByteArrayBaseGetInt16:
case MethodRecognizer::kByteArrayBaseGetUint16:
case MethodRecognizer::kByteArrayBaseGetInt32:
case MethodRecognizer::kByteArrayBaseGetUint32:
case MethodRecognizer::kByteArrayBaseGetInt64:
case MethodRecognizer::kByteArrayBaseGetUint64:
case MethodRecognizer::kByteArrayBaseGetFloat32:
case MethodRecognizer::kByteArrayBaseGetFloat64:
case MethodRecognizer::kByteArrayBaseGetFloat32x4:
case MethodRecognizer::kByteArrayBaseGetFloat64x2:
case MethodRecognizer::kByteArrayBaseGetInt32x4:
case MethodRecognizer::kByteArrayBaseSetInt8:
case MethodRecognizer::kByteArrayBaseSetUint8:
case MethodRecognizer::kByteArrayBaseSetInt16:
case MethodRecognizer::kByteArrayBaseSetUint16:
case MethodRecognizer::kByteArrayBaseSetInt32:
case MethodRecognizer::kByteArrayBaseSetUint32:
case MethodRecognizer::kByteArrayBaseSetInt64:
case MethodRecognizer::kByteArrayBaseSetUint64:
case MethodRecognizer::kByteArrayBaseSetFloat32:
case MethodRecognizer::kByteArrayBaseSetFloat64:
case MethodRecognizer::kByteArrayBaseSetFloat32x4:
case MethodRecognizer::kByteArrayBaseSetFloat64x2:
case MethodRecognizer::kByteArrayBaseSetInt32x4:
case MethodRecognizer::kFinalizerBase_getIsolateFinalizers:
case MethodRecognizer::kFinalizerBase_setIsolate:
case MethodRecognizer::kFinalizerBase_setIsolateFinalizers:
+52 -26
View File
@@ -2051,102 +2051,128 @@ abstract final class _TypedList extends _TypedListBase {
@pragma("vm:recognized", "other")
@pragma("vm:exact-result-type", "dart:core#_Smi")
@pragma("vm:external-name", "TypedData_GetInt8")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external int _getInt8(int offsetInBytes);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_SetInt8")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external void _setInt8(int offsetInBytes, int value);
@pragma("vm:recognized", "other")
@pragma("vm:exact-result-type", "dart:core#_Smi")
@pragma("vm:external-name", "TypedData_GetUint8")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external int _getUint8(int offsetInBytes);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_SetUint8")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external void _setUint8(int offsetInBytes, int value);
@pragma("vm:recognized", "other")
@pragma("vm:exact-result-type", "dart:core#_Smi")
@pragma("vm:external-name", "TypedData_GetInt16")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external int _getInt16(int offsetInBytes);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_SetInt16")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external void _setInt16(int offsetInBytes, int value);
@pragma("vm:recognized", "other")
@pragma("vm:exact-result-type", "dart:core#_Smi")
@pragma("vm:external-name", "TypedData_GetUint16")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external int _getUint16(int offsetInBytes);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_SetUint16")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external void _setUint16(int offsetInBytes, int value);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_GetInt32")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external int _getInt32(int offsetInBytes);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_SetInt32")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external void _setInt32(int offsetInBytes, int value);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_GetUint32")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external int _getUint32(int offsetInBytes);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_SetUint32")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external void _setUint32(int offsetInBytes, int value);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_GetInt64")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external int _getInt64(int offsetInBytes);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_SetInt64")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external void _setInt64(int offsetInBytes, int value);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_GetUint64")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external int _getUint64(int offsetInBytes);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_SetUint64")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external void _setUint64(int offsetInBytes, int value);
@pragma("vm:recognized", "other")
@pragma("vm:exact-result-type", "dart:core#_Double")
@pragma("vm:external-name", "TypedData_GetFloat32")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external double _getFloat32(int offsetInBytes);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_SetFloat32")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external void _setFloat32(int offsetInBytes, double value);
@pragma("vm:recognized", "other")
@pragma("vm:exact-result-type", "dart:core#_Double")
@pragma("vm:external-name", "TypedData_GetFloat64")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external double _getFloat64(int offsetInBytes);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_SetFloat64")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external void _setFloat64(int offsetInBytes, double value);
@pragma("vm:recognized", "other")
@pragma("vm:exact-result-type", _Float32x4)
@pragma("vm:external-name", "TypedData_GetFloat32x4")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external Float32x4 _getFloat32x4(int offsetInBytes);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_SetFloat32x4")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external void _setFloat32x4(int offsetInBytes, Float32x4 value);
@pragma("vm:recognized", "other")
@pragma("vm:exact-result-type", _Int32x4)
@pragma("vm:external-name", "TypedData_GetInt32x4")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external Int32x4 _getInt32x4(int offsetInBytes);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_SetInt32x4")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external void _setInt32x4(int offsetInBytes, Int32x4 value);
@pragma("vm:recognized", "other")
@pragma("vm:exact-result-type", _Float64x2)
@pragma("vm:external-name", "TypedData_GetFloat64x2")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external Float64x2 _getFloat64x2(int offsetInBytes);
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "TypedData_SetFloat64x2")
@pragma("vm:idempotent")
@pragma("vm:prefer-inline")
external void _setFloat64x2(int offsetInBytes, Float64x2 value);
/**