mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[vm/ffi] Update inner pointer accesses in IL
FFI loads and stores via structs can have a TypedData as receiver, so this CL updates those loads to `kMayBeInnerPointer`. This CL adds an IL test to verify that for `Pointer` loads the untagged value is treated correctly as `kCannotBeInnerPointer`. (And adds some prefer-inline pragmas to make some common operations be inlined to avoid allocating `Pointer` objects.) This CL updates the load in the FFI closures to use a load-field. This can also potentially enable not allocating a pointer object when this closure is inlined. TEST=tests/ffi/unwrap_typeddata_generated_test.dart TEST=tests/ffi CoreLibraryReviewExempt: Only adding some pragmas. Change-Id: If687e54c676f275cc849b3fed526a13766ab331a Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-x64-try,vm-kernel-linux-debug-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-release-ia32-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/349241 Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
bf683bacbb
commit
c0c7c1ef49
|
@ -237,6 +237,7 @@ $platform$truncate$alignment external void operator []=(int index, $dartType va
|
||||||
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
||||||
/// and similarly for setting.
|
/// and similarly for setting.
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<$nativeType> operator +(int offset) => Pointer.fromAddress(address + sizeOf<$nativeType>() * offset);
|
Pointer<$nativeType> operator +(int offset) => Pointer.fromAddress(address + sizeOf<$nativeType>() * offset);
|
||||||
|
|
||||||
/// A pointer to the [offset]th [$nativeType] before this one.
|
/// A pointer to the [offset]th [$nativeType] before this one.
|
||||||
|
@ -250,6 +251,7 @@ $platform$truncate$alignment external void operator []=(int index, $dartType va
|
||||||
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
||||||
/// and similarly for setting,
|
/// and similarly for setting,
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<$nativeType> operator -(int offset) => Pointer.fromAddress(address - sizeOf<$nativeType>() * offset);
|
Pointer<$nativeType> operator -(int offset) => Pointer.fromAddress(address - sizeOf<$nativeType>() * offset);
|
||||||
|
|
||||||
$asTypedList
|
$asTypedList
|
||||||
|
@ -308,15 +310,19 @@ void generatePatchExtension(
|
||||||
@patch
|
@patch
|
||||||
extension ${nativeType}Pointer on Pointer<$nativeType> {
|
extension ${nativeType}Pointer on Pointer<$nativeType> {
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
$dartType get value => _load$nativeType(this, 0);
|
$dartType get value => _load$nativeType(this, 0);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
set value($dartType value) => _store$nativeType(this, 0, value);
|
set value($dartType value) => _store$nativeType(this, 0, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
$dartType operator [](int index) => _load$nativeType(this, ${sizeTimes}index);
|
$dartType operator [](int index) => _load$nativeType(this, ${sizeTimes}index);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
operator []=(int index, $dartType value) => _store$nativeType(this, ${sizeTimes}index, value);
|
operator []=(int index, $dartType value) => _store$nativeType(this, ${sizeTimes}index, value);
|
||||||
|
|
||||||
$asTypedList
|
$asTypedList
|
||||||
|
|
|
@ -1648,8 +1648,10 @@ Fragment StreamingFlowGraphBuilder::AllocateContext(
|
||||||
return flow_graph_builder_->AllocateContext(context_slots);
|
return flow_graph_builder_->AllocateContext(context_slots);
|
||||||
}
|
}
|
||||||
|
|
||||||
Fragment StreamingFlowGraphBuilder::LoadNativeField(const Slot& field) {
|
Fragment StreamingFlowGraphBuilder::LoadNativeField(
|
||||||
return flow_graph_builder_->LoadNativeField(field);
|
const Slot& field,
|
||||||
|
InnerPointerAccess loads_inner_pointer) {
|
||||||
|
return flow_graph_builder_->LoadNativeField(field, loads_inner_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Fragment StreamingFlowGraphBuilder::StoreLocal(TokenPosition position,
|
Fragment StreamingFlowGraphBuilder::StoreLocal(TokenPosition position,
|
||||||
|
@ -6241,8 +6243,9 @@ Fragment StreamingFlowGraphBuilder::BuildFfiCall() {
|
||||||
Fragment code;
|
Fragment code;
|
||||||
// Push the target function pointer passed as Pointer object.
|
// Push the target function pointer passed as Pointer object.
|
||||||
code += BuildExpression();
|
code += BuildExpression();
|
||||||
// This can only be Pointer, so it is always safe to LoadUntagged.
|
// This can only be Pointer, so the data field points to unmanaged memory.
|
||||||
code += B->LoadUntagged(compiler::target::PointerBase::data_offset());
|
code += LoadNativeField(Slot::PointerBase_data(),
|
||||||
|
InnerPointerAccess::kCannotBeInnerPointer);
|
||||||
code += B->ConvertUntaggedToUnboxed(kUnboxedFfiIntPtr);
|
code += B->ConvertUntaggedToUnboxed(kUnboxedFfiIntPtr);
|
||||||
|
|
||||||
// Skip (empty) named arguments list.
|
// Skip (empty) named arguments list.
|
||||||
|
|
|
@ -215,7 +215,9 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper {
|
||||||
const Class& klass,
|
const Class& klass,
|
||||||
intptr_t argument_count);
|
intptr_t argument_count);
|
||||||
Fragment AllocateContext(const ZoneGrowableArray<const Slot*>& context_slots);
|
Fragment AllocateContext(const ZoneGrowableArray<const Slot*>& context_slots);
|
||||||
Fragment LoadNativeField(const Slot& field);
|
Fragment LoadNativeField(const Slot& field,
|
||||||
|
InnerPointerAccess loads_inner_pointer =
|
||||||
|
InnerPointerAccess::kNotUntagged);
|
||||||
Fragment StoreLocal(TokenPosition position, LocalVariable* variable);
|
Fragment StoreLocal(TokenPosition position, LocalVariable* variable);
|
||||||
Fragment StoreStaticField(TokenPosition position, const Field& field);
|
Fragment StoreStaticField(TokenPosition position, const Field& field);
|
||||||
Fragment StringInterpolate(TokenPosition position);
|
Fragment StringInterpolate(TokenPosition position);
|
||||||
|
|
|
@ -1453,18 +1453,20 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
|
||||||
compiler::ffi::ElementTypedDataCid(ffi_type_arg_cid);
|
compiler::ffi::ElementTypedDataCid(ffi_type_arg_cid);
|
||||||
|
|
||||||
ASSERT_EQUAL(function.NumParameters(), 2);
|
ASSERT_EQUAL(function.NumParameters(), 2);
|
||||||
LocalVariable* arg_pointer = parsed_function_->RawParameterVariable(0);
|
// Argument can be a TypedData for loads on struct fields.
|
||||||
|
LocalVariable* arg_typed_data_base =
|
||||||
|
parsed_function_->RawParameterVariable(0);
|
||||||
LocalVariable* arg_offset = parsed_function_->RawParameterVariable(1);
|
LocalVariable* arg_offset = parsed_function_->RawParameterVariable(1);
|
||||||
|
|
||||||
body += LoadLocal(arg_offset);
|
body += LoadLocal(arg_offset);
|
||||||
body += CheckNullOptimized(String::ZoneHandle(Z, function.name()));
|
body += CheckNullOptimized(String::ZoneHandle(Z, function.name()));
|
||||||
LocalVariable* arg_offset_not_null = MakeTemporary();
|
LocalVariable* arg_offset_not_null = MakeTemporary();
|
||||||
|
|
||||||
body += LoadLocal(arg_pointer);
|
body += LoadLocal(arg_typed_data_base);
|
||||||
body += CheckNullOptimized(String::ZoneHandle(Z, function.name()));
|
body += CheckNullOptimized(String::ZoneHandle(Z, function.name()));
|
||||||
// No GC from here til LoadIndexed.
|
// No GC from here til LoadIndexed.
|
||||||
body += LoadNativeField(Slot::PointerBase_data(),
|
body += LoadNativeField(Slot::PointerBase_data(),
|
||||||
InnerPointerAccess::kCannotBeInnerPointer);
|
InnerPointerAccess::kMayBeInnerPointer);
|
||||||
body += LoadLocal(arg_offset_not_null);
|
body += LoadLocal(arg_offset_not_null);
|
||||||
body += UnboxTruncate(kUnboxedFfiIntPtr);
|
body += UnboxTruncate(kUnboxedFfiIntPtr);
|
||||||
body += LoadIndexed(typed_data_cid, /*index_scale=*/1,
|
body += LoadIndexed(typed_data_cid, /*index_scale=*/1,
|
||||||
|
@ -1520,7 +1522,9 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
|
||||||
const classid_t typed_data_cid =
|
const classid_t typed_data_cid =
|
||||||
compiler::ffi::ElementTypedDataCid(ffi_type_arg_cid);
|
compiler::ffi::ElementTypedDataCid(ffi_type_arg_cid);
|
||||||
|
|
||||||
LocalVariable* arg_pointer = parsed_function_->RawParameterVariable(0);
|
// Argument can be a TypedData for stores on struct fields.
|
||||||
|
LocalVariable* arg_typed_data_base =
|
||||||
|
parsed_function_->RawParameterVariable(0);
|
||||||
LocalVariable* arg_offset = parsed_function_->RawParameterVariable(1);
|
LocalVariable* arg_offset = parsed_function_->RawParameterVariable(1);
|
||||||
LocalVariable* arg_value = parsed_function_->RawParameterVariable(2);
|
LocalVariable* arg_value = parsed_function_->RawParameterVariable(2);
|
||||||
|
|
||||||
|
@ -1532,11 +1536,11 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
|
||||||
body += CheckNullOptimized(String::ZoneHandle(Z, function.name()));
|
body += CheckNullOptimized(String::ZoneHandle(Z, function.name()));
|
||||||
LocalVariable* arg_value_not_null = MakeTemporary();
|
LocalVariable* arg_value_not_null = MakeTemporary();
|
||||||
|
|
||||||
body += LoadLocal(arg_pointer); // Pointer.
|
body += LoadLocal(arg_typed_data_base); // Pointer.
|
||||||
body += CheckNullOptimized(String::ZoneHandle(Z, function.name()));
|
body += CheckNullOptimized(String::ZoneHandle(Z, function.name()));
|
||||||
// No GC from here til StoreIndexed.
|
// No GC from here til StoreIndexed.
|
||||||
body += LoadNativeField(Slot::PointerBase_data(),
|
body += LoadNativeField(Slot::PointerBase_data(),
|
||||||
InnerPointerAccess::kCannotBeInnerPointer);
|
InnerPointerAccess::kMayBeInnerPointer);
|
||||||
body += LoadLocal(arg_offset_not_null);
|
body += LoadLocal(arg_offset_not_null);
|
||||||
body += UnboxTruncate(kUnboxedFfiIntPtr);
|
body += UnboxTruncate(kUnboxedFfiIntPtr);
|
||||||
body += LoadLocal(arg_value_not_null);
|
body += LoadLocal(arg_value_not_null);
|
||||||
|
|
|
@ -572,15 +572,19 @@ extension NativeFunctionPointer<NF extends Function>
|
||||||
@patch
|
@patch
|
||||||
extension Int8Pointer on Pointer<Int8> {
|
extension Int8Pointer on Pointer<Int8> {
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int get value => _loadInt8(this, 0);
|
int get value => _loadInt8(this, 0);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
set value(int value) => _storeInt8(this, 0, value);
|
set value(int value) => _storeInt8(this, 0, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int operator [](int index) => _loadInt8(this, index);
|
int operator [](int index) => _loadInt8(this, index);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
operator []=(int index, int value) => _storeInt8(this, index, value);
|
operator []=(int index, int value) => _storeInt8(this, index, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@ -605,15 +609,19 @@ extension Int8Pointer on Pointer<Int8> {
|
||||||
@patch
|
@patch
|
||||||
extension Int16Pointer on Pointer<Int16> {
|
extension Int16Pointer on Pointer<Int16> {
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int get value => _loadInt16(this, 0);
|
int get value => _loadInt16(this, 0);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
set value(int value) => _storeInt16(this, 0, value);
|
set value(int value) => _storeInt16(this, 0, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int operator [](int index) => _loadInt16(this, 2 * index);
|
int operator [](int index) => _loadInt16(this, 2 * index);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
operator []=(int index, int value) => _storeInt16(this, 2 * index, value);
|
operator []=(int index, int value) => _storeInt16(this, 2 * index, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@ -638,15 +646,19 @@ extension Int16Pointer on Pointer<Int16> {
|
||||||
@patch
|
@patch
|
||||||
extension Int32Pointer on Pointer<Int32> {
|
extension Int32Pointer on Pointer<Int32> {
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int get value => _loadInt32(this, 0);
|
int get value => _loadInt32(this, 0);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
set value(int value) => _storeInt32(this, 0, value);
|
set value(int value) => _storeInt32(this, 0, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int operator [](int index) => _loadInt32(this, 4 * index);
|
int operator [](int index) => _loadInt32(this, 4 * index);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
operator []=(int index, int value) => _storeInt32(this, 4 * index, value);
|
operator []=(int index, int value) => _storeInt32(this, 4 * index, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@ -671,15 +683,19 @@ extension Int32Pointer on Pointer<Int32> {
|
||||||
@patch
|
@patch
|
||||||
extension Int64Pointer on Pointer<Int64> {
|
extension Int64Pointer on Pointer<Int64> {
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int get value => _loadInt64(this, 0);
|
int get value => _loadInt64(this, 0);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
set value(int value) => _storeInt64(this, 0, value);
|
set value(int value) => _storeInt64(this, 0, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int operator [](int index) => _loadInt64(this, 8 * index);
|
int operator [](int index) => _loadInt64(this, 8 * index);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
operator []=(int index, int value) => _storeInt64(this, 8 * index, value);
|
operator []=(int index, int value) => _storeInt64(this, 8 * index, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@ -704,15 +720,19 @@ extension Int64Pointer on Pointer<Int64> {
|
||||||
@patch
|
@patch
|
||||||
extension Uint8Pointer on Pointer<Uint8> {
|
extension Uint8Pointer on Pointer<Uint8> {
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int get value => _loadUint8(this, 0);
|
int get value => _loadUint8(this, 0);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
set value(int value) => _storeUint8(this, 0, value);
|
set value(int value) => _storeUint8(this, 0, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int operator [](int index) => _loadUint8(this, index);
|
int operator [](int index) => _loadUint8(this, index);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
operator []=(int index, int value) => _storeUint8(this, index, value);
|
operator []=(int index, int value) => _storeUint8(this, index, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@ -737,15 +757,19 @@ extension Uint8Pointer on Pointer<Uint8> {
|
||||||
@patch
|
@patch
|
||||||
extension Uint16Pointer on Pointer<Uint16> {
|
extension Uint16Pointer on Pointer<Uint16> {
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int get value => _loadUint16(this, 0);
|
int get value => _loadUint16(this, 0);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
set value(int value) => _storeUint16(this, 0, value);
|
set value(int value) => _storeUint16(this, 0, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int operator [](int index) => _loadUint16(this, 2 * index);
|
int operator [](int index) => _loadUint16(this, 2 * index);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
operator []=(int index, int value) => _storeUint16(this, 2 * index, value);
|
operator []=(int index, int value) => _storeUint16(this, 2 * index, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@ -770,15 +794,19 @@ extension Uint16Pointer on Pointer<Uint16> {
|
||||||
@patch
|
@patch
|
||||||
extension Uint32Pointer on Pointer<Uint32> {
|
extension Uint32Pointer on Pointer<Uint32> {
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int get value => _loadUint32(this, 0);
|
int get value => _loadUint32(this, 0);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
set value(int value) => _storeUint32(this, 0, value);
|
set value(int value) => _storeUint32(this, 0, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int operator [](int index) => _loadUint32(this, 4 * index);
|
int operator [](int index) => _loadUint32(this, 4 * index);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
operator []=(int index, int value) => _storeUint32(this, 4 * index, value);
|
operator []=(int index, int value) => _storeUint32(this, 4 * index, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@ -803,15 +831,19 @@ extension Uint32Pointer on Pointer<Uint32> {
|
||||||
@patch
|
@patch
|
||||||
extension Uint64Pointer on Pointer<Uint64> {
|
extension Uint64Pointer on Pointer<Uint64> {
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int get value => _loadUint64(this, 0);
|
int get value => _loadUint64(this, 0);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
set value(int value) => _storeUint64(this, 0, value);
|
set value(int value) => _storeUint64(this, 0, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
int operator [](int index) => _loadUint64(this, 8 * index);
|
int operator [](int index) => _loadUint64(this, 8 * index);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
operator []=(int index, int value) => _storeUint64(this, 8 * index, value);
|
operator []=(int index, int value) => _storeUint64(this, 8 * index, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@ -836,15 +868,19 @@ extension Uint64Pointer on Pointer<Uint64> {
|
||||||
@patch
|
@patch
|
||||||
extension FloatPointer on Pointer<Float> {
|
extension FloatPointer on Pointer<Float> {
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
double get value => _loadFloat(this, 0);
|
double get value => _loadFloat(this, 0);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
set value(double value) => _storeFloat(this, 0, value);
|
set value(double value) => _storeFloat(this, 0, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
double operator [](int index) => _loadFloat(this, 4 * index);
|
double operator [](int index) => _loadFloat(this, 4 * index);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
operator []=(int index, double value) => _storeFloat(this, 4 * index, value);
|
operator []=(int index, double value) => _storeFloat(this, 4 * index, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@ -869,15 +905,19 @@ extension FloatPointer on Pointer<Float> {
|
||||||
@patch
|
@patch
|
||||||
extension DoublePointer on Pointer<Double> {
|
extension DoublePointer on Pointer<Double> {
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
double get value => _loadDouble(this, 0);
|
double get value => _loadDouble(this, 0);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
set value(double value) => _storeDouble(this, 0, value);
|
set value(double value) => _storeDouble(this, 0, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
double operator [](int index) => _loadDouble(this, 8 * index);
|
double operator [](int index) => _loadDouble(this, 8 * index);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
operator []=(int index, double value) => _storeDouble(this, 8 * index, value);
|
operator []=(int index, double value) => _storeDouble(this, 8 * index, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@ -902,15 +942,19 @@ extension DoublePointer on Pointer<Double> {
|
||||||
@patch
|
@patch
|
||||||
extension BoolPointer on Pointer<Bool> {
|
extension BoolPointer on Pointer<Bool> {
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
bool get value => _loadBool(this, 0);
|
bool get value => _loadBool(this, 0);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
set value(bool value) => _storeBool(this, 0, value);
|
set value(bool value) => _storeBool(this, 0, value);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
bool operator [](int index) => _loadBool(this, index);
|
bool operator [](int index) => _loadBool(this, index);
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
operator []=(int index, bool value) => _storeBool(this, index, value);
|
operator []=(int index, bool value) => _storeBool(this, index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -335,6 +335,7 @@ extension Int8Pointer on Pointer<Int8> {
|
||||||
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
||||||
/// and similarly for setting.
|
/// and similarly for setting.
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Int8> operator +(int offset) =>
|
Pointer<Int8> operator +(int offset) =>
|
||||||
Pointer.fromAddress(address + sizeOf<Int8>() * offset);
|
Pointer.fromAddress(address + sizeOf<Int8>() * offset);
|
||||||
|
|
||||||
|
@ -349,6 +350,7 @@ extension Int8Pointer on Pointer<Int8> {
|
||||||
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
||||||
/// and similarly for setting,
|
/// and similarly for setting,
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Int8> operator -(int offset) =>
|
Pointer<Int8> operator -(int offset) =>
|
||||||
Pointer.fromAddress(address - sizeOf<Int8>() * offset);
|
Pointer.fromAddress(address - sizeOf<Int8>() * offset);
|
||||||
|
|
||||||
|
@ -412,6 +414,7 @@ extension Int16Pointer on Pointer<Int16> {
|
||||||
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
||||||
/// and similarly for setting.
|
/// and similarly for setting.
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Int16> operator +(int offset) =>
|
Pointer<Int16> operator +(int offset) =>
|
||||||
Pointer.fromAddress(address + sizeOf<Int16>() * offset);
|
Pointer.fromAddress(address + sizeOf<Int16>() * offset);
|
||||||
|
|
||||||
|
@ -426,6 +429,7 @@ extension Int16Pointer on Pointer<Int16> {
|
||||||
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
||||||
/// and similarly for setting,
|
/// and similarly for setting,
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Int16> operator -(int offset) =>
|
Pointer<Int16> operator -(int offset) =>
|
||||||
Pointer.fromAddress(address - sizeOf<Int16>() * offset);
|
Pointer.fromAddress(address - sizeOf<Int16>() * offset);
|
||||||
|
|
||||||
|
@ -491,6 +495,7 @@ extension Int32Pointer on Pointer<Int32> {
|
||||||
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
||||||
/// and similarly for setting.
|
/// and similarly for setting.
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Int32> operator +(int offset) =>
|
Pointer<Int32> operator +(int offset) =>
|
||||||
Pointer.fromAddress(address + sizeOf<Int32>() * offset);
|
Pointer.fromAddress(address + sizeOf<Int32>() * offset);
|
||||||
|
|
||||||
|
@ -505,6 +510,7 @@ extension Int32Pointer on Pointer<Int32> {
|
||||||
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
||||||
/// and similarly for setting,
|
/// and similarly for setting,
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Int32> operator -(int offset) =>
|
Pointer<Int32> operator -(int offset) =>
|
||||||
Pointer.fromAddress(address - sizeOf<Int32>() * offset);
|
Pointer.fromAddress(address - sizeOf<Int32>() * offset);
|
||||||
|
|
||||||
|
@ -561,6 +567,7 @@ extension Int64Pointer on Pointer<Int64> {
|
||||||
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
||||||
/// and similarly for setting.
|
/// and similarly for setting.
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Int64> operator +(int offset) =>
|
Pointer<Int64> operator +(int offset) =>
|
||||||
Pointer.fromAddress(address + sizeOf<Int64>() * offset);
|
Pointer.fromAddress(address + sizeOf<Int64>() * offset);
|
||||||
|
|
||||||
|
@ -575,6 +582,7 @@ extension Int64Pointer on Pointer<Int64> {
|
||||||
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
||||||
/// and similarly for setting,
|
/// and similarly for setting,
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Int64> operator -(int offset) =>
|
Pointer<Int64> operator -(int offset) =>
|
||||||
Pointer.fromAddress(address - sizeOf<Int64>() * offset);
|
Pointer.fromAddress(address - sizeOf<Int64>() * offset);
|
||||||
|
|
||||||
|
@ -634,6 +642,7 @@ extension Uint8Pointer on Pointer<Uint8> {
|
||||||
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
||||||
/// and similarly for setting.
|
/// and similarly for setting.
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Uint8> operator +(int offset) =>
|
Pointer<Uint8> operator +(int offset) =>
|
||||||
Pointer.fromAddress(address + sizeOf<Uint8>() * offset);
|
Pointer.fromAddress(address + sizeOf<Uint8>() * offset);
|
||||||
|
|
||||||
|
@ -648,6 +657,7 @@ extension Uint8Pointer on Pointer<Uint8> {
|
||||||
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
||||||
/// and similarly for setting,
|
/// and similarly for setting,
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Uint8> operator -(int offset) =>
|
Pointer<Uint8> operator -(int offset) =>
|
||||||
Pointer.fromAddress(address - sizeOf<Uint8>() * offset);
|
Pointer.fromAddress(address - sizeOf<Uint8>() * offset);
|
||||||
|
|
||||||
|
@ -711,6 +721,7 @@ extension Uint16Pointer on Pointer<Uint16> {
|
||||||
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
||||||
/// and similarly for setting.
|
/// and similarly for setting.
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Uint16> operator +(int offset) =>
|
Pointer<Uint16> operator +(int offset) =>
|
||||||
Pointer.fromAddress(address + sizeOf<Uint16>() * offset);
|
Pointer.fromAddress(address + sizeOf<Uint16>() * offset);
|
||||||
|
|
||||||
|
@ -725,6 +736,7 @@ extension Uint16Pointer on Pointer<Uint16> {
|
||||||
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
||||||
/// and similarly for setting,
|
/// and similarly for setting,
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Uint16> operator -(int offset) =>
|
Pointer<Uint16> operator -(int offset) =>
|
||||||
Pointer.fromAddress(address - sizeOf<Uint16>() * offset);
|
Pointer.fromAddress(address - sizeOf<Uint16>() * offset);
|
||||||
|
|
||||||
|
@ -790,6 +802,7 @@ extension Uint32Pointer on Pointer<Uint32> {
|
||||||
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
||||||
/// and similarly for setting.
|
/// and similarly for setting.
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Uint32> operator +(int offset) =>
|
Pointer<Uint32> operator +(int offset) =>
|
||||||
Pointer.fromAddress(address + sizeOf<Uint32>() * offset);
|
Pointer.fromAddress(address + sizeOf<Uint32>() * offset);
|
||||||
|
|
||||||
|
@ -804,6 +817,7 @@ extension Uint32Pointer on Pointer<Uint32> {
|
||||||
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
||||||
/// and similarly for setting,
|
/// and similarly for setting,
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Uint32> operator -(int offset) =>
|
Pointer<Uint32> operator -(int offset) =>
|
||||||
Pointer.fromAddress(address - sizeOf<Uint32>() * offset);
|
Pointer.fromAddress(address - sizeOf<Uint32>() * offset);
|
||||||
|
|
||||||
|
@ -860,6 +874,7 @@ extension Uint64Pointer on Pointer<Uint64> {
|
||||||
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
||||||
/// and similarly for setting.
|
/// and similarly for setting.
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Uint64> operator +(int offset) =>
|
Pointer<Uint64> operator +(int offset) =>
|
||||||
Pointer.fromAddress(address + sizeOf<Uint64>() * offset);
|
Pointer.fromAddress(address + sizeOf<Uint64>() * offset);
|
||||||
|
|
||||||
|
@ -874,6 +889,7 @@ extension Uint64Pointer on Pointer<Uint64> {
|
||||||
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
||||||
/// and similarly for setting,
|
/// and similarly for setting,
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Uint64> operator -(int offset) =>
|
Pointer<Uint64> operator -(int offset) =>
|
||||||
Pointer.fromAddress(address - sizeOf<Uint64>() * offset);
|
Pointer.fromAddress(address - sizeOf<Uint64>() * offset);
|
||||||
|
|
||||||
|
@ -939,6 +955,7 @@ extension FloatPointer on Pointer<Float> {
|
||||||
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
||||||
/// and similarly for setting.
|
/// and similarly for setting.
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Float> operator +(int offset) =>
|
Pointer<Float> operator +(int offset) =>
|
||||||
Pointer.fromAddress(address + sizeOf<Float>() * offset);
|
Pointer.fromAddress(address + sizeOf<Float>() * offset);
|
||||||
|
|
||||||
|
@ -953,6 +970,7 @@ extension FloatPointer on Pointer<Float> {
|
||||||
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
||||||
/// and similarly for setting,
|
/// and similarly for setting,
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Float> operator -(int offset) =>
|
Pointer<Float> operator -(int offset) =>
|
||||||
Pointer.fromAddress(address - sizeOf<Float>() * offset);
|
Pointer.fromAddress(address - sizeOf<Float>() * offset);
|
||||||
|
|
||||||
|
@ -1009,6 +1027,7 @@ extension DoublePointer on Pointer<Double> {
|
||||||
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
||||||
/// and similarly for setting.
|
/// and similarly for setting.
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Double> operator +(int offset) =>
|
Pointer<Double> operator +(int offset) =>
|
||||||
Pointer.fromAddress(address + sizeOf<Double>() * offset);
|
Pointer.fromAddress(address + sizeOf<Double>() * offset);
|
||||||
|
|
||||||
|
@ -1023,6 +1042,7 @@ extension DoublePointer on Pointer<Double> {
|
||||||
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
||||||
/// and similarly for setting,
|
/// and similarly for setting,
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Double> operator -(int offset) =>
|
Pointer<Double> operator -(int offset) =>
|
||||||
Pointer.fromAddress(address - sizeOf<Double>() * offset);
|
Pointer.fromAddress(address - sizeOf<Double>() * offset);
|
||||||
|
|
||||||
|
@ -1074,6 +1094,7 @@ extension BoolPointer on Pointer<Bool> {
|
||||||
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
/// Also `(this + offset).value` is equivalent to `this[offset]`,
|
||||||
/// and similarly for setting.
|
/// and similarly for setting.
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Bool> operator +(int offset) =>
|
Pointer<Bool> operator +(int offset) =>
|
||||||
Pointer.fromAddress(address + sizeOf<Bool>() * offset);
|
Pointer.fromAddress(address + sizeOf<Bool>() * offset);
|
||||||
|
|
||||||
|
@ -1088,6 +1109,7 @@ extension BoolPointer on Pointer<Bool> {
|
||||||
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
/// Also, `(this - offset).value` is equivalent to `this[-offset]`,
|
||||||
/// and similarly for setting,
|
/// and similarly for setting,
|
||||||
@Since('3.3')
|
@Since('3.3')
|
||||||
|
@pragma("vm:prefer-inline")
|
||||||
Pointer<Bool> operator -(int offset) =>
|
Pointer<Bool> operator -(int offset) =>
|
||||||
Pointer.fromAddress(address - sizeOf<Bool>() * offset);
|
Pointer.fromAddress(address - sizeOf<Bool>() * offset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,11 +42,17 @@ function_callbacks_structs_by_value_generated_test: Pass, Slow
|
||||||
[ $mode == product ]
|
[ $mode == product ]
|
||||||
regress_47594_test: Skip # Profiler is not available in Product.
|
regress_47594_test: Skip # Profiler is not available in Product.
|
||||||
|
|
||||||
|
[ $nnbd == weak ]
|
||||||
|
vmspecific_pointer_load_il_test: SkipByDesign # Unsound NNBD boxes things because of nulls.
|
||||||
|
|
||||||
[ $system == android ]
|
[ $system == android ]
|
||||||
*: Pass, Slow # https://github.com/dart-lang/sdk/issues/38489
|
*: Pass, Slow # https://github.com/dart-lang/sdk/issues/38489
|
||||||
regress_47594_test: Skip # DartDev is not available on Android.
|
regress_47594_test: Skip # DartDev is not available on Android.
|
||||||
vmspecific_native_finalizer_isolate_groups_test: Skip # SpawnUri not available on Android tester.
|
vmspecific_native_finalizer_isolate_groups_test: Skip # SpawnUri not available on Android tester.
|
||||||
|
|
||||||
|
[ $system == fuchsia ]
|
||||||
|
vmspecific_pointer_load_il_test: SkipByDesign # Not bloating the Fuchsia test package with package:vm/testing/il_matchers.dart
|
||||||
|
|
||||||
[ $system == windows ]
|
[ $system == windows ]
|
||||||
regress_47594_test: Skip # DynamicLibrary.process() is not available on Windows.
|
regress_47594_test: Skip # DynamicLibrary.process() is not available on Windows.
|
||||||
|
|
||||||
|
@ -71,6 +77,9 @@ vmspecific_regress_37511_test: SkipByDesign # Symbols are not exposed on purpose
|
||||||
vmspecific_regress_37780_test: SkipByDesign # Symbols are not exposed on purpose and are not linked in Windows Precompiled. dartbug.com/40579
|
vmspecific_regress_37780_test: SkipByDesign # Symbols are not exposed on purpose and are not linked in Windows Precompiled. dartbug.com/40579
|
||||||
vmspecific_regress_51794_test: SkipByDesign # Symbols are not exposed on purpose and are not linked in Windows Precompiled. dartbug.com/40579
|
vmspecific_regress_51794_test: SkipByDesign # Symbols are not exposed on purpose and are not linked in Windows Precompiled. dartbug.com/40579
|
||||||
|
|
||||||
|
[ $arch == arm || $arch == arm_x64 || $arch == ia32 || $arch == riscv32 || $arch == simarm || $arch == simriscv32 ]
|
||||||
|
vmspecific_pointer_load_il_test: SkipByDesign # 32 bit archs use uint32 for pointers and have more int conversions.
|
||||||
|
|
||||||
# These tests trigger and catch an abort (intentionally) and terminate the VM.
|
# These tests trigger and catch an abort (intentionally) and terminate the VM.
|
||||||
# They're incompatible with ASAN because not all memory is freed when aborting and
|
# They're incompatible with ASAN because not all memory is freed when aborting and
|
||||||
# with AppJit because the abort the VM before it can generate a snapshot.
|
# with AppJit because the abort the VM before it can generate a snapshot.
|
||||||
|
|
222
tests/ffi/vmspecific_pointer_load_il_test.dart
Normal file
222
tests/ffi/vmspecific_pointer_load_il_test.dart
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
// Copyright (c) 2024, 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.
|
||||||
|
|
||||||
|
// Check that `Pointer` are not allocated before being passed into a load.
|
||||||
|
|
||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
|
import 'package:expect/expect.dart';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
import 'package:vm/testing/il_matchers.dart';
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
using((arena) {
|
||||||
|
const length = 100;
|
||||||
|
final pointer = arena<Int8>(100);
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
pointer[i] = i;
|
||||||
|
}
|
||||||
|
Expect.equals(
|
||||||
|
10,
|
||||||
|
testOffset(pointer),
|
||||||
|
);
|
||||||
|
Expect.equals(
|
||||||
|
10,
|
||||||
|
testAllocate(pointer),
|
||||||
|
);
|
||||||
|
Expect.equals(
|
||||||
|
45,
|
||||||
|
testHoist(pointer),
|
||||||
|
);
|
||||||
|
print(globalVar);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@pragma('vm:never-inline')
|
||||||
|
@pragma('vm:testing:print-flow-graph')
|
||||||
|
int testOffset(Pointer<Int8> pointer) {
|
||||||
|
// `pointer2` is not allocated.
|
||||||
|
final pointer2 = pointer + 10;
|
||||||
|
return pointer2.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void matchIL$testOffset(FlowGraph graph) {
|
||||||
|
graph.dump();
|
||||||
|
graph.match([
|
||||||
|
match.block('Graph', [
|
||||||
|
'int 10' << match.UnboxedConstant(value: 10),
|
||||||
|
'int 0' << match.UnboxedConstant(value: 0),
|
||||||
|
]),
|
||||||
|
match.block('Function', [
|
||||||
|
'pointer' <<
|
||||||
|
match.Parameter(
|
||||||
|
index: 0,
|
||||||
|
),
|
||||||
|
'pointer.address untagged' <<
|
||||||
|
match.LoadField(
|
||||||
|
'pointer',
|
||||||
|
slot: 'PointerBase.data',
|
||||||
|
),
|
||||||
|
'pointer.address int64' <<
|
||||||
|
match.IntConverter(
|
||||||
|
'pointer.address untagged',
|
||||||
|
from: 'untagged',
|
||||||
|
to: 'int64',
|
||||||
|
),
|
||||||
|
'pointer2.address int64' <<
|
||||||
|
match.BinaryInt64Op(
|
||||||
|
'pointer.address int64',
|
||||||
|
'int 10',
|
||||||
|
),
|
||||||
|
// `pointer2` is not allocated.
|
||||||
|
'pointer2.address untagged' <<
|
||||||
|
match.IntConverter(
|
||||||
|
'pointer2.address int64',
|
||||||
|
from: 'int64',
|
||||||
|
to: 'untagged',
|
||||||
|
),
|
||||||
|
'pointer2.value' <<
|
||||||
|
match.LoadIndexed(
|
||||||
|
'pointer2.address untagged',
|
||||||
|
'int 0',
|
||||||
|
),
|
||||||
|
match.Return('pointer2.value'),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
final int i;
|
||||||
|
|
||||||
|
A(this.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
A? globalVar;
|
||||||
|
|
||||||
|
@pragma('vm:never-inline')
|
||||||
|
@pragma('vm:testing:print-flow-graph')
|
||||||
|
int testAllocate(Pointer<Int8> pointer) {
|
||||||
|
final pointer2 = pointer + 10;
|
||||||
|
globalVar = A(10);
|
||||||
|
return pointer2.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void matchIL$testAllocate(FlowGraph graph) {
|
||||||
|
graph.dump();
|
||||||
|
graph.match([
|
||||||
|
match.block('Graph', [
|
||||||
|
'int 10' << match.UnboxedConstant(value: 10),
|
||||||
|
'int 0' << match.UnboxedConstant(value: 0),
|
||||||
|
]),
|
||||||
|
match.block('Function', [
|
||||||
|
'pointer' <<
|
||||||
|
match.Parameter(
|
||||||
|
index: 0,
|
||||||
|
),
|
||||||
|
'pointer.address untagged' <<
|
||||||
|
match.LoadField(
|
||||||
|
'pointer',
|
||||||
|
slot: 'PointerBase.data',
|
||||||
|
),
|
||||||
|
'pointer.address int64' <<
|
||||||
|
match.IntConverter(
|
||||||
|
'pointer.address untagged',
|
||||||
|
from: 'untagged',
|
||||||
|
to: 'int64',
|
||||||
|
),
|
||||||
|
'pointer2.address int64' <<
|
||||||
|
match.BinaryInt64Op(
|
||||||
|
'pointer.address int64',
|
||||||
|
'int 10',
|
||||||
|
),
|
||||||
|
'pointer2.address untagged' <<
|
||||||
|
match.IntConverter(
|
||||||
|
'pointer2.address int64',
|
||||||
|
from: 'int64',
|
||||||
|
to: 'untagged',
|
||||||
|
),
|
||||||
|
// The untagged pointer2.address can live through an allocation
|
||||||
|
// even though it is marked `InnerPointerAccess::kMayBeInnerPointer`
|
||||||
|
// because its cid is a Pointer cid.
|
||||||
|
match.AllocateObject(),
|
||||||
|
match.StoreStaticField(match.any),
|
||||||
|
'pointer2.value' <<
|
||||||
|
match.LoadIndexed(
|
||||||
|
'pointer2.address untagged',
|
||||||
|
'int 0',
|
||||||
|
),
|
||||||
|
match.Return('pointer2.value'),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@pragma('vm:never-inline')
|
||||||
|
@pragma('vm:testing:print-flow-graph')
|
||||||
|
int testHoist(Pointer<Int8> pointer) {
|
||||||
|
int result = 0;
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
globalVar = A(10);
|
||||||
|
// The address load is hoisted out of the loop.
|
||||||
|
// The indexed load is _not_ hoisted out of the loop.
|
||||||
|
result += pointer[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void matchIL$testHoist(FlowGraph graph) {
|
||||||
|
graph.dump();
|
||||||
|
graph.match([
|
||||||
|
match.block('Graph', [
|
||||||
|
'int 0' << match.UnboxedConstant(value: 0),
|
||||||
|
'int 10' << match.UnboxedConstant(value: 10),
|
||||||
|
'int 1' << match.UnboxedConstant(value: 1),
|
||||||
|
]),
|
||||||
|
match.block('Function', [
|
||||||
|
'pointer' <<
|
||||||
|
match.Parameter(
|
||||||
|
index: 0,
|
||||||
|
),
|
||||||
|
'pointer.address' <<
|
||||||
|
match.LoadField(
|
||||||
|
'pointer',
|
||||||
|
slot: 'PointerBase.data',
|
||||||
|
),
|
||||||
|
match.Goto('B1'),
|
||||||
|
]),
|
||||||
|
'B1' <<
|
||||||
|
match.block('Join', [
|
||||||
|
match.CheckStackOverflow(),
|
||||||
|
match.Branch(match.RelationalOp(match.any, match.any, kind: '<'),
|
||||||
|
ifTrue: 'B2', ifFalse: 'B3'),
|
||||||
|
]),
|
||||||
|
'B2' <<
|
||||||
|
match.block('Target', [
|
||||||
|
// Do some allocation.
|
||||||
|
match.AllocateObject(),
|
||||||
|
match.StoreStaticField(match.any),
|
||||||
|
// Do a load indexed with the untagged pointer.address that is
|
||||||
|
// hoisted out of the loop.
|
||||||
|
'pointer[i]' <<
|
||||||
|
match.LoadIndexed(
|
||||||
|
'pointer.address',
|
||||||
|
match.any, // i
|
||||||
|
),
|
||||||
|
'result' <<
|
||||||
|
match.BinaryInt64Op(
|
||||||
|
match.any,
|
||||||
|
'pointer[i]',
|
||||||
|
),
|
||||||
|
'i' <<
|
||||||
|
match.BinaryInt64Op(
|
||||||
|
match.any,
|
||||||
|
match.any,
|
||||||
|
),
|
||||||
|
match.Goto('B1'),
|
||||||
|
]),
|
||||||
|
'B3' <<
|
||||||
|
match.block('Target', [
|
||||||
|
match.Return(match.any),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
Loading…
Reference in a new issue