From 8dcb212010fb20942ea300d5d13b15aac8a72934 Mon Sep 17 00:00:00 2001 From: Keerti Parthasarathy Date: Tue, 2 Apr 2024 14:47:02 +0000 Subject: [PATCH 1/6] Issue 53669: Remove duplicate await when inlining methods. Fixes https://github.com/dart-lang/sdk/issues/53669 Change-Id: I64eb73d5eef4a8a8ab5184b3e67bb2303faed5e7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/360580 Commit-Queue: Keerti Parthasarathy Reviewed-by: Brian Wilkerson --- .../refactoring/legacy/inline_method.dart | 7 +++++++ .../test/edit/refactoring_test.dart | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/pkg/analysis_server/lib/src/services/refactoring/legacy/inline_method.dart b/pkg/analysis_server/lib/src/services/refactoring/legacy/inline_method.dart index a386476895fc..1410c1ce9fc9 100644 --- a/pkg/analysis_server/lib/src/services/refactoring/legacy/inline_method.dart +++ b/pkg/analysis_server/lib/src/services/refactoring/legacy/inline_method.dart @@ -15,6 +15,7 @@ import 'package:analysis_server/src/utilities/strings.dart'; import 'package:analyzer/dart/analysis/results.dart'; import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/ast/precedence.dart'; +import 'package:analyzer/dart/ast/token.dart'; import 'package:analyzer/dart/ast/visitor.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/source/source_range.dart'; @@ -572,6 +573,12 @@ class _ReferenceProcessor { } // do replace var methodUsageRange = range.node(usage); + var awaitKeyword = Keyword.AWAIT.lexeme; + if (usage.parent is AwaitExpression && + source.startsWith(awaitKeyword)) { + // remove the duplicate await keyword and the following whitespace. + source = source.substring(awaitKeyword.length + 1); + } var edit = newSourceEdit_range(methodUsageRange, source); _addRefEdit(edit); } else { diff --git a/pkg/analysis_server/test/edit/refactoring_test.dart b/pkg/analysis_server/test/edit/refactoring_test.dart index f1ae36b9f10a..a388f6515258 100644 --- a/pkg/analysis_server/test/edit/refactoring_test.dart +++ b/pkg/analysis_server/test/edit/refactoring_test.dart @@ -1321,6 +1321,22 @@ void f() { '''); } + Future test_topLevelFunction_async() { + addTestFile(''' +Future a() async => 3; +Future b() async => await a(); +Future c() async => await b(); +} +'''); + return assertSuccessfulRefactoring(() { + return _sendInlineRequest('b('); + }, ''' +Future a() async => 3; +Future c() async => await a(); +} +'''); + } + Future test_topLevelFunction_oneInvocation() { addTestFile(''' test(a, b) { From 9fc280a7f6dcaf57d9a94d663a6d62c7af1a1f90 Mon Sep 17 00:00:00 2001 From: Tess Strickland Date: Tue, 2 Apr 2024 14:54:13 +0000 Subject: [PATCH 2/6] [vm/compiler] Add all Compressed Assembler methods to AssemblerBase. Remove CompareWithCompressedFieldFromOffset, which has no uses. Rename the LoadFromOffset and StoreFromOffset methods that took Addresses to Load and Store, respectively. This makes the names of the Assembler methods more uniform: * Takes an address: Load, Store, LoadField, LoadCompressedField, StoreIntoObject, StoreCompressedIntoObject, LoadSmi, LoadCompressedSmi, etc. * Takes a base register and an offset: LoadFromOffset, StoreToOffset, LoadFieldFromOffset, LoadCompressedFieldFromOffset, StoreIntoObjectOffset, StoreCompressedIntoObjectOffset, LoadSmiFromOffset, LoadCompressedSmiFromOffset, etc. Create AssemblerBase methods for loading and storing compressed pointers that weren't already there, as well as the corresponding methods for loading and storing uncompressed values. Make non-virtual methods that load and store uncompressed fields that call the corresponding method for loading from and storing to memory regions, adjusting the address or offset accordingly. This avoids needing per-architecture overrides for these. Make non-virtual methods that load compressed fields, calling the corresponding method for loading a compressed value from a memory region. (Since compressed pointers are only stored in Dart objects, and stores into a Dart object may require a barrier, there is no method for storing a compressed value into an arbitrary memory region.) Create pure virtual methods for loading from or storing to an Address or any method that does not have both an Address-taking and a base register and offset pair-taking version (e.g., LoadAcquire). Create methods for loading from or storing to a base register and an offset. The base implementation takes the base register and offset and creates an Address from it, then calls the Address-taking equivalent. These methods are non-virtual when the implementation is the same on all architectures and virtual to allow overriding when necessary. Make a non-virtual method for loading uncompressed Smis, since all architectures have the same code for this, including the DEBUG check. If compressed pointers are not being used, all the methods for compressed pointers are non-virtual methods that call the corresponding method for uncompressed values. If compressed pointers are being used: * Install pure virtual methods for loading compressed values from and storing compressed values to an Address or any method that does not have both an Address-taking and a base register and offset pair-taking version (e.g., LoadAcquireCompressed). * Install virtual methods for loading compressed values from and storing compressed values to a base register and offset. Like the uncompressed implementation, the base implementation of these create an Address and call the Address-taking equivalent, and these implementations are overridden on ARM64. * Install a non-virtual method for loading compressed Smis, since the only difference is that it loads a zero-extended 32-bit value, which AssemblerBase can do. TEST=ci (refactoring only) Change-Id: I934791d26a6e2cdaa6ac5f188b0fd89dbdc491d1 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-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-linux-debug-ia32-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/+/359861 Reviewed-by: Daco Harkes Commit-Queue: Tess Strickland Reviewed-by: Alexander Markov --- runtime/vm/compiler/asm_intrinsifier.cc | 2 +- .../vm/compiler/assembler/assembler_arm.cc | 36 +- runtime/vm/compiler/assembler/assembler_arm.h | 146 +++---- .../vm/compiler/assembler/assembler_arm64.cc | 84 ++-- .../vm/compiler/assembler/assembler_arm64.h | 159 +++---- .../vm/compiler/assembler/assembler_base.cc | 189 +++++++-- .../vm/compiler/assembler/assembler_base.h | 399 +++++++++++++++--- .../vm/compiler/assembler/assembler_ia32.cc | 20 +- .../vm/compiler/assembler/assembler_ia32.h | 119 ++---- .../vm/compiler/assembler/assembler_riscv.cc | 98 +---- .../vm/compiler/assembler/assembler_riscv.h | 147 +------ .../vm/compiler/assembler/assembler_x64.cc | 34 +- runtime/vm/compiler/assembler/assembler_x64.h | 161 ++----- .../compiler/backend/flow_graph_compiler.cc | 12 +- runtime/vm/compiler/backend/il.cc | 5 +- runtime/vm/compiler/backend/il_arm.cc | 12 +- runtime/vm/compiler/backend/il_arm64.cc | 5 +- runtime/vm/compiler/backend/il_ia32.cc | 10 +- runtime/vm/compiler/backend/il_riscv.cc | 51 +-- runtime/vm/compiler/backend/il_x64.cc | 6 +- runtime/vm/compiler/stub_code_compiler.cc | 170 ++++---- runtime/vm/compiler/stub_code_compiler_arm.cc | 7 +- .../vm/compiler/stub_code_compiler_arm64.cc | 7 +- .../vm/compiler/stub_code_compiler_ia32.cc | 2 +- .../vm/compiler/stub_code_compiler_riscv.cc | 7 +- runtime/vm/compiler/stub_code_compiler_x64.cc | 7 +- 26 files changed, 904 insertions(+), 991 deletions(-) diff --git a/runtime/vm/compiler/asm_intrinsifier.cc b/runtime/vm/compiler/asm_intrinsifier.cc index 8ebe07386b63..64da178689b6 100644 --- a/runtime/vm/compiler/asm_intrinsifier.cc +++ b/runtime/vm/compiler/asm_intrinsifier.cc @@ -45,7 +45,7 @@ void AsmIntrinsifier::StringEquality(Assembler* assembler, __ CompareClassId(obj2, string_cid, temp1); __ BranchIf(NOT_EQUAL, normal_ir_body, AssemblerBase::kNearJump); - __ LoadFromOffset(temp1, FieldAddress(obj1, target::String::length_offset())); + __ LoadFieldFromOffset(temp1, obj1, target::String::length_offset()); __ CompareWithMemoryValue( temp1, FieldAddress(obj2, target::String::length_offset())); __ BranchIf(NOT_EQUAL, &is_false, AssemblerBase::kNearJump); diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc index 1b7fb32e4e44..e5e5f0c64b1c 100644 --- a/runtime/vm/compiler/assembler/assembler_arm.cc +++ b/runtime/vm/compiler/assembler/assembler_arm.cc @@ -1773,7 +1773,7 @@ void Assembler::StoreIntoObject(Register object, if (memory_order == kRelease) { StoreRelease(value, dest); } else { - StoreToOffset(value, dest); + Store(value, dest); } // In parallel, test whether @@ -1909,7 +1909,7 @@ void Assembler::StoreIntoObjectNoBarrier(Register object, if (memory_order == kRelease) { StoreRelease(value, dest); } else { - StoreToOffset(value, dest); + Store(value, dest); } #if defined(DEBUG) // We can't assert the incremental barrier is not needed here, only the @@ -2030,7 +2030,7 @@ void Assembler::StoreIntoSmiField(const Address& dest, Register value) { Stop("New value must be Smi."); Bind(&done); #endif // defined(DEBUG) - StoreToOffset(value, dest); + Store(value, dest); } void Assembler::ExtractClassIdFromTags(Register result, @@ -2280,16 +2280,6 @@ void Assembler::Bind(Label* label) { BindARMv7(label); } -void Assembler::LoadCompressedSmi(Register dest, const Address& slot) { - ldr(dest, slot); -#if defined(DEBUG) - Label done; - BranchIfSmi(dest, &done, kNearJump); - Stop("Expected Smi"); - Bind(&done); -#endif -} - OperandSize Address::OperandSizeFor(intptr_t cid) { auto const rep = RepresentationUtils::RepresentationOfArrayElement(cid); switch (rep) { @@ -2890,10 +2880,10 @@ Address Assembler::PrepareLargeStoreOffset(const Address& address, return Address(base, offset, mode); } -void Assembler::LoadFromOffset(Register reg, - const Address& address, - OperandSize size, - Condition cond) { +void Assembler::Load(Register reg, + const Address& address, + OperandSize size, + Condition cond) { const Address& addr = PrepareLargeLoadOffset(address, size, cond); switch (size) { case kByte: @@ -2932,10 +2922,10 @@ void Assembler::CompareToStack(Register src, intptr_t depth) { CompareRegisters(src, TMP); } -void Assembler::StoreToOffset(Register reg, - const Address& address, - OperandSize size, - Condition cond) { +void Assembler::Store(Register reg, + const Address& address, + OperandSize size, + Condition cond) { const Address& addr = PrepareLargeStoreOffset(address, size, cond); switch (size) { case kUnsignedByte: @@ -3866,8 +3856,8 @@ void Assembler::LoadElementAddressForRegIndex(Register address, void Assembler::LoadStaticFieldAddress(Register address, Register field, Register scratch) { - LoadCompressedFieldFromOffset( - scratch, field, target::Field::host_offset_or_field_id_offset()); + LoadFieldFromOffset(scratch, field, + target::Field::host_offset_or_field_id_offset()); const intptr_t field_table_offset = compiler::target::Thread::field_table_values_offset(); LoadMemoryValue(address, THR, static_cast(field_table_offset)); diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h index 7371cd066b9e..bb019d7635c0 100644 --- a/runtime/vm/compiler/assembler/assembler_arm.h +++ b/runtime/vm/compiler/assembler/assembler_arm.h @@ -415,7 +415,7 @@ class Assembler : public AssemblerBase { void PushValueAtOffset(Register base, int32_t offset) { UNIMPLEMENTED(); } - void Bind(Label* label); + void Bind(Label* label) override; // Unconditional jump to a given label. [distance] is ignored on ARM. void Jump(Label* label, JumpDistance distance = kFarJump) { b(label); } // Unconditional jump to a given address in register. @@ -423,16 +423,9 @@ class Assembler : public AssemblerBase { // Unconditional jump to a given address in memory. void Jump(const Address& address) { Branch(address); } - void LoadField(Register dst, const FieldAddress& address) override { - LoadFromOffset(dst, address); - } void LoadMemoryValue(Register dst, Register base, int32_t offset) { LoadFromOffset(dst, base, offset); } - void LoadCompressed(Register dest, const Address& slot) { - LoadFromOffset(dest, slot); - } - void LoadCompressedSmi(Register dest, const Address& slot) override; void StoreMemoryValue(Register src, Register base, int32_t offset) { StoreToOffset(src, base, offset); } @@ -440,7 +433,7 @@ class Assembler : public AssemblerBase { Register address, int32_t offset = 0, OperandSize size = kFourBytes) override { - LoadFromOffset(dst, Address(address, offset), size); + Load(dst, Address(address, offset), size); dmb(); } void StoreRelease(Register src, @@ -450,23 +443,16 @@ class Assembler : public AssemblerBase { } void StoreRelease(Register src, Address dest) { dmb(); - StoreToOffset(src, dest); + Store(src, dest); // We don't run TSAN bots on 32 bit. } - void CompareWithCompressedFieldFromOffset(Register value, - Register base, - int32_t offset) { - LoadCompressedFieldFromOffset(TMP, base, offset); - cmp(value, Operand(TMP)); - } - void CompareWithMemoryValue(Register value, Address address, OperandSize size = kFourBytes) override { ASSERT_EQUAL(size, kFourBytes); - LoadFromOffset(TMP, address, size); + Load(TMP, address, size); cmp(value, Operand(TMP)); } @@ -1022,32 +1008,34 @@ class Assembler : public AssemblerBase { void StoreIntoArray(Register object, Register slot, Register value, - CanBeSmi can_value_be_smi = kValueCanBeSmi); - void StoreIntoObjectOffset(Register object, - int32_t offset, - Register value, - CanBeSmi can_value_be_smi = kValueCanBeSmi, - MemoryOrder memory_order = kRelaxedNonAtomic); + CanBeSmi can_value_be_smi = kValueCanBeSmi) override; + void StoreIntoObjectOffset( + Register object, + int32_t offset, + Register value, + CanBeSmi can_value_be_smi = kValueCanBeSmi, + MemoryOrder memory_order = kRelaxedNonAtomic) override; void StoreIntoObjectNoBarrier( Register object, const Address& dest, Register value, MemoryOrder memory_order = kRelaxedNonAtomic) override; - void StoreIntoObjectNoBarrier(Register object, - const Address& dest, - const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic); + void StoreIntoObjectNoBarrier( + Register object, + const Address& dest, + const Object& value, + MemoryOrder memory_order = kRelaxedNonAtomic) override; void StoreIntoObjectOffsetNoBarrier( Register object, int32_t offset, Register value, - MemoryOrder memory_order = kRelaxedNonAtomic); + MemoryOrder memory_order = kRelaxedNonAtomic) override; void StoreIntoObjectOffsetNoBarrier( Register object, int32_t offset, const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic); + MemoryOrder memory_order = kRelaxedNonAtomic) override; // Stores a non-tagged value into a heap object. void StoreInternalPointer(Register object, @@ -1106,46 +1094,40 @@ class Assembler : public AssemblerBase { OperandSize sz, Condition cond); + void Load(Register reg, + const Address& address, + OperandSize type, + Condition cond); + void Load(Register reg, + const Address& address, + OperandSize type = kFourBytes) override { + Load(reg, address, type, AL); + } void LoadFromOffset(Register reg, - const Address& address, - OperandSize type, - Condition cond); - void LoadFromOffset(Register reg, - const Address& address, + Register base, + int32_t offset, OperandSize type = kFourBytes) override { - LoadFromOffset(reg, address, type, AL); + LoadFromOffset(reg, base, offset, type, AL); } void LoadFromOffset(Register reg, Register base, int32_t offset, - OperandSize type = kFourBytes, - Condition cond = AL) { - LoadFromOffset(reg, Address(base, offset), type, cond); + OperandSize type, + Condition cond) { + Load(reg, Address(base, offset), type, cond); } void LoadFieldFromOffset(Register reg, Register base, int32_t offset, - OperandSize sz = kFourBytes) override { - LoadFromOffset(reg, FieldAddress(base, offset), sz, AL); + OperandSize type = kFourBytes) override { + LoadFieldFromOffset(reg, base, offset, type, AL); } void LoadFieldFromOffset(Register reg, Register base, int32_t offset, OperandSize type, Condition cond) { - LoadFromOffset(reg, FieldAddress(base, offset), type, cond); - } - void LoadCompressedFieldFromOffset(Register reg, - Register base, - int32_t offset) override { - LoadCompressedFieldFromOffset(reg, base, offset, kFourBytes, AL); - } - void LoadCompressedFieldFromOffset(Register reg, - Register base, - int32_t offset, - OperandSize type, - Condition cond = AL) { - LoadFieldFromOffset(reg, base, offset, type, cond); + Load(reg, FieldAddress(base, offset), type, cond); } // For loading indexed payloads out of tagged objects like Arrays. If the // payload objects are word-sized, use TIMES_HALF_WORD_SIZE if the contents of @@ -1155,47 +1137,52 @@ class Assembler : public AssemblerBase { int32_t payload_start, Register index, ScaleFactor scale, - OperandSize type = kFourBytes) { + OperandSize type = kFourBytes) override { add(dst, base, Operand(index, LSL, scale)); LoadFromOffset(dst, dst, payload_start - kHeapObjectTag, type); } - void LoadIndexedCompressed(Register dst, - Register base, - int32_t offset, - Register index) { - add(dst, base, Operand(index, LSL, TIMES_COMPRESSED_WORD_SIZE)); - LoadCompressedFieldFromOffset(dst, dst, offset); - } void LoadFromStack(Register dst, intptr_t depth); void StoreToStack(Register src, intptr_t depth); void CompareToStack(Register src, intptr_t depth); + void Store(Register reg, + const Address& address, + OperandSize type, + Condition cond); + void Store(Register reg, + const Address& address, + OperandSize type = kFourBytes) override { + Store(reg, address, type, AL); + } void StoreToOffset(Register reg, - const Address& address, - OperandSize type, - Condition cond); - void StoreToOffset(Register reg, - const Address& address, + Register base, + int32_t offset, OperandSize type = kFourBytes) override { - StoreToOffset(reg, address, type, AL); + StoreToOffset(reg, base, offset, type, AL); } void StoreToOffset(Register reg, Register base, int32_t offset, - OperandSize type = kFourBytes, - Condition cond = AL) { - StoreToOffset(reg, Address(base, offset), type, cond); + OperandSize type, + Condition cond) { + Store(reg, Address(base, offset), type, cond); } void StoreFieldToOffset(Register reg, Register base, int32_t offset, - OperandSize type = kFourBytes, - Condition cond = AL) { - StoreToOffset(reg, FieldAddress(base, offset), type, cond); + OperandSize type = kFourBytes) override { + StoreFieldToOffset(reg, base, offset, type, AL); + } + void StoreFieldToOffset(Register reg, + Register base, + int32_t offset, + OperandSize type, + Condition cond) { + Store(reg, FieldAddress(base, offset), type, cond); } void StoreZero(const Address& address, Register temp) { mov(temp, Operand(0)); - StoreToOffset(temp, address); + Store(temp, address); } void LoadSFromOffset(SRegister reg, Register base, @@ -1545,16 +1532,9 @@ class Assembler : public AssemblerBase { Register field, Register scratch); - void LoadCompressedFieldAddressForRegOffset(Register address, - Register instance, - Register offset_in_words_as_smi) { - return LoadFieldAddressForRegOffset(address, instance, - offset_in_words_as_smi); - } - void LoadFieldAddressForRegOffset(Register address, Register instance, - Register offset_in_words_as_smi); + Register offset_in_words_as_smi) override; void LoadFieldAddressForOffset(Register address, Register instance, diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc index a9987b3301fc..c937ce58f0fb 100644 --- a/runtime/vm/compiler/assembler/assembler_arm64.cc +++ b/runtime/vm/compiler/assembler/assembler_arm64.cc @@ -942,11 +942,15 @@ Address Assembler::PrepareLargeOffset(Register base, } } -void Assembler::LoadFromOffset(Register dest, - const Address& addr, - OperandSize sz) { - ldr(dest, PrepareLargeOffset(addr.base(), addr.offset(), sz, addr.type()), - sz); +void Assembler::Load(Register dst, const Address& addr, OperandSize sz) { + if (addr.type() == Address::AddressType::Offset || + addr.type() == Address::AddressType::PairOffset) { + ldr(dst, PrepareLargeOffset(addr.base(), addr.offset(), sz, addr.type()), + sz); + } else { + // Pass the address through unchanged. + ldr(dst, addr, sz); + } } void Assembler::LoadSFromOffset(VRegister dest, Register base, int32_t offset) { @@ -964,10 +968,15 @@ void Assembler::LoadQFromOffset(VRegister dest, Register base, int32_t offset) { fldrq(dest, PrepareLargeOffset(base, offset, kQWord, type)); } -void Assembler::StoreToOffset(Register src, - const Address& addr, - OperandSize sz) { - str(src, PrepareLargeOffset(addr.base(), addr.offset(), sz, addr.type()), sz); +void Assembler::Store(Register src, const Address& addr, OperandSize sz) { + if (addr.type() == Address::AddressType::Offset || + addr.type() == Address::AddressType::PairOffset) { + str(src, PrepareLargeOffset(addr.base(), addr.offset(), sz, addr.type()), + sz); + } else { + // Pass the address through unchanged. + str(src, addr, sz); + } } void Assembler::StorePairToOffset(Register low, @@ -1024,55 +1033,19 @@ void Assembler::VRSqrts(VRegister vd, VRegister vn) { vmuls(vd, vd, VTMP); } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::LoadCompressed(Register dest, const Address& slot) { -#if !defined(DART_COMPRESSED_POINTERS) - ldr(dest, slot); -#else ldr(dest, slot, kUnsignedFourBytes); // Zero-extension. add(dest, dest, Operand(HEAP_BITS, LSL, 32)); -#endif } void Assembler::LoadCompressedFromOffset(Register dest, Register base, int32_t offset) { -#if !defined(DART_COMPRESSED_POINTERS) - LoadFromOffset(dest, base, offset, kObjectBytes); -#else LoadFromOffset(dest, base, offset, kUnsignedFourBytes); // Zero-extension. add(dest, dest, Operand(HEAP_BITS, LSL, 32)); -#endif } - -void Assembler::LoadCompressedSmi(Register dest, const Address& slot) { -#if !defined(DART_COMPRESSED_POINTERS) - ldr(dest, slot); -#else - ldr(dest, slot, kUnsignedFourBytes); // Zero-extension. -#endif -#if defined(DEBUG) - Label done; - BranchIfSmi(dest, &done, kNearJump); - Stop("Expected Smi"); - Bind(&done); -#endif -} - -void Assembler::LoadCompressedSmiFromOffset(Register dest, - Register base, - int32_t offset) { -#if !defined(DART_COMPRESSED_POINTERS) - LoadFromOffset(dest, base, offset); -#else - LoadFromOffset(dest, base, offset, kUnsignedFourBytes); // Zero-extension. -#endif -#if defined(DEBUG) - Label done; - BranchIfSmi(dest, &done); - Stop("Expected Smi"); - Bind(&done); #endif -} void Assembler::StoreIntoObjectOffset(Register object, int32_t offset, @@ -1087,6 +1060,7 @@ void Assembler::StoreIntoObjectOffset(Register object, StoreBarrier(object, value, value_can_be_smi); } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::StoreCompressedIntoObjectOffset(Register object, int32_t offset, Register value, @@ -1099,6 +1073,7 @@ void Assembler::StoreCompressedIntoObjectOffset(Register object, } StoreBarrier(object, value, value_can_be_smi); } +#endif void Assembler::StoreIntoObject(Register object, const Address& dest, @@ -1111,6 +1086,7 @@ void Assembler::StoreIntoObject(Register object, StoreBarrier(object, value, can_be_smi); } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::StoreCompressedIntoObject(Register object, const Address& dest, Register value, @@ -1121,6 +1097,7 @@ void Assembler::StoreCompressedIntoObject(Register object, str(value, dest, kObjectBytes); StoreBarrier(object, value, can_be_smi); } +#endif void Assembler::StoreBarrier(Register object, Register value, @@ -1195,6 +1172,7 @@ void Assembler::StoreIntoArray(Register object, StoreIntoArrayBarrier(object, slot, value, can_be_smi); } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::StoreCompressedIntoArray(Register object, Register slot, Register value, @@ -1202,6 +1180,7 @@ void Assembler::StoreCompressedIntoArray(Register object, str(value, Address(slot, 0), kObjectBytes); StoreIntoArrayBarrier(object, slot, value, can_be_smi); } +#endif void Assembler::StoreIntoArrayBarrier(Register object, Register slot, @@ -1274,6 +1253,7 @@ void Assembler::StoreIntoObjectNoBarrier(Register object, // No store buffer update. } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::StoreCompressedIntoObjectNoBarrier(Register object, const Address& dest, Register value, @@ -1298,6 +1278,7 @@ void Assembler::StoreCompressedIntoObjectNoBarrier(Register object, #endif // defined(DEBUG) // No store buffer update. } +#endif void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, int32_t offset, @@ -1313,6 +1294,7 @@ void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, } } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::StoreCompressedIntoObjectOffsetNoBarrier( Register object, int32_t offset, @@ -1328,6 +1310,7 @@ void Assembler::StoreCompressedIntoObjectOffsetNoBarrier( StoreCompressedIntoObjectNoBarrier(object, Address(TMP), value); } } +#endif void Assembler::StoreIntoObjectNoBarrier(Register object, const Address& dest, @@ -1346,6 +1329,7 @@ void Assembler::StoreIntoObjectNoBarrier(Register object, } } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::StoreCompressedIntoObjectNoBarrier(Register object, const Address& dest, const Object& value, @@ -1364,6 +1348,7 @@ void Assembler::StoreCompressedIntoObjectNoBarrier(Register object, str(TMP2, dest, kObjectBytes); } } +#endif void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, int32_t offset, @@ -1387,6 +1372,7 @@ void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, } } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::StoreCompressedIntoObjectOffsetNoBarrier( Register object, int32_t offset, @@ -1411,6 +1397,7 @@ void Assembler::StoreCompressedIntoObjectOffsetNoBarrier( StoreCompressedIntoObjectNoBarrier(object, Address(TMP), value); } } +#endif void Assembler::StoreInternalPointer(Register object, const Address& dest, @@ -2128,8 +2115,7 @@ void Assembler::TryAllocateObject(intptr_t cid, const uword tags = target::MakeTagWordForNewSpaceObject(cid, instance_size); LoadImmediate(temp_reg, tags); - StoreToOffset(temp_reg, - FieldAddress(instance_reg, target::Object::tags_offset())); + Store(temp_reg, FieldAddress(instance_reg, target::Object::tags_offset())); } else { b(failure); } @@ -2355,6 +2341,7 @@ void Assembler::LoadStaticFieldAddress(Register address, Operand(scratch, LSL, target::kWordSizeLog2 - kSmiTagShift)); } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::LoadCompressedFieldAddressForRegOffset( Register address, Register instance, @@ -2364,6 +2351,7 @@ void Assembler::LoadCompressedFieldAddressForRegOffset( target::kCompressedWordSizeLog2 - kSmiTagShift)); AddImmediate(address, -kHeapObjectTag); } +#endif void Assembler::LoadFieldAddressForRegOffset(Register address, Register instance, diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h index 728d5689d1df..fc178857e4a1 100644 --- a/runtime/vm/compiler/assembler/assembler_arm64.h +++ b/runtime/vm/compiler/assembler/assembler_arm64.h @@ -500,7 +500,7 @@ class Assembler : public AssemblerBase { } } - void Bind(Label* label); + void Bind(Label* label) override; // Unconditional jump to a given label. [distance] is ignored on ARM. void Jump(Label* label, JumpDistance distance = kFarJump) { b(label); } // Unconditional jump to a given address in register. @@ -511,12 +511,6 @@ class Assembler : public AssemblerBase { br(TMP); } - void LoadField(Register dst, const FieldAddress& address) override { - LoadFromOffset(dst, address); - } - void LoadCompressedField(Register dst, const FieldAddress& address) override { - LoadCompressed(dst, address); - } void LoadMemoryValue(Register dst, Register base, int32_t offset) { LoadFromOffset(dst, base, offset, kEightBytes); } @@ -544,14 +538,14 @@ class Assembler : public AssemblerBase { #endif } +#if defined(DART_COMPRESSED_POINTERS) void LoadAcquireCompressed(Register dst, Register address, int32_t offset = 0) override { LoadAcquire(dst, address, offset, kObjectBytes); -#if defined(DART_COMPRESSED_POINTERS) add(dst, dst, Operand(HEAP_BITS, LSL, 32)); -#endif } +#endif void StoreRelease(Register src, Register address, @@ -567,9 +561,10 @@ class Assembler : public AssemblerBase { #endif } +#if defined(DART_COMPRESSED_POINTERS) void StoreReleaseCompressed(Register src, Register address, - int32_t offset = 0) { + int32_t offset = 0) override { Register kResultReg = address; if (offset != 0) { kResultReg = TMP; @@ -580,18 +575,12 @@ class Assembler : public AssemblerBase { TsanStoreRelease(kResultReg); #endif } - - void CompareWithCompressedFieldFromOffset(Register value, - Register base, - int32_t offset) { - LoadCompressedFieldFromOffset(TMP, base, offset); - cmp(value, Operand(TMP)); - } +#endif void CompareWithMemoryValue(Register value, Address address, OperandSize sz = kEightBytes) override { - LoadFromOffset(TMP, address, sz); + Load(TMP, address, sz); cmp(value, Operand(TMP), sz); } @@ -1880,31 +1869,9 @@ class Assembler : public AssemblerBase { int32_t offset, OperandSize sz, Address::AddressType addr_type); - void LoadFromOffset(Register dest, - const Address& address, - OperandSize sz = kEightBytes) override; - void LoadFromOffset(Register dest, - Register base, - int32_t offset, - OperandSize sz = kEightBytes) { - LoadFromOffset(dest, Address(base, offset), sz); - } - void LoadFieldFromOffset(Register dest, - Register base, - int32_t offset, - OperandSize sz = kEightBytes) override { - LoadFromOffset(dest, FieldAddress(base, offset), sz); - } - void LoadCompressedFieldFromOffset(Register dest, - Register base, - int32_t offset) override { - LoadCompressedFromOffset(dest, base, offset - kHeapObjectTag); - } - void LoadCompressedSmiFieldFromOffset(Register dest, - Register base, - int32_t offset) { - LoadCompressedSmiFromOffset(dest, base, offset - kHeapObjectTag); - } + void Load(Register dest, + const Address& address, + OperandSize sz = kEightBytes) override; // For loading indexed payloads out of tagged objects like Arrays. If the // payload objects are word-sized, use TIMES_HALF_WORD_SIZE if the contents of // [index] is a Smi, otherwise TIMES_WORD_SIZE if unboxed. @@ -1913,17 +1880,19 @@ class Assembler : public AssemblerBase { int32_t payload_offset, Register index, ScaleFactor scale, - OperandSize sz = kEightBytes) { + OperandSize sz = kEightBytes) override { add(dest, base, Operand(index, LSL, scale)); LoadFromOffset(dest, dest, payload_offset - kHeapObjectTag, sz); } +#if defined(DART_COMPRESSED_POINTERS) void LoadIndexedCompressed(Register dest, Register base, int32_t offset, - Register index) { + Register index) override { add(dest, base, Operand(index, LSL, TIMES_COMPRESSED_WORD_SIZE)); LoadCompressedFieldFromOffset(dest, dest, offset); } +#endif void LoadSFromOffset(VRegister dest, Register base, int32_t offset); void LoadDFromOffset(VRegister dest, Register base, int32_t offset); void LoadDFieldFromOffset(VRegister dest, Register base, int32_t offset) { @@ -1938,23 +1907,11 @@ class Assembler : public AssemblerBase { void StoreToStack(Register src, intptr_t depth); void CompareToStack(Register src, intptr_t depth); - void StoreToOffset(Register src, - const Address& address, - OperandSize sz = kEightBytes) override; - void StoreToOffset(Register src, - Register base, - int32_t offset, - OperandSize sz = kEightBytes) { - StoreToOffset(src, Address(base, offset), sz); - } - void StoreFieldToOffset(Register src, - Register base, - int32_t offset, - OperandSize sz = kEightBytes) { - StoreToOffset(src, FieldAddress(base, offset), sz); - } + void Store(Register src, + const Address& address, + OperandSize sz = kEightBytes) override; void StoreZero(const Address& address, Register temp = kNoRegister) { - StoreToOffset(ZR, address); + Store(ZR, address); } void StorePairToOffset(Register low, @@ -1997,12 +1954,12 @@ class Assembler : public AssemblerBase { } } - void LoadCompressed(Register dest, const Address& slot); - void LoadCompressedFromOffset(Register dest, Register base, int32_t offset); - void LoadCompressedSmi(Register dest, const Address& slot) override; - void LoadCompressedSmiFromOffset(Register dest, - Register base, - int32_t offset); +#if defined(DART_COMPRESSED_POINTERS) + void LoadCompressed(Register dest, const Address& slot) override; + void LoadCompressedFromOffset(Register dest, + Register base, + int32_t offset) override; +#endif // Store into a heap object and apply the generational and incremental write // barriers. All stores into heap objects must pass through this function or, @@ -2014,76 +1971,93 @@ class Assembler : public AssemblerBase { Register value, CanBeSmi can_value_be_smi = kValueCanBeSmi, MemoryOrder memory_order = kRelaxedNonAtomic) override; +#if defined(DART_COMPRESSED_POINTERS) void StoreCompressedIntoObject( Register object, const Address& dest, Register value, CanBeSmi can_value_be_smi = kValueCanBeSmi, MemoryOrder memory_order = kRelaxedNonAtomic) override; +#endif void StoreBarrier(Register object, Register value, CanBeSmi can_value_be_smi); void StoreIntoArray(Register object, Register slot, Register value, - CanBeSmi can_value_be_smi = kValueCanBeSmi); - void StoreCompressedIntoArray(Register object, - Register slot, - Register value, - CanBeSmi can_value_be_smi = kValueCanBeSmi); + CanBeSmi can_value_be_smi = kValueCanBeSmi) override; +#if defined(DART_COMPRESSED_POINTERS) + void StoreCompressedIntoArray( + Register object, + Register slot, + Register value, + CanBeSmi can_value_be_smi = kValueCanBeSmi) override; +#endif void StoreIntoArrayBarrier(Register object, Register slot, Register value, CanBeSmi can_value_be_smi); - void StoreIntoObjectOffset(Register object, - int32_t offset, - Register value, - CanBeSmi can_value_be_smi = kValueCanBeSmi, - MemoryOrder memory_order = kRelaxedNonAtomic); + void StoreIntoObjectOffset( + Register object, + int32_t offset, + Register value, + CanBeSmi can_value_be_smi = kValueCanBeSmi, + MemoryOrder memory_order = kRelaxedNonAtomic) override; +#if defined(DART_COMPRESSED_POINTERS) void StoreCompressedIntoObjectOffset( Register object, int32_t offset, Register value, CanBeSmi can_value_be_smi = kValueCanBeSmi, - MemoryOrder memory_order = kRelaxedNonAtomic); + MemoryOrder memory_order = kRelaxedNonAtomic) override; +#endif void StoreIntoObjectNoBarrier( Register object, const Address& dest, Register value, MemoryOrder memory_order = kRelaxedNonAtomic) override; +#if defined(DART_COMPRESSED_POINTERS) void StoreCompressedIntoObjectNoBarrier( Register object, const Address& dest, Register value, MemoryOrder memory_order = kRelaxedNonAtomic) override; +#endif void StoreIntoObjectOffsetNoBarrier( Register object, int32_t offset, Register value, - MemoryOrder memory_order = kRelaxedNonAtomic); + MemoryOrder memory_order = kRelaxedNonAtomic) override; +#if defined(DART_COMPRESSED_POINTERS) void StoreCompressedIntoObjectOffsetNoBarrier( Register object, int32_t offset, Register value, - MemoryOrder memory_order = kRelaxedNonAtomic); - void StoreIntoObjectNoBarrier(Register object, - const Address& dest, - const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic); + MemoryOrder memory_order = kRelaxedNonAtomic) override; +#endif + void StoreIntoObjectNoBarrier( + Register object, + const Address& dest, + const Object& value, + MemoryOrder memory_order = kRelaxedNonAtomic) override; +#if defined(DART_COMPRESSED_POINTERS) void StoreCompressedIntoObjectNoBarrier( Register object, const Address& dest, const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic); + MemoryOrder memory_order = kRelaxedNonAtomic) override; +#endif void StoreIntoObjectOffsetNoBarrier( Register object, int32_t offset, const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic); + MemoryOrder memory_order = kRelaxedNonAtomic) override; +#if defined(DART_COMPRESSED_POINTERS) void StoreCompressedIntoObjectOffsetNoBarrier( Register object, int32_t offset, const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic); + MemoryOrder memory_order = kRelaxedNonAtomic) override; +#endif // Stores a non-tagged value into a heap object. void StoreInternalPointer(Register object, @@ -2371,13 +2345,16 @@ class Assembler : public AssemblerBase { Register field, Register scratch); - void LoadCompressedFieldAddressForRegOffset(Register address, - Register instance, - Register offset_in_words_as_smi); +#if defined(DART_COMPRESSED_POINTERS) + void LoadCompressedFieldAddressForRegOffset( + Register address, + Register instance, + Register offset_in_words_as_smi) override; +#endif void LoadFieldAddressForRegOffset(Register address, Register instance, - Register offset_in_words_as_smi); + Register offset_in_words_as_smi) override; void LoadFieldAddressForOffset(Register address, Register instance, diff --git a/runtime/vm/compiler/assembler/assembler_base.cc b/runtime/vm/compiler/assembler/assembler_base.cc index 083f58a5306a..5ad969f64fff 100644 --- a/runtime/vm/compiler/assembler/assembler_base.cc +++ b/runtime/vm/compiler/assembler/assembler_base.cc @@ -32,54 +32,159 @@ AssemblerBase::~AssemblerBase() {} void AssemblerBase::LoadFromSlot(Register dst, Register base, const Slot& slot) { - auto const rep = slot.representation(); - const FieldAddress address(base, slot.offset_in_bytes()); - if (rep != kTagged) { - auto const sz = RepresentationUtils::OperandSize(rep); - return LoadFromOffset(dst, address, sz); + if (slot.is_unboxed()) { + // The result cannot be a floating point or SIMD value. + ASSERT(slot.representation() == kUntagged || + RepresentationUtils::IsUnboxedInteger(slot.representation())); + // Since we only have a single destination register, the result value must + // fit into a register. + ASSERT(RepresentationUtils::ValueSize(slot.representation()) <= + compiler::target::kWordSize); + const intptr_t offset = slot.offset_in_bytes() - kHeapObjectTag; + auto const sz = RepresentationUtils::OperandSize(slot.representation()); + return LoadFromOffset(dst, base, offset, sz); } - if (slot.is_compressed()) { - if (slot.type().ToCid() == kSmiCid) { - return LoadCompressedSmi(dst, address); - } else { - return LoadCompressedField(dst, address); - } + if (!slot.is_compressed()) { + LoadFieldFromOffset(dst, base, slot.offset_in_bytes()); + } else if (slot.type().ToCid() == kSmiCid) { + LoadCompressedSmiFieldFromOffset(dst, base, slot.offset_in_bytes()); + } else { + LoadCompressedFieldFromOffset(dst, base, slot.offset_in_bytes()); } - return LoadField(dst, address); } -void AssemblerBase::StoreToSlot(Register src, Register base, const Slot& slot) { - auto const rep = slot.representation(); - const FieldAddress address(base, slot.offset_in_bytes()); - if (rep != kTagged) { - auto const sz = RepresentationUtils::OperandSize(rep); - return StoreToOffset(src, address, sz); +void AssemblerBase::StoreToSlot(Register src, + Register base, + const Slot& slot, + MemoryOrder memory_order) { + auto const can_be_smi = + slot.type().CanBeSmi() ? kValueCanBeSmi : kValueIsNotSmi; + StoreToSlot(src, base, slot, can_be_smi, memory_order); +} + +void AssemblerBase::StoreToSlot(Register src, + Register base, + const Slot& slot, + CanBeSmi can_be_smi, + MemoryOrder memory_order) { + if (slot.is_unboxed()) { + // Same as the no barrier case. + StoreToSlotNoBarrier(src, base, slot, memory_order); } if (slot.is_compressed()) { - return StoreCompressedIntoObject( - base, address, src, - slot.type().CanBeSmi() ? kValueCanBeSmi : kValueIsNotSmi); + StoreCompressedIntoObjectOffset(base, slot.offset_in_bytes(), src, + can_be_smi, memory_order); + } else { + StoreIntoObjectOffset(base, slot.offset_in_bytes(), src, can_be_smi, + memory_order); } - return StoreIntoObject( - base, address, src, - slot.type().CanBeSmi() ? kValueCanBeSmi : kValueIsNotSmi); } void AssemblerBase::StoreToSlotNoBarrier(Register src, Register base, - const Slot& slot) { - auto const rep = slot.representation(); - const FieldAddress address(base, slot.offset_in_bytes()); - if (rep != kTagged) { - auto const sz = RepresentationUtils::OperandSize(rep); - return StoreToOffset(src, address, sz); + const Slot& slot, + MemoryOrder memory_order) { + if (slot.is_unboxed()) { + // The stored value cannot be a floating point or SIMD value. + ASSERT(slot.representation() == kUntagged || + RepresentationUtils::IsUnboxedInteger(slot.representation())); + // Since we only have a single source register, the stored value must + // fit into a register. + ASSERT(RepresentationUtils::ValueSize(slot.representation()) <= + compiler::target::kWordSize); + const intptr_t offset = slot.offset_in_bytes() - kHeapObjectTag; + auto const sz = RepresentationUtils::OperandSize(slot.representation()); + return StoreToOffset(src, base, offset, sz); } if (slot.is_compressed()) { - return StoreCompressedIntoObjectNoBarrier(base, address, src); + StoreCompressedIntoObjectOffsetNoBarrier(base, slot.offset_in_bytes(), src, + memory_order); + } else { + StoreIntoObjectOffsetNoBarrier(base, slot.offset_in_bytes(), src, + memory_order); } - return StoreIntoObjectNoBarrier(base, address, src); } +void AssemblerBase::LoadFromOffset(Register dst, + Register base, + int32_t offset, + OperandSize sz) { + Load(dst, Address(base, offset), sz); +} + +void AssemblerBase::StoreToOffset(Register src, + Register base, + int32_t offset, + OperandSize sz) { + Store(src, Address(base, offset), sz); +} + +void AssemblerBase::LoadField(Register dst, + const FieldAddress& address, + OperandSize sz) { + Load(dst, address, sz); +} + +void AssemblerBase::LoadCompressedField(Register dst, + const FieldAddress& address) { + LoadCompressed(dst, address); +} + +void AssemblerBase::StoreIntoObjectOffset(Register object, + int32_t offset, + Register value, + CanBeSmi can_be_smi, + MemoryOrder memory_order) { + StoreIntoObject(object, FieldAddress(object, offset), value, can_be_smi, + memory_order); +} +void AssemblerBase::StoreIntoObjectOffsetNoBarrier(Register object, + int32_t offset, + Register value, + MemoryOrder memory_order) { + StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value, + memory_order); +} +void AssemblerBase::StoreIntoObjectOffsetNoBarrier(Register object, + int32_t offset, + const Object& value, + MemoryOrder memory_order) { + StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value, + memory_order); +} + +#if defined(DART_COMPRESSED_POINTERS) +void AssemblerBase::LoadCompressedFromOffset(Register dst, + Register base, + int32_t offset) { + LoadCompressed(dst, Address(base, offset)); +} +void AssemblerBase::StoreCompressedIntoObjectOffset(Register object, + int32_t offset, + Register value, + CanBeSmi can_be_smi, + MemoryOrder memory_order) { + StoreCompressedIntoObject(object, FieldAddress(object, offset), value, + can_be_smi, memory_order); +} +void AssemblerBase::StoreCompressedIntoObjectOffsetNoBarrier( + Register object, + int32_t offset, + Register value, + MemoryOrder memory_order) { + StoreCompressedIntoObjectNoBarrier(object, FieldAddress(object, offset), + value, memory_order); +} +void AssemblerBase::StoreCompressedIntoObjectOffsetNoBarrier( + Register object, + int32_t offset, + const Object& value, + MemoryOrder memory_order) { + StoreCompressedIntoObjectNoBarrier(object, FieldAddress(object, offset), + value, memory_order); +} +#endif + void AssemblerBase::UnrolledMemCopy(Register dst_base, intptr_t dst_offset, Register src_base, @@ -89,28 +194,24 @@ void AssemblerBase::UnrolledMemCopy(Register dst_base, intptr_t offset = 0; if (target::kWordSize >= 8) { while (offset + 8 <= size) { - LoadFromOffset(temp, Address(src_base, src_offset + offset), kEightBytes); - StoreToOffset(temp, Address(dst_base, dst_offset + offset), kEightBytes); + LoadFromOffset(temp, src_base, src_offset + offset, kEightBytes); + StoreToOffset(temp, dst_base, dst_offset + offset, kEightBytes); offset += 8; } } while (offset + 4 <= size) { - LoadFromOffset(temp, Address(src_base, src_offset + offset), - kUnsignedFourBytes); - StoreToOffset(temp, Address(dst_base, dst_offset + offset), - kUnsignedFourBytes); + LoadFromOffset(temp, src_base, src_offset + offset, kUnsignedFourBytes); + StoreToOffset(temp, dst_base, dst_offset + offset, kUnsignedFourBytes); offset += 4; } while (offset + 2 <= size) { - LoadFromOffset(temp, Address(src_base, src_offset + offset), - kUnsignedTwoBytes); - StoreToOffset(temp, Address(dst_base, dst_offset + offset), - kUnsignedTwoBytes); + LoadFromOffset(temp, src_base, src_offset + offset, kUnsignedTwoBytes); + StoreToOffset(temp, dst_base, dst_offset + offset, kUnsignedTwoBytes); offset += 2; } while (offset + 1 <= size) { - LoadFromOffset(temp, Address(src_base, src_offset + offset), kUnsignedByte); - StoreToOffset(temp, Address(dst_base, dst_offset + offset), kUnsignedByte); + LoadFromOffset(temp, src_base, src_offset + offset, kUnsignedByte); + StoreToOffset(temp, dst_base, dst_offset + offset, kUnsignedByte); offset += 1; } ASSERT(offset == size); diff --git a/runtime/vm/compiler/assembler/assembler_base.h b/runtime/vm/compiler/assembler/assembler_base.h index 8a282dbff9ef..a8cc3151e5c6 100644 --- a/runtime/vm/compiler/assembler/assembler_base.h +++ b/runtime/vm/compiler/assembler/assembler_base.h @@ -629,6 +629,8 @@ class AssemblerBase : public StackResource { virtual void SmiTag(Register r) = 0; + virtual void Bind(Label* label) = 0; + // If Smis are compressed and the Smi value in dst is non-negative, ensures // the upper bits are cleared. If Smis are not compressed, is a no-op. // @@ -704,14 +706,6 @@ class AssemblerBase : public StackResource { instance_reg, temp); } - virtual void LoadFromOffset(Register dst, - const Address& address, - OperandSize sz = kWordBytes) = 0; - // Does not use write barriers, use StoreIntoObject instead for boxed fields. - virtual void StoreToOffset(Register src, - const Address& address, - OperandSize sz = kWordBytes) = 0; - virtual void BranchIfSmi(Register reg, Label* label, JumpDistance distance = kFarJump) = 0; @@ -745,99 +739,360 @@ class AssemblerBase : public StackResource { kRelaxedNonAtomic, }; - virtual void LoadAcquire(Register reg, - Register address, - int32_t offset = 0, - OperandSize size = kWordBytes) = 0; - virtual void LoadFieldAddressForOffset(Register reg, Register base, int32_t offset) = 0; + virtual void LoadFieldAddressForRegOffset( + Register address, + Register instance, + Register offset_in_words_as_smi) = 0; - virtual void LoadField(Register dst, const FieldAddress& address) = 0; - virtual void LoadFieldFromOffset(Register reg, - Register base, - int32_t offset, - OperandSize = kWordBytes) = 0; - void LoadFromSlot(Register dst, Register base, const Slot& slot); + virtual void LoadAcquire(Register reg, + Register address, + int32_t offset = 0, + OperandSize size = kWordBytes) = 0; + virtual void StoreRelease(Register src, + Register address, + int32_t offset = 0) = 0; + virtual void Load(Register dst, + const Address& address, + OperandSize sz = kWordBytes) = 0; + // Does not use write barriers, use StoreIntoObject instead for boxed fields. + virtual void Store(Register src, + const Address& address, + OperandSize sz = kWordBytes) = 0; virtual void StoreIntoObject( - Register object, // Object we are storing into. - const Address& dest, // Where we are storing into. - Register value, // Value we are storing. + Register object, // Object being stored into. + const Address& address, // Offset into object. + Register value, // Value being stored. CanBeSmi can_be_smi = kValueCanBeSmi, MemoryOrder memory_order = kRelaxedNonAtomic) = 0; virtual void StoreIntoObjectNoBarrier( - Register object, // Object we are storing into. - const Address& dest, // Where we are storing into. - Register value, // Value we are storing. + Register object, // Object being stored into. + const Address& address, // Offset into object. + Register value, // Value being stored. + MemoryOrder memory_order = kRelaxedNonAtomic) = 0; + virtual void StoreIntoObjectNoBarrier( + Register object, // Object being stored into. + const Address& address, // Offset into object. + const Object& value, // Value being stored. MemoryOrder memory_order = kRelaxedNonAtomic) = 0; - // For native unboxed slots, both methods are the same, as no write barrier - // is needed. - void StoreToSlot(Register src, Register base, const Slot& slot); - void StoreToSlotNoBarrier(Register src, Register base, const Slot& slot); - // Loads a Smi, handling sign extension appropriately when compressed. - // In DEBUG mode, also checks that the loaded value is a Smi and halts if not. - virtual void LoadCompressedSmi(Register dst, const Address& slot) = 0; + virtual void LoadIndexedPayload(Register dst, + Register base, + int32_t offset, + Register index, + ScaleFactor scale, + OperandSize sz = kWordBytes) = 0; + virtual void StoreIntoArray(Register object, + Register slot, + Register value, + CanBeSmi can_value_be_smi = kValueCanBeSmi) = 0; + + // For virtual XFromOffset methods, the base method implementation creates an + // appropriate address from the base register and offset and calls the + // corresponding address-taking method. These should be overridden for + // architectures where offsets should not be converted to addresses without + // additional precautions, or for when the ARM-specific Assembler needs + // to override with an overloaded version for the Condition argument. + + virtual void LoadFromOffset(Register dst, + Register base, + int32_t offset, + OperandSize sz = kWordBytes); + // Does not use write barriers, use StoreIntoObject instead for boxed fields. + virtual void StoreToOffset(Register src, + Register base, + int32_t offset, + OperandSize sz = kWordBytes); + + virtual void StoreIntoObjectOffset( + Register object, // Object being stored into. + int32_t offset, // Offset into object. + Register value, // Value being stored. + CanBeSmi can_be_smi = kValueCanBeSmi, + MemoryOrder memory_order = kRelaxedNonAtomic); + virtual void StoreIntoObjectOffsetNoBarrier( + Register object, // Object being stored into. + int32_t offset, // Offset into object. + Register value, // Value being stored. + MemoryOrder memory_order = kRelaxedNonAtomic); + virtual void StoreIntoObjectOffsetNoBarrier( + Register object, // Object being stored into. + int32_t offset, // Offset into object. + const Object& value, // Value being stored. + MemoryOrder memory_order = kRelaxedNonAtomic); + + void LoadField(Register dst, + const FieldAddress& address, + OperandSize sz = kWordBytes); + virtual void LoadFieldFromOffset(Register dst, + Register base, + int32_t offset, + OperandSize sz = kWordBytes) { + LoadFromOffset(dst, base, offset - kHeapObjectTag, sz); + } + // Does not use write barriers, use StoreIntoObjectOffset instead for + // boxed fields. + virtual void StoreFieldToOffset(Register src, + Register base, + int32_t offset, + OperandSize sz = kWordBytes) { + StoreToOffset(src, base, offset - kHeapObjectTag, sz); + } + + // Loads a Smi. In DEBUG mode, also checks that the loaded value is a Smi and + // halts if not. + void LoadSmi(Register dst, const Address& address) { + Load(dst, address); + DEBUG_ONLY(VerifySmi(dst)); + } + + // Loads a Smi. In DEBUG mode, also checks that the loaded value is a Smi and + // halts if not. + void LoadSmiFromOffset(Register dst, Register base, int32_t offset) { + LoadFromOffset(dst, base, offset); + DEBUG_ONLY(VerifySmi(dst)); + } - // Install pure virtual methods if using compressed pointers, to ensure that - // these methods are overridden. If there are no compressed pointers, forward - // to the uncompressed version. #if defined(DART_COMPRESSED_POINTERS) + // Add pure virtual methods for methods that take addresses. + // + // Since the methods are only virtual when using compressed pointers, the + // overriding definitions must be guarded by the appropriate #ifdef. + + virtual void LoadCompressedFieldAddressForRegOffset( + Register address, + Register instance, + Register offset_in_words_as_smi) = 0; + virtual void LoadAcquireCompressed(Register dst, Register address, int32_t offset = 0) = 0; - virtual void LoadCompressedField(Register dst, - const FieldAddress& address) = 0; - virtual void LoadCompressedFieldFromOffset(Register dst, - Register base, - int32_t offset) = 0; + virtual void StoreReleaseCompressed(Register src, + Register address, + int32_t offset = 0) = 0; + + virtual void LoadCompressed(Register dst, const Address& address) = 0; + + // There is no StoreCompressed because only Dart objects contain compressed + // pointers and compressed pointers may require write barriers, so + // StoreCompressedIntoObject should be used instead. + virtual void StoreCompressedIntoObject( - Register object, // Object we are storing into. - const Address& dest, // Where we are storing into. - Register value, // Value we are storing. + Register object, // Object being stored into. + const Address& address, // Address to store the value at. + Register value, // Value being stored. CanBeSmi can_be_smi = kValueCanBeSmi, MemoryOrder memory_order = kRelaxedNonAtomic) = 0; virtual void StoreCompressedIntoObjectNoBarrier( - Register object, // Object we are storing into. - const Address& dest, // Where we are storing into. - Register value, // Value we are storing. + Register object, // Object being stored into. + const Address& address, // Address to store the value at. + Register value, // Value being stored. + MemoryOrder memory_order = kRelaxedNonAtomic) = 0; + virtual void StoreCompressedIntoObjectNoBarrier( + Register object, // Object being stored into. + const Address& address, // Address to store the value at. + const Object& value, // Value being stored. MemoryOrder memory_order = kRelaxedNonAtomic) = 0; + + virtual void LoadIndexedCompressed(Register dst, + Register base, + int32_t offset, + Register index) = 0; + virtual void StoreCompressedIntoArray( + Register object, + Register slot, + Register value, + CanBeSmi can_value_be_smi = kValueCanBeSmi) = 0; + + // Add a base virtual method for methods that take offsets which convert + // the base register and offset into an address appropriately. + // + // The latter should be overridden for architectures where offsets should not + // be converted to addresses without additional precautions. + // + // Since the methods are only virtual when using compressed pointers, the + // overriding definitions must be guarded by the appropriate #ifdef. + + virtual void LoadCompressedFromOffset(Register dst, + Register base, + int32_t offset); + virtual void StoreCompressedIntoObjectOffset( + Register object, // Object being stored into. + int32_t offset, // Offset into object. + Register value, // Value being stored. + CanBeSmi can_be_smi = kValueCanBeSmi, + MemoryOrder memory_order = kRelaxedNonAtomic); + virtual void StoreCompressedIntoObjectOffsetNoBarrier( + Register object, // Object being stored into. + int32_t offset, // Offset into object. + Register value, // Value being stored. + MemoryOrder memory_order = kRelaxedNonAtomic); + virtual void StoreCompressedIntoObjectOffsetNoBarrier( + Register object, // Object being stored into. + int32_t offset, // Offset into object. + const Object& value, // Value being stored. + MemoryOrder memory_order = kRelaxedNonAtomic); + + // Since loading Smis just involves zero extension instead of adjusting the + // high bits to be heap bits, these are non-virtual. + + // Loads a Smi, handling sign extension appropriately when compressed. + // In DEBUG mode, also checks that the loaded value is a Smi and halts if not. + void LoadCompressedSmi(Register dst, const Address& address) { + Load(dst, address, kUnsignedFourBytes); // Zero extension. + DEBUG_ONLY(VerifySmi(dst);) + } + + // Loads a Smi, handling sign extension appropriately when compressed. + // In DEBUG mode, also checks that the loaded value is a Smi and halts if not. + void LoadCompressedSmiFromOffset(Register dst, + Register base, + int32_t offset) { + LoadFromOffset(dst, base, offset, kUnsignedFourBytes); // Zero extension. + DEBUG_ONLY(VerifySmi(dst);) + } #else - virtual void LoadAcquireCompressed(Register dst, - Register address, - int32_t offset = 0) { + // The methods are non-virtual and forward to the uncompressed versions. + + void LoadCompressedFieldAddressForRegOffset(Register address, + Register instance, + Register offset_in_words_as_smi) { + LoadFieldAddressForRegOffset(address, instance, offset_in_words_as_smi); + } + + void LoadAcquireCompressed(Register dst, + Register address, + int32_t offset = 0) { LoadAcquire(dst, address, offset); } - virtual void LoadCompressedField(Register dst, const FieldAddress& address) { - LoadField(dst, address); + void StoreReleaseCompressed(Register src, + Register address, + int32_t offset = 0) { + StoreRelease(src, address, offset); } - virtual void LoadCompressedFieldFromOffset(Register dst, - Register base, - int32_t offset) { - LoadFieldFromOffset(dst, base, offset); + + void LoadCompressed(Register dst, const Address& address) { + Load(dst, address); } - virtual void StoreCompressedIntoObject( - Register object, // Object we are storing into. - const Address& dest, // Where we are storing into. - Register value, // Value we are storing. + + // There is no StoreCompressed because only Dart objects contain compressed + // pointers, so StoreCompressedIntoObject should be used instead. + + void StoreCompressedIntoObject( + Register object, // Object being stored into. + const Address& address, // Address to store the value at. + Register value, // Value being stored. CanBeSmi can_be_smi = kValueCanBeSmi, MemoryOrder memory_order = kRelaxedNonAtomic) { - StoreIntoObject(object, dest, value, can_be_smi); + StoreIntoObject(object, address, value, can_be_smi, memory_order); } - virtual void StoreCompressedIntoObjectNoBarrier( - Register object, // Object we are storing into. - const Address& dest, // Where we are storing into. - Register value, // Value we are storing. + void StoreCompressedIntoObjectNoBarrier( + Register object, // Object being stored into. + const Address& address, // Address to store the value at. + Register value, // Value being stored. MemoryOrder memory_order = kRelaxedNonAtomic) { - StoreIntoObjectNoBarrier(object, dest, value); + StoreIntoObjectNoBarrier(object, address, value, memory_order); + } + void StoreCompressedIntoObjectNoBarrier( + Register object, // Object being stored into. + const Address& address, // Address to store the value at. + const Object& value, // Value being stored. + MemoryOrder memory_order = kRelaxedNonAtomic) { + StoreIntoObjectNoBarrier(object, address, value, memory_order); + } + + void LoadIndexedCompressed(Register dst, + Register base, + int32_t offset, + Register index) { + LoadIndexedPayload(dst, base, offset, index, TIMES_WORD_SIZE, kWordBytes); + } + void StoreCompressedIntoArray(Register object, + Register slot, + Register value, + CanBeSmi can_value_be_smi = kValueCanBeSmi) { + StoreIntoArray(object, slot, value, can_value_be_smi); + } + + void LoadCompressedFromOffset(Register dst, Register base, int32_t offset) { + LoadFromOffset(dst, base, offset); + } + void StoreCompressedIntoObjectOffset( + Register object, // Object being stored into. + int32_t offset, // Offset into object. + Register value, // Value being stored. + CanBeSmi can_be_smi = kValueCanBeSmi, + MemoryOrder memory_order = kRelaxedNonAtomic) { + StoreIntoObjectOffset(object, offset, value, can_be_smi, memory_order); + } + void StoreCompressedIntoObjectOffsetNoBarrier( + Register object, // Object being stored into. + int32_t offset, // Offset into object. + Register value, // Value being stored. + MemoryOrder memory_order = kRelaxedNonAtomic) { + StoreIntoObjectOffsetNoBarrier(object, offset, value, memory_order); + } + void StoreCompressedIntoObjectOffsetNoBarrier( + Register object, // Object being stored into. + int32_t offset, // Offset into object. + const Object& value, // Value being stored. + MemoryOrder memory_order = kRelaxedNonAtomic) { + StoreIntoObjectOffsetNoBarrier(object, offset, value, memory_order); + } + + // Loads a Smi, handling sign extension appropriately when compressed. + // In DEBUG mode, also checks that the loaded value is a Smi and halts if not. + void LoadCompressedSmi(Register dst, const Address& address) { + LoadSmi(dst, address); + } + + // Loads a Smi, handling sign extension appropriately when compressed. + // In DEBUG mode, also checks that the loaded value is a Smi and halts if not. + void LoadCompressedSmiFromOffset(Register dst, + Register base, + int32_t offset) { + LoadSmiFromOffset(dst, base, offset); } #endif // defined(DART_COMPRESSED_POINTERS) - virtual void StoreRelease(Register src, - Register address, - int32_t offset = 0) = 0; + // These methods just delegate to the non-Field classes, either passing + // along a FieldAddress as the Address or adjusting the offset appropriately. + + void LoadCompressedField(Register dst, const FieldAddress& address); + void LoadCompressedFieldFromOffset(Register dst, + Register base, + int32_t offset) { + LoadCompressedFromOffset(dst, base, offset - kHeapObjectTag); + } + void LoadCompressedSmiFieldFromOffset(Register dst, + Register base, + int32_t offset) { + LoadCompressedSmiFromOffset(dst, base, offset - kHeapObjectTag); + } + + // There are no StoreCompressedField methods because only Dart objects contain + // compressed pointers and compressed pointers may require write barriers, so + // StoreCompressedIntoObject should be used instead. + + void LoadFromSlot(Register dst, Register base, const Slot& slot); + void StoreToSlot(Register src, + Register base, + const Slot& slot, + CanBeSmi can_be_smi, + MemoryOrder memory_order = kRelaxedNonAtomic); + void StoreToSlotNoBarrier(Register src, + Register base, + const Slot& slot, + MemoryOrder memory_order = kRelaxedNonAtomic); + // Uses the type information of the Slot to determine whether the field + // can be a Smi or not. + void StoreToSlot(Register src, + Register base, + const Slot& slot, + MemoryOrder memory_order = kRelaxedNonAtomic); // Truncates upper bits. virtual void LoadInt32FromBoxOrSmi(Register result, Register value) = 0; @@ -986,6 +1241,14 @@ class AssemblerBase : public StackResource { RangeCheckCondition condition, Label* target) = 0; + // Checks [dst] for a Smi, halting if it does not contain one. + void VerifySmi(Register dst) { + Label done; + BranchIfSmi(dst, &done, kNearJump); + Stop("Expected Smi"); + Bind(&done); + } + protected: AssemblerBuffer buffer_; // Contains position independent code. int32_t prologue_offset_; diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc index 01eb2095bfaf..8b62ebd3d995 100644 --- a/runtime/vm/compiler/assembler/assembler_ia32.cc +++ b/runtime/vm/compiler/assembler/assembler_ia32.cc @@ -1796,9 +1796,7 @@ void Assembler::CompareRegisters(Register a, Register b) { cmpl(a, b); } -void Assembler::LoadFromOffset(Register reg, - const Address& address, - OperandSize type) { +void Assembler::Load(Register reg, const Address& address, OperandSize type) { switch (type) { case kByte: return movsxb(reg, address); @@ -1817,9 +1815,7 @@ void Assembler::LoadFromOffset(Register reg, } } -void Assembler::StoreToOffset(Register reg, - const Address& address, - OperandSize sz) { +void Assembler::Store(Register reg, const Address& address, OperandSize sz) { switch (sz) { case kByte: case kUnsignedByte: @@ -1836,7 +1832,7 @@ void Assembler::StoreToOffset(Register reg, } } -void Assembler::StoreToOffset(const Object& object, const Address& dst) { +void Assembler::Store(const Object& object, const Address& dst) { if (target::CanEmbedAsRawPointerInGeneratedCode(object)) { movl(dst, Immediate(target::ToRawPointer(object))); } else { @@ -2080,16 +2076,6 @@ void Assembler::CompareObject(Register reg, const Object& object) { } } -void Assembler::LoadCompressedSmi(Register dest, const Address& slot) { - movl(dest, slot); -#if defined(DEBUG) - Label done; - BranchIfSmi(dest, &done, kNearJump); - Stop("Expected Smi"); - Bind(&done); -#endif -} - void Assembler::StoreIntoObject(Register object, const Address& dest, Register value, diff --git a/runtime/vm/compiler/assembler/assembler_ia32.h b/runtime/vm/compiler/assembler/assembler_ia32.h index 52ba1af1d21b..a269c0bc5736 100644 --- a/runtime/vm/compiler/assembler/assembler_ia32.h +++ b/runtime/vm/compiler/assembler/assembler_ia32.h @@ -617,64 +617,22 @@ class Assembler : public AssemblerBase { j(condition, label, distance); } - // Arch-specific LoadFromOffset to choose the right operation for [sz]. - void LoadFromOffset(Register dst, - const Address& address, - OperandSize sz = kFourBytes) override; - void LoadFromOffset(Register dst, - Register base, - int32_t offset, - OperandSize sz = kFourBytes) { - LoadFromOffset(dst, Address(base, offset), sz); - } - void LoadField(Register dst, const FieldAddress& address) override { - LoadField(dst, address, kFourBytes); - } - void LoadField(Register dst, const FieldAddress& address, OperandSize sz) { - LoadFromOffset(dst, address, sz); - } - void LoadFieldFromOffset(Register reg, - Register base, - int32_t offset, - OperandSize sz = kFourBytes) override { - LoadFromOffset(reg, FieldAddress(base, offset), sz); - } - void LoadCompressedFieldFromOffset(Register reg, - Register base, - int32_t offset) override { - LoadFieldFromOffset(reg, base, offset); - } + // Arch-specific Load to choose the right operation for [sz]. + void Load(Register dst, + const Address& address, + OperandSize sz = kFourBytes) override; void LoadIndexedPayload(Register dst, Register base, int32_t payload_offset, Register index, ScaleFactor scale, - OperandSize sz = kFourBytes) { - LoadFromOffset(dst, FieldAddress(base, index, scale, payload_offset), sz); - } - void LoadIndexedCompressed(Register dst, - Register base, - int32_t offset, - Register index) { - LoadCompressedField( - dst, FieldAddress(base, index, TIMES_COMPRESSED_WORD_SIZE, offset)); - } - void StoreToOffset(Register src, - const Address& address, - OperandSize sz = kFourBytes) override; - void StoreToOffset(Register src, - Register base, - int32_t offset, - OperandSize sz = kFourBytes) { - StoreToOffset(src, Address(base, offset), sz); - } - void StoreToOffset(const Object& value, const Address& address); - void StoreFieldToOffset(Register src, - Register base, - int32_t offset, - OperandSize sz = kFourBytes) { - StoreToOffset(src, FieldAddress(base, offset), sz); + OperandSize sz = kFourBytes) override { + Load(dst, FieldAddress(base, index, scale, payload_offset), sz); } + void Store(Register src, + const Address& address, + OperandSize sz = kFourBytes) override; + void Store(const Object& value, const Address& address); void StoreZero(const Address& address, Register temp = kNoRegister) { movl(address, Immediate(0)); } @@ -718,7 +676,7 @@ class Assembler : public AssemblerBase { OperandSize size = kFourBytes) override { // On intel loads have load-acquire behavior (i.e. loads are not re-ordered // with other loads). - LoadFromOffset(dst, Address(address, offset), size); + Load(dst, Address(address, offset), size); } void StoreRelease(Register src, Register address, @@ -848,9 +806,6 @@ class Assembler : public AssemblerBase { void PushObject(const Object& object); void CompareObject(Register reg, const Object& object); - void LoadCompressed(Register dest, const Address& slot) { movl(dest, slot); } - void LoadCompressedSmi(Register dst, const Address& slot) override; - // Store into a heap object and apply the generational write barrier. (Unlike // the other architectures, this does not apply the incremental write barrier, // and so concurrent marking is not enabled for now on IA32.) All stores into @@ -874,24 +829,40 @@ class Assembler : public AssemblerBase { void StoreIntoArray(Register object, // Object we are storing into. Register slot, // Where we are storing into. Register value, // Value we are storing. - CanBeSmi can_value_be_smi = kValueCanBeSmi, - Register scratch = kNoRegister); + CanBeSmi can_value_be_smi = kValueCanBeSmi) override { + StoreIntoArray(object, slot, value, can_value_be_smi, kNoRegister); + } + void StoreIntoArray(Register object, // Object we are storing into. + Register slot, // Where we are storing into. + Register value, // Value we are storing. + CanBeSmi can_value_be_smi, + Register scratch); void StoreIntoObjectNoBarrier( Register object, const Address& dest, Register value, MemoryOrder memory_order = kRelaxedNonAtomic) override; - void StoreIntoObjectNoBarrier(Register object, - const Address& dest, - const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic); + void StoreIntoObjectNoBarrier( + Register object, + const Address& dest, + const Object& value, + MemoryOrder memory_order = kRelaxedNonAtomic) override; + void StoreIntoObjectOffset( + Register object, // Object we are storing into. + int32_t offset, // Where we are storing into. + Register value, // Value we are storing. + CanBeSmi can_value_be_smi = kValueCanBeSmi, + MemoryOrder memory_order = kRelaxedNonAtomic) override { + StoreIntoObjectOffset(object, offset, value, can_value_be_smi, memory_order, + kNoRegister); + } void StoreIntoObjectOffset(Register object, // Object we are storing into. int32_t offset, // Where we are storing into. Register value, // Value we are storing. - CanBeSmi can_value_be_smi = kValueCanBeSmi, - MemoryOrder memory_order = kRelaxedNonAtomic, - Register scratch = kNoRegister) { + CanBeSmi can_value_be_smi, + MemoryOrder memory_order, + Register scratch) { StoreIntoObject(object, FieldAddress(object, offset), value, can_value_be_smi, memory_order, scratch); } @@ -899,7 +870,7 @@ class Assembler : public AssemblerBase { Register object, int32_t offset, Register value, - MemoryOrder memory_order = kRelaxedNonAtomic) { + MemoryOrder memory_order = kRelaxedNonAtomic) override { StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value, memory_order); } @@ -907,7 +878,7 @@ class Assembler : public AssemblerBase { Register object, int32_t offset, const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic) { + MemoryOrder memory_order = kRelaxedNonAtomic) override { StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value, memory_order); } @@ -1042,8 +1013,8 @@ class Assembler : public AssemblerBase { void LoadStaticFieldAddress(Register address, Register field, Register scratch) { - LoadCompressedFieldFromOffset( - scratch, field, target::Field::host_offset_or_field_id_offset()); + LoadFieldFromOffset(scratch, field, + target::Field::host_offset_or_field_id_offset()); const intptr_t field_table_offset = compiler::target::Thread::field_table_values_offset(); LoadMemoryValue(address, THR, static_cast(field_table_offset)); @@ -1051,15 +1022,9 @@ class Assembler : public AssemblerBase { leal(address, Address(address, scratch, TIMES_HALF_WORD_SIZE, 0)); } - void LoadCompressedFieldAddressForRegOffset(Register address, - Register instance, - Register offset_in_words_as_smi) { - LoadFieldAddressForRegOffset(address, instance, offset_in_words_as_smi); - } - void LoadFieldAddressForRegOffset(Register address, Register instance, - Register offset_in_words_as_smi) { + Register offset_in_words_as_smi) override { static_assert(kSmiTagShift == 1, "adjust scale factor"); leal(address, FieldAddress(instance, offset_in_words_as_smi, TIMES_2, 0)); } @@ -1122,7 +1087,7 @@ class Assembler : public AssemblerBase { Label* equals) override; void Align(intptr_t alignment, intptr_t offset); - void Bind(Label* label); + void Bind(Label* label) override; void Jump(Label* label, JumpDistance distance = kFarJump) { jmp(label, distance); } diff --git a/runtime/vm/compiler/assembler/assembler_riscv.cc b/runtime/vm/compiler/assembler/assembler_riscv.cc index 9d6c2be458fb..42b3f72dbbd5 100644 --- a/runtime/vm/compiler/assembler/assembler_riscv.cc +++ b/runtime/vm/compiler/assembler/assembler_riscv.cc @@ -2567,10 +2567,6 @@ void Assembler::Jump(const Address& address) { jr(TMP2); } -void Assembler::LoadField(Register dst, const FieldAddress& address) { - lx(dst, address); -} - #if defined(TARGET_USES_THREAD_SANITIZER) void Assembler::TsanLoadAcquire(Register addr) { LeafRuntimeScope rt(this, /*frame_size=*/0, /*preserve_registers=*/true); @@ -2602,29 +2598,11 @@ void Assembler::LoadAcquire(Register dst, #endif } -void Assembler::LoadAcquireCompressed(Register dst, - Register address, - int32_t offset) { - LoadAcquire(dst, address, offset); -} - void Assembler::StoreRelease(Register src, Register address, int32_t offset) { fence(HartEffects::kMemory, HartEffects::kWrite); StoreToOffset(src, address, offset); } -void Assembler::StoreReleaseCompressed(Register src, - Register address, - int32_t offset) { - UNIMPLEMENTED(); -} - -void Assembler::CompareWithCompressedFieldFromOffset(Register value, - Register base, - int32_t offset) { - UNIMPLEMENTED(); -} - void Assembler::CompareWithMemoryValue(Register value, Address address, OperandSize size) { @@ -3188,9 +3166,7 @@ Address Assembler::PrepareLargeOffset(Register base, int32_t offset) { return Address(TMP2, lo); } -void Assembler::LoadFromOffset(Register dest, - const Address& address, - OperandSize sz) { +void Assembler::Load(Register dest, const Address& address, OperandSize sz) { Address addr = PrepareLargeOffset(address.base(), address.offset()); switch (sz) { #if XLEN == 64 @@ -3228,12 +3204,6 @@ void Assembler::LoadIndexedPayload(Register dest, AddShifted(TMP, base, index, scale); LoadFromOffset(dest, TMP, payload_offset - kHeapObjectTag, sz); } -void Assembler::LoadIndexedCompressed(Register dest, - Register base, - int32_t offset, - Register index) { - LoadIndexedPayload(dest, base, offset, index, TIMES_WORD_SIZE, kObjectBytes); -} void Assembler::LoadSFromOffset(FRegister dest, Register base, int32_t offset) { flw(dest, PrepareLargeOffset(base, offset)); @@ -3253,9 +3223,7 @@ void Assembler::CompareToStack(Register src, intptr_t depth) { CompareWithMemoryValue(src, Address(SPREG, target::kWordSize * depth)); } -void Assembler::StoreToOffset(Register src, - const Address& address, - OperandSize sz) { +void Assembler::Store(Register src, const Address& address, OperandSize sz) { Address addr = PrepareLargeOffset(address.base(), address.offset()); switch (sz) { #if XLEN == 64 @@ -3296,16 +3264,9 @@ void Assembler::StoreIntoObject(Register object, MemoryOrder memory_order) { // stlr does not feature an address operand. ASSERT(memory_order == kRelaxedNonAtomic); - StoreToOffset(value, dest); + Store(value, dest); StoreBarrier(object, value, can_value_be_smi); } -void Assembler::StoreCompressedIntoObject(Register object, - const Address& dest, - Register value, - CanBeSmi can_value_be_smi, - MemoryOrder memory_order) { - StoreIntoObject(object, dest, value, can_value_be_smi, memory_order); -} void Assembler::StoreBarrier(Register object, Register value, CanBeSmi can_value_be_smi) { @@ -3371,12 +3332,6 @@ void Assembler::StoreIntoArray(Register object, sx(value, Address(slot, 0)); StoreIntoArrayBarrier(object, slot, value, can_value_be_smi); } -void Assembler::StoreCompressedIntoArray(Register object, - Register slot, - Register value, - CanBeSmi can_value_be_smi) { - StoreIntoArray(object, slot, value, can_value_be_smi); -} void Assembler::StoreIntoArrayBarrier(Register object, Register slot, Register value, @@ -3436,19 +3391,12 @@ void Assembler::StoreIntoObjectOffset(Register object, } StoreBarrier(object, value, can_value_be_smi); } -void Assembler::StoreCompressedIntoObjectOffset(Register object, - int32_t offset, - Register value, - CanBeSmi can_value_be_smi, - MemoryOrder memory_order) { - StoreIntoObjectOffset(object, offset, value, can_value_be_smi, memory_order); -} void Assembler::StoreIntoObjectNoBarrier(Register object, const Address& dest, Register value, MemoryOrder memory_order) { ASSERT(memory_order == kRelaxedNonAtomic); - StoreToOffset(value, dest); + Store(value, dest); #if defined(DEBUG) // We can't assert the incremental barrier is not needed here, only the // generational barrier. We sometimes omit the write barrier when 'value' is @@ -3467,12 +3415,6 @@ void Assembler::StoreIntoObjectNoBarrier(Register object, Bind(&done); #endif } -void Assembler::StoreCompressedIntoObjectNoBarrier(Register object, - const Address& dest, - Register value, - MemoryOrder memory_order) { - StoreIntoObjectNoBarrier(object, dest, value, memory_order); -} void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, int32_t offset, Register value, @@ -3500,13 +3442,6 @@ void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, Bind(&done); #endif } -void Assembler::StoreCompressedIntoObjectOffsetNoBarrier( - Register object, - int32_t offset, - Register value, - MemoryOrder memory_order) { - StoreIntoObjectOffsetNoBarrier(object, offset, value, memory_order); -} void Assembler::StoreIntoObjectNoBarrier(Register object, const Address& dest, const Object& value, @@ -3528,12 +3463,6 @@ void Assembler::StoreIntoObjectNoBarrier(Register object, } sx(value_reg, dest); } -void Assembler::StoreCompressedIntoObjectNoBarrier(Register object, - const Address& dest, - const Object& value, - MemoryOrder memory_order) { - UNIMPLEMENTED(); -} void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, int32_t offset, const Object& value, @@ -3555,13 +3484,6 @@ void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, StoreIntoObjectNoBarrier(object, Address(TMP), value); } } -void Assembler::StoreCompressedIntoObjectOffsetNoBarrier( - Register object, - int32_t offset, - const Object& value, - MemoryOrder memory_order) { - UNIMPLEMENTED(); -} // Stores a non-tagged value into a heap object. void Assembler::StoreInternalPointer(Register object, @@ -4492,8 +4414,7 @@ void Assembler::TryAllocateObject(intptr_t cid, const uword tags = target::MakeTagWordForNewSpaceObject(cid, instance_size); LoadImmediate(temp_reg, tags); - StoreToOffset(temp_reg, - FieldAddress(instance_reg, target::Object::tags_offset())); + Store(temp_reg, FieldAddress(instance_reg, target::Object::tags_offset())); } else { j(failure, distance); } @@ -4654,15 +4575,6 @@ void Assembler::LoadStaticFieldAddress(Register address, add(address, address, scratch); } -void Assembler::LoadCompressedFieldAddressForRegOffset( - Register address, - Register instance, - Register offset_in_words_as_smi) { - AddShifted(address, instance, offset_in_words_as_smi, - target::kCompressedWordSizeLog2 - kSmiTagShift); - addi(address, address, -kHeapObjectTag); -} - void Assembler::LoadFieldAddressForRegOffset(Register address, Register instance, Register offset_in_words_as_smi) { diff --git a/runtime/vm/compiler/assembler/assembler_riscv.h b/runtime/vm/compiler/assembler/assembler_riscv.h index 6884ade6eb12..92b509ae663a 100644 --- a/runtime/vm/compiler/assembler/assembler_riscv.h +++ b/runtime/vm/compiler/assembler/assembler_riscv.h @@ -856,7 +856,7 @@ class Assembler : public MicroAssembler { } } - void Bind(Label* label) { MicroAssembler::Bind(label); } + void Bind(Label* label) override { MicroAssembler::Bind(label); } // Unconditional jump to a given label. void Jump(Label* label, JumpDistance distance = kFarJump) { j(label, distance); @@ -866,10 +866,6 @@ class Assembler : public MicroAssembler { // Unconditional jump to a given address in memory. Clobbers TMP. void Jump(const Address& address); - void LoadField(Register dst, const FieldAddress& address) override; - void LoadCompressedField(Register dst, const FieldAddress& address) override { - LoadCompressed(dst, address); - } void LoadMemoryValue(Register dst, Register base, int32_t offset) { LoadFromOffset(dst, base, offset, kWordBytes); } @@ -887,22 +883,10 @@ class Assembler : public MicroAssembler { int32_t offset = 0, OperandSize size = kWordBytes) override; - void LoadAcquireCompressed(Register dst, - Register address, - int32_t offset = 0) override; - void StoreRelease(Register src, Register address, int32_t offset = 0) override; - void StoreReleaseCompressed(Register src, - Register address, - int32_t offset = 0); - - void CompareWithCompressedFieldFromOffset(Register value, - Register base, - int32_t offset); - void CompareWithMemoryValue(Register value, Address address, OperandSize size = kWordBytes) override; @@ -1119,31 +1103,9 @@ class Assembler : public MicroAssembler { OperandSize sz = kWordBytes) override; Address PrepareLargeOffset(Register base, int32_t offset); - void LoadFromOffset(Register dest, - const Address& address, - OperandSize sz = kWordBytes) override; - void LoadFromOffset(Register dest, - Register base, - int32_t offset, - OperandSize sz = kWordBytes) { - LoadFromOffset(dest, Address(base, offset), sz); - } - void LoadFieldFromOffset(Register dest, - Register base, - int32_t offset, - OperandSize sz = kWordBytes) override { - LoadFromOffset(dest, base, offset - kHeapObjectTag, sz); - } - void LoadCompressedFieldFromOffset(Register dest, - Register base, - int32_t offset) override { - LoadCompressedFromOffset(dest, base, offset - kHeapObjectTag); - } - void LoadCompressedSmiFieldFromOffset(Register dest, - Register base, - int32_t offset) { - LoadCompressedSmiFromOffset(dest, base, offset - kHeapObjectTag); - } + void Load(Register dest, + const Address& address, + OperandSize sz = kWordBytes) override; // For loading indexed payloads out of tagged objects like Arrays. If the // payload objects are word-sized, use TIMES_HALF_WORD_SIZE if the contents of // [index] is a Smi, otherwise TIMES_WORD_SIZE if unboxed. @@ -1152,11 +1114,7 @@ class Assembler : public MicroAssembler { int32_t payload_offset, Register index, ScaleFactor scale, - OperandSize sz = kWordBytes); - void LoadIndexedCompressed(Register dest, - Register base, - int32_t offset, - Register index); + OperandSize sz = kWordBytes) override; void LoadSFromOffset(FRegister dest, Register base, int32_t offset); void LoadDFromOffset(FRegister dest, Register base, int32_t offset); void LoadSFieldFromOffset(FRegister dest, Register base, int32_t offset) { @@ -1170,23 +1128,11 @@ class Assembler : public MicroAssembler { void StoreToStack(Register src, intptr_t depth); void CompareToStack(Register src, intptr_t depth); - void StoreToOffset(Register src, - const Address& address, - OperandSize sz = kWordBytes) override; - void StoreToOffset(Register src, - Register base, - int32_t offset, - OperandSize sz = kWordBytes) { - StoreToOffset(src, Address(base, offset), sz); - } - void StoreFieldToOffset(Register src, - Register base, - int32_t offset, - OperandSize sz = kWordBytes) { - StoreToOffset(src, FieldAddress(base, offset), sz); - } + void Store(Register src, + const Address& address, + OperandSize sz = kWordBytes) override; void StoreZero(const Address& address, Register temp = kNoRegister) { - StoreToOffset(ZR, address); + Store(ZR, address); } void StoreSToOffset(FRegister src, Register base, int32_t offset); void StoreSFieldToOffset(FRegister src, Register base, int32_t offset) { @@ -1220,27 +1166,6 @@ class Assembler : public MicroAssembler { UNREACHABLE(); } - void LoadCompressed(Register dest, const Address& slot) { - LoadFromOffset(dest, slot); - } - void LoadCompressedFromOffset(Register dest, Register base, int32_t offset) { - LoadFromOffset(dest, base, offset); - } - void LoadCompressedSmi(Register dest, const Address& slot) override { - LoadFromOffset(dest, slot); -#if defined(DEBUG) - Label done; - BranchIfSmi(dest, &done, kNearJump); - Stop("Expected Smi"); - Bind(&done); -#endif - } - void LoadCompressedSmiFromOffset(Register dest, - Register base, - int32_t offset) { - LoadFromOffset(dest, base, offset); - } - // Store into a heap object and apply the generational and incremental write // barriers. All stores into heap objects must pass through this function or, // if the value can be proven either Smi or old-and-premarked, its NoBarrier @@ -1251,43 +1176,23 @@ class Assembler : public MicroAssembler { Register value, CanBeSmi can_value_be_smi = kValueCanBeSmi, MemoryOrder memory_order = kRelaxedNonAtomic) override; - void StoreCompressedIntoObject( - Register object, - const Address& dest, - Register value, - CanBeSmi can_value_be_smi = kValueCanBeSmi, - MemoryOrder memory_order = kRelaxedNonAtomic) override; void StoreBarrier(Register object, Register value, CanBeSmi can_value_be_smi); void StoreIntoArray(Register object, Register slot, Register value, - CanBeSmi can_value_be_smi = kValueCanBeSmi); - void StoreCompressedIntoArray(Register object, - Register slot, - Register value, - CanBeSmi can_value_be_smi = kValueCanBeSmi); + CanBeSmi can_value_be_smi = kValueCanBeSmi) override; void StoreIntoArrayBarrier(Register object, Register slot, Register value, CanBeSmi can_value_be_smi); - void StoreIntoObjectOffset(Register object, - int32_t offset, - Register value, - CanBeSmi can_value_be_smi = kValueCanBeSmi, - MemoryOrder memory_order = kRelaxedNonAtomic); - void StoreCompressedIntoObjectOffset( + void StoreIntoObjectOffset( Register object, int32_t offset, Register value, CanBeSmi can_value_be_smi = kValueCanBeSmi, - MemoryOrder memory_order = kRelaxedNonAtomic); - void StoreIntoObjectNoBarrier( - Register object, - const Address& dest, - Register value, MemoryOrder memory_order = kRelaxedNonAtomic) override; - void StoreCompressedIntoObjectNoBarrier( + void StoreIntoObjectNoBarrier( Register object, const Address& dest, Register value, @@ -1296,31 +1201,17 @@ class Assembler : public MicroAssembler { Register object, int32_t offset, Register value, - MemoryOrder memory_order = kRelaxedNonAtomic); - void StoreCompressedIntoObjectOffsetNoBarrier( - Register object, - int32_t offset, - Register value, - MemoryOrder memory_order = kRelaxedNonAtomic); - void StoreIntoObjectNoBarrier(Register object, - const Address& dest, - const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic); - void StoreCompressedIntoObjectNoBarrier( + MemoryOrder memory_order = kRelaxedNonAtomic) override; + void StoreIntoObjectNoBarrier( Register object, const Address& dest, const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic); + MemoryOrder memory_order = kRelaxedNonAtomic) override; void StoreIntoObjectOffsetNoBarrier( Register object, int32_t offset, const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic); - void StoreCompressedIntoObjectOffsetNoBarrier( - Register object, - int32_t offset, - const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic); + MemoryOrder memory_order = kRelaxedNonAtomic) override; // Stores a non-tagged value into a heap object. void StoreInternalPointer(Register object, @@ -1590,13 +1481,9 @@ class Assembler : public MicroAssembler { Register field, Register scratch); - void LoadCompressedFieldAddressForRegOffset(Register address, - Register instance, - Register offset_in_words_as_smi); - void LoadFieldAddressForRegOffset(Register address, Register instance, - Register offset_in_words_as_smi); + Register offset_in_words_as_smi) override; void LoadFieldAddressForOffset(Register address, Register instance, diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc index 4594100d46ae..26c400c2822a 100644 --- a/runtime/vm/compiler/assembler/assembler_x64.cc +++ b/runtime/vm/compiler/assembler/assembler_x64.cc @@ -1545,28 +1545,12 @@ void Assembler::LoadQImmediate(FpuRegister dst, simd128_value_t immediate) { kHeapObjectTag)); } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::LoadCompressed(Register dest, const Address& slot) { -#if !defined(DART_COMPRESSED_POINTERS) - movq(dest, slot); -#else movl(dest, slot); // Zero-extension. addq(dest, Address(THR, target::Thread::heap_base_offset())); -#endif } - -void Assembler::LoadCompressedSmi(Register dest, const Address& slot) { -#if !defined(DART_COMPRESSED_POINTERS) - movq(dest, slot); -#else - movl(dest, slot); // Zero-extension. #endif -#if defined(DEBUG) - Label done; - BranchIfSmi(dest, &done, kNearJump); - Stop("Expected Smi"); - Bind(&done); -#endif -} void Assembler::StoreIntoObject(Register object, const Address& dest, @@ -1581,6 +1565,7 @@ void Assembler::StoreIntoObject(Register object, StoreBarrier(object, value, can_be_smi); } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::StoreCompressedIntoObject(Register object, const Address& dest, Register value, @@ -1593,6 +1578,7 @@ void Assembler::StoreCompressedIntoObject(Register object, } StoreBarrier(object, value, can_be_smi); } +#endif void Assembler::StoreBarrier(Register object, Register value, @@ -1652,6 +1638,7 @@ void Assembler::StoreIntoArray(Register object, StoreIntoArrayBarrier(object, slot, value, can_be_smi); } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::StoreCompressedIntoArray(Register object, Register slot, Register value, @@ -1659,6 +1646,7 @@ void Assembler::StoreCompressedIntoArray(Register object, OBJ(mov)(Address(slot, 0), value); StoreIntoArrayBarrier(object, slot, value, can_be_smi); } +#endif void Assembler::StoreIntoArrayBarrier(Register object, Register slot, @@ -1728,6 +1716,7 @@ void Assembler::StoreIntoObjectNoBarrier(Register object, // No store buffer update. } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::StoreCompressedIntoObjectNoBarrier(Register object, const Address& dest, Register value, @@ -1756,6 +1745,7 @@ void Assembler::StoreCompressedIntoObjectNoBarrier(Register object, #endif // defined(DEBUG) // No store buffer update. } +#endif void Assembler::StoreIntoObjectNoBarrier(Register object, const Address& dest, @@ -1769,6 +1759,7 @@ void Assembler::StoreIntoObjectNoBarrier(Register object, } } +#if defined(DART_COMPRESSED_POINTERS) void Assembler::StoreCompressedIntoObjectNoBarrier(Register object, const Address& dest, const Object& value, @@ -1776,6 +1767,7 @@ void Assembler::StoreCompressedIntoObjectNoBarrier(Register object, LoadObject(TMP, value); StoreCompressedIntoObjectNoBarrier(object, dest, TMP, memory_order); } +#endif void Assembler::StoreInternalPointer(Register object, const Address& dest, @@ -1830,9 +1822,7 @@ void Assembler::Bind(Label* label) { label->BindTo(bound); } -void Assembler::LoadFromOffset(Register reg, - const Address& address, - OperandSize sz) { +void Assembler::Load(Register reg, const Address& address, OperandSize sz) { switch (sz) { case kByte: return movsxb(reg, address); @@ -1854,9 +1844,7 @@ void Assembler::LoadFromOffset(Register reg, } } -void Assembler::StoreToOffset(Register reg, - const Address& address, - OperandSize sz) { +void Assembler::Store(Register reg, const Address& address, OperandSize sz) { switch (sz) { case kByte: case kUnsignedByte: diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h index be444c98fce4..be3207f63569 100644 --- a/runtime/vm/compiler/assembler/assembler_x64.h +++ b/runtime/vm/compiler/assembler/assembler_x64.h @@ -856,9 +856,9 @@ class Assembler : public AssemblerBase { void PushObject(const Object& object); void CompareObject(Register reg, const Object& object); - void LoadCompressed(Register dest, const Address& slot); - void LoadCompressedSmi(Register dest, const Address& slot) override; - +#if defined(DART_COMPRESSED_POINTERS) + void LoadCompressed(Register dest, const Address& slot) override; +#endif // Store into a heap object and apply the generational and incremental write // barriers. All stores into heap objects must pass through this function or, // if the value can be proven either Smi or old-and-premarked, its NoBarrier @@ -869,93 +869,52 @@ class Assembler : public AssemblerBase { Register value, // Value we are storing. CanBeSmi can_be_smi = kValueCanBeSmi, MemoryOrder memory_order = kRelaxedNonAtomic) override; - void StoreIntoObjectOffset(Register object, // Object we are storing into. - int32_t offset, // Where we are storing into. - Register value, // Value we are storing. - CanBeSmi can_be_smi = kValueCanBeSmi, - MemoryOrder memory_order = kRelaxedNonAtomic) { - StoreIntoObject(object, FieldAddress(object, offset), value, can_be_smi, - memory_order); - } +#if defined(DART_COMPRESSED_POINTERS) void StoreCompressedIntoObject( Register object, // Object we are storing into. const Address& dest, // Where we are storing into. Register value, // Value we are storing. CanBeSmi can_be_smi = kValueCanBeSmi, MemoryOrder memory_order = kRelaxedNonAtomic) override; - void StoreCompressedIntoObjectOffset( - Register object, // Object we are storing into. - int32_t offset, // Where we are storing into. - Register value, // Value we are storing. - CanBeSmi can_be_smi = kValueCanBeSmi, - MemoryOrder memory_order = kRelaxedNonAtomic) { - StoreCompressedIntoObject(object, FieldAddress(object, offset), value, - can_be_smi, memory_order); - } +#endif void StoreBarrier(Register object, // Object we are storing into. Register value, // Value we are storing. CanBeSmi can_be_smi); void StoreIntoArray(Register object, // Object we are storing into. Register slot, // Where we are storing into. Register value, // Value we are storing. - CanBeSmi can_be_smi = kValueCanBeSmi); + CanBeSmi can_be_smi = kValueCanBeSmi) override; +#if defined(DART_COMPRESSED_POINTERS) void StoreCompressedIntoArray(Register object, // Object we are storing into. Register slot, // Where we are storing into. Register value, // Value we are storing. - CanBeSmi can_be_smi = kValueCanBeSmi); + CanBeSmi can_be_smi = kValueCanBeSmi) override; +#endif void StoreIntoObjectNoBarrier( Register object, const Address& dest, Register value, MemoryOrder memory_order = kRelaxedNonAtomic) override; +#if defined(DART_COMPRESSED_POINTERS) void StoreCompressedIntoObjectNoBarrier( Register object, const Address& dest, Register value, MemoryOrder memory_order = kRelaxedNonAtomic) override; - void StoreIntoObjectNoBarrier(Register object, - const Address& dest, - const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic); - void StoreCompressedIntoObjectNoBarrier( +#endif + void StoreIntoObjectNoBarrier( Register object, const Address& dest, const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic); - - void StoreIntoObjectOffsetNoBarrier( - Register object, - int32_t offset, - Register value, - MemoryOrder memory_order = kRelaxedNonAtomic) { - StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value, - memory_order); - } - void StoreCompressedIntoObjectOffsetNoBarrier( - Register object, - int32_t offset, - Register value, - MemoryOrder memory_order = kRelaxedNonAtomic) { - StoreCompressedIntoObjectNoBarrier(object, FieldAddress(object, offset), - value, memory_order); - } - void StoreIntoObjectOffsetNoBarrier( - Register object, - int32_t offset, - const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic) { - StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value, - memory_order); - } - void StoreCompressedIntoObjectOffsetNoBarrier( + MemoryOrder memory_order = kRelaxedNonAtomic) override; +#if defined(DART_COMPRESSED_POINTERS) + void StoreCompressedIntoObjectNoBarrier( Register object, - int32_t offset, + const Address& dest, const Object& value, - MemoryOrder memory_order = kRelaxedNonAtomic) { - StoreCompressedIntoObjectNoBarrier(object, FieldAddress(object, offset), - value, memory_order); - } + MemoryOrder memory_order = kRelaxedNonAtomic) override; +#endif // Stores a non-tagged value into a heap object. void StoreInternalPointer(Register object, @@ -1109,7 +1068,7 @@ class Assembler : public AssemblerBase { Label* equals) override; void Align(int alignment, intptr_t offset); - void Bind(Label* label); + void Bind(Label* label) override; // Unconditional jump to a given label. void Jump(Label* label, JumpDistance distance = kFarJump) { jmp(label, distance); @@ -1122,65 +1081,29 @@ class Assembler : public AssemblerBase { void Jump(const Address& address) { jmp(address); } // Arch-specific LoadFromOffset to choose the right operation for [sz]. - void LoadFromOffset(Register dst, - const Address& address, - OperandSize sz = kEightBytes) override; - void LoadFromOffset(Register dst, - Register base, - int32_t offset, - OperandSize sz = kEightBytes) { - LoadFromOffset(dst, Address(base, offset), sz); - } - void LoadField(Register dst, const FieldAddress& address) override { - LoadField(dst, address, kEightBytes); - } - void LoadField(Register dst, const FieldAddress& address, OperandSize sz) { - LoadFromOffset(dst, address, sz); - } - void LoadCompressedField(Register dst, const FieldAddress& address) override { - LoadCompressed(dst, address); - } - void LoadFieldFromOffset(Register dst, - Register base, - int32_t offset, - OperandSize sz = kEightBytes) override { - LoadFromOffset(dst, FieldAddress(base, offset), sz); - } - void LoadCompressedFieldFromOffset(Register dst, - Register base, - int32_t offset) override { - LoadCompressed(dst, FieldAddress(base, offset)); - } + void Load(Register dst, + const Address& address, + OperandSize sz = kEightBytes) override; void LoadIndexedPayload(Register dst, Register base, int32_t payload_offset, Register index, ScaleFactor scale, - OperandSize sz = kEightBytes) { - LoadFromOffset(dst, FieldAddress(base, index, scale, payload_offset), sz); + OperandSize sz = kEightBytes) override { + Load(dst, FieldAddress(base, index, scale, payload_offset), sz); } +#if defined(DART_COMPRESSED_POINTERS) void LoadIndexedCompressed(Register dst, Register base, int32_t offset, - Register index) { + Register index) override { LoadCompressed( dst, FieldAddress(base, index, TIMES_COMPRESSED_WORD_SIZE, offset)); } - void StoreToOffset(Register src, - const Address& address, - OperandSize sz = kEightBytes) override; - void StoreToOffset(Register src, - Register base, - int32_t offset, - OperandSize sz = kEightBytes) { - StoreToOffset(src, Address(base, offset), sz); - } - void StoreFieldToOffset(Register src, - Register base, - int32_t offset, - OperandSize sz = kEightBytes) { - StoreToOffset(src, FieldAddress(base, offset), sz); - } +#endif + void Store(Register src, + const Address& address, + OperandSize sz = kEightBytes) override; void StoreZero(const Address& address, Register temp = kNoRegister) { movq(address, Immediate(0)); } @@ -1235,11 +1158,12 @@ class Assembler : public AssemblerBase { OperandSize size = kEightBytes) override { // On intel loads have load-acquire behavior (i.e. loads are not re-ordered // with other loads). - LoadFromOffset(dst, Address(address, offset), size); + Load(dst, Address(address, offset), size); #if defined(TARGET_USES_THREAD_SANITIZER) TsanLoadAcquire(Address(address, offset)); #endif } +#if defined(DART_COMPRESSED_POINTERS) void LoadAcquireCompressed(Register dst, Register address, int32_t offset = 0) override { @@ -1250,6 +1174,7 @@ class Assembler : public AssemblerBase { TsanLoadAcquire(Address(address, offset)); #endif } +#endif void StoreRelease(Register src, Register address, int32_t offset = 0) override { @@ -1260,9 +1185,10 @@ class Assembler : public AssemblerBase { TsanStoreRelease(Address(address, offset)); #endif } +#if defined(DART_COMPRESSED_POINTERS) void StoreReleaseCompressed(Register src, Register address, - int32_t offset = 0) { + int32_t offset = 0) override { // On intel stores have store-release behavior (i.e. stores are not // re-ordered with other stores). OBJ(mov)(Address(address, offset), src); @@ -1270,6 +1196,7 @@ class Assembler : public AssemblerBase { TsanStoreRelease(Address(address, offset)); #endif } +#endif void CompareWithMemoryValue(Register value, Address address, @@ -1281,11 +1208,6 @@ class Assembler : public AssemblerBase { cmpq(value, address); } } - void CompareWithCompressedFieldFromOffset(Register value, - Register base, - int32_t offset) { - OBJ(cmp)(value, FieldAddress(base, offset)); - } void RestoreCodePointer(); void LoadPoolPointer(Register pp = PP); @@ -1458,18 +1380,21 @@ class Assembler : public AssemblerBase { void LoadFieldAddressForRegOffset(Register address, Register instance, - Register offset_in_words_as_smi) { + Register offset_in_words_as_smi) override { static_assert(kSmiTagShift == 1, "adjust scale factor"); leaq(address, FieldAddress(instance, offset_in_words_as_smi, TIMES_4, 0)); } - void LoadCompressedFieldAddressForRegOffset(Register address, - Register instance, - Register offset_in_words_as_smi) { +#if defined(DART_COMPRESSED_POINTERS) + void LoadCompressedFieldAddressForRegOffset( + Register address, + Register instance, + Register offset_in_words_as_smi) override { static_assert(kSmiTagShift == 1, "adjust scale factor"); leaq(address, FieldAddress(instance, offset_in_words_as_smi, TIMES_COMPRESSED_HALF_WORD_SIZE, 0)); } +#endif void LoadFieldAddressForOffset(Register address, Register instance, diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc index 6d859c1afaee..2ec1785056d2 100644 --- a/runtime/vm/compiler/backend/flow_graph_compiler.cc +++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc @@ -3163,15 +3163,11 @@ void RangeErrorSlowPath::PushArgumentsForRuntimeCall( // The unboxed int64 argument is passed through a dedicated slot in Thread. // TODO(dartbug.com/33549): Clean this up when unboxed values // could be passed as arguments. + __ StoreToOffset(locs->in(CheckBoundBaseInstr::kLengthPos).reg(), THR, + compiler::target::Thread::unboxed_runtime_arg_offset()); __ StoreToOffset( - locs->in(CheckBoundBaseInstr::kLengthPos).reg(), - compiler::Address( - THR, compiler::target::Thread::unboxed_runtime_arg_offset())); - __ StoreToOffset( - locs->in(CheckBoundBaseInstr::kIndexPos).reg(), - compiler::Address( - THR, compiler::target::Thread::unboxed_runtime_arg_offset() + - kInt64Size)); + locs->in(CheckBoundBaseInstr::kIndexPos).reg(), THR, + compiler::target::Thread::unboxed_runtime_arg_offset() + kInt64Size); } else { __ PushRegisterPair(locs->in(CheckBoundBaseInstr::kIndexPos).reg(), locs->in(CheckBoundBaseInstr::kLengthPos).reg()); diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc index dc8ae3454047..e4c85df8de5c 100644 --- a/runtime/vm/compiler/backend/il.cc +++ b/runtime/vm/compiler/backend/il.cc @@ -7528,9 +7528,8 @@ void FfiCallInstr::EmitParamMoves(FlowGraphCompiler* compiler, const auto& target_stack = def_target.AsStack(); __ AddImmediate(temp0, origin.base_reg(), origin.stack_index() * compiler::target::kWordSize); - __ StoreToOffset(temp0, - compiler::Address(target_stack.base_register(), - target_stack.offset_in_bytes())); + __ StoreToOffset(temp0, target_stack.base_register(), + target_stack.offset_in_bytes()); } } else { __ Comment("def_target %s <- origin %s %s", diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc index 87abc1f502c1..6b6d24ddf1e1 100644 --- a/runtime/vm/compiler/backend/il_arm.cc +++ b/runtime/vm/compiler/backend/il_arm.cc @@ -300,10 +300,8 @@ static void CopyUpToWordMultiple(FlowGraphCompiler* compiler, tested_bits |= (1 << tested_bit); __ tst(length_reg, compiler::Operand(1 << tested_bit)); auto const sz = OperandSizeFor(bytes); - __ LoadFromOffset(TMP, compiler::Address(src_reg, bytes, mode), sz, - NOT_ZERO); - __ StoreToOffset(TMP, compiler::Address(dest_reg, bytes, mode), sz, - NOT_ZERO); + __ Load(TMP, compiler::Address(src_reg, bytes, mode), sz, NOT_ZERO); + __ Store(TMP, compiler::Address(dest_reg, bytes, mode), sz, NOT_ZERO); } __ bics(length_reg, length_reg, compiler::Operand(tested_bits)); @@ -2322,8 +2320,7 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { } else { const Register result = locs()->out(0).reg(); if (aligned()) { - __ LoadFromOffset(result, element_address, - RepresentationUtils::OperandSize(rep)); + __ Load(result, element_address, RepresentationUtils::OperandSize(rep)); } else { switch (rep) { case kUnboxedUint32: @@ -2552,8 +2549,7 @@ void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { } else { const Register value = locs()->in(2).reg(); if (aligned()) { - __ StoreToOffset(value, element_address, - RepresentationUtils::OperandSize(rep)); + __ Store(value, element_address, RepresentationUtils::OperandSize(rep)); } else { switch (rep) { case kUnboxedUint32: diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc index fb5d21afc237..f5e1298f8558 100644 --- a/runtime/vm/compiler/backend/il_arm64.cc +++ b/runtime/vm/compiler/backend/il_arm64.cc @@ -457,9 +457,8 @@ class ArgumentsMover : public ValueObject { // Flush all buffered registers. void Flush(FlowGraphCompiler* compiler) { if (pending_register_ != kNoRegister) { - __ StoreToOffset( - pending_register_, - compiler::Address(SP, pending_sp_relative_index_ * kWordSize)); + __ StoreToOffset(pending_register_, SP, + pending_sp_relative_index_ * kWordSize); pending_sp_relative_index_ = -1; pending_register_ = kNoRegister; } diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc index e4bc484d9d56..41a6c6d29adf 100644 --- a/runtime/vm/compiler/backend/il_ia32.cc +++ b/runtime/vm/compiler/backend/il_ia32.cc @@ -338,10 +338,10 @@ void MoveArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) { Location value = locs()->in(0); const compiler::Address dst = LocationToStackSlotAddress(location()); if (value.IsConstant()) { - __ StoreToOffset(value.constant(), dst); + __ Store(value.constant(), dst); } else { ASSERT(value.IsRegister()); - __ StoreToOffset(value.reg(), dst); + __ Store(value.reg(), dst); } } @@ -1771,8 +1771,7 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ movl(result_hi, element_address); } else { Register result = locs()->out(0).reg(); - __ LoadFromOffset(result, element_address, - RepresentationUtils::OperandSize(rep)); + __ Load(result, element_address, RepresentationUtils::OperandSize(rep)); } } else if (RepresentationUtils::IsUnboxed(rep)) { XmmRegister result = locs()->out(0).fpu_reg(); @@ -1923,8 +1922,7 @@ void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ movl(element_address, value_hi); } else { Register value = locs()->in(2).reg(); - __ StoreToOffset(value, element_address, - RepresentationUtils::OperandSize(rep)); + __ Store(value, element_address, RepresentationUtils::OperandSize(rep)); } } else if (RepresentationUtils::IsUnboxed(rep)) { if (rep == kUnboxedFloat) { diff --git a/runtime/vm/compiler/backend/il_riscv.cc b/runtime/vm/compiler/backend/il_riscv.cc index ea25edee619d..80d93d33f4c3 100644 --- a/runtime/vm/compiler/backend/il_riscv.cc +++ b/runtime/vm/compiler/backend/il_riscv.cc @@ -249,19 +249,15 @@ static void CopyBytes(FlowGraphCompiler* compiler, auto const sz = OperandSizeFor(XLEN / 8); const intptr_t offset = (reversed ? -1 : 1) * (XLEN / 8); const intptr_t initial = reversed ? offset : 0; - __ LoadFromOffset(TMP, compiler::Address(src_reg, initial), sz); - __ LoadFromOffset(TMP2, compiler::Address(src_reg, initial + offset), sz); - __ StoreToOffset(TMP, compiler::Address(dest_reg, initial), sz); - __ StoreToOffset(TMP2, compiler::Address(dest_reg, initial + offset), sz); - __ LoadFromOffset(TMP, compiler::Address(src_reg, initial + 2 * offset), - sz); - __ LoadFromOffset(TMP2, compiler::Address(src_reg, initial + 3 * offset), - sz); + __ LoadFromOffset(TMP, src_reg, initial, sz); + __ LoadFromOffset(TMP2, src_reg, initial + offset, sz); + __ StoreToOffset(TMP, dest_reg, initial, sz); + __ StoreToOffset(TMP2, dest_reg, initial + offset, sz); + __ LoadFromOffset(TMP, src_reg, initial + 2 * offset, sz); + __ LoadFromOffset(TMP2, src_reg, initial + 3 * offset, sz); __ addi(src_reg, src_reg, 4 * offset); - __ StoreToOffset(TMP, compiler::Address(dest_reg, initial + 2 * offset), - sz); - __ StoreToOffset(TMP2, compiler::Address(dest_reg, initial + 3 * offset), - sz); + __ StoreToOffset(TMP, dest_reg, initial + 2 * offset, sz); + __ StoreToOffset(TMP2, dest_reg, initial + 3 * offset, sz); __ addi(dest_reg, dest_reg, 4 * offset); return; } @@ -272,11 +268,11 @@ static void CopyBytes(FlowGraphCompiler* compiler, auto const sz = OperandSizeFor(XLEN / 8); const intptr_t offset = (reversed ? -1 : 1) * (XLEN / 8); const intptr_t initial = reversed ? offset : 0; - __ LoadFromOffset(TMP, compiler::Address(src_reg, initial), sz); - __ LoadFromOffset(TMP2, compiler::Address(src_reg, initial + offset), sz); + __ LoadFromOffset(TMP, src_reg, initial, sz); + __ LoadFromOffset(TMP2, src_reg, initial + offset, sz); __ addi(src_reg, src_reg, 2 * offset); - __ StoreToOffset(TMP, compiler::Address(dest_reg, initial), sz); - __ StoreToOffset(TMP2, compiler::Address(dest_reg, initial + offset), sz); + __ StoreToOffset(TMP, dest_reg, initial, sz); + __ StoreToOffset(TMP2, dest_reg, initial + offset, sz); __ addi(dest_reg, dest_reg, 2 * offset); return; } @@ -286,9 +282,9 @@ static void CopyBytes(FlowGraphCompiler* compiler, auto const sz = OperandSizeFor(count); const intptr_t offset = (reversed ? -1 : 1) * count; const intptr_t initial = reversed ? offset : 0; - __ LoadFromOffset(TMP, compiler::Address(src_reg, initial), sz); + __ LoadFromOffset(TMP, src_reg, initial, sz); __ addi(src_reg, src_reg, offset); - __ StoreToOffset(TMP, compiler::Address(dest_reg, initial), sz); + __ StoreToOffset(TMP, dest_reg, initial, sz); __ addi(dest_reg, dest_reg, offset); } @@ -1758,10 +1754,8 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { ASSERT(temp1 != CallingConventions::kReturnReg); ASSERT(temp2 != CallingConventions::kReturnReg); compiler::Label not_error; - __ LoadFromOffset( - temp1, - compiler::Address(CallingConventions::kReturnReg, - compiler::target::LocalHandle::ptr_offset())); + __ LoadFromOffset(temp1, CallingConventions::kReturnReg, + compiler::target::LocalHandle::ptr_offset()); __ BranchIfSmi(temp1, ¬_error); __ LoadClassId(temp1, temp1); __ RangeCheck(temp1, temp2, kFirstErrorCid, kLastErrorCid, @@ -2189,13 +2183,11 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { element_address.offset() + 4)); } else { const Register result = locs()->out(0).reg(); - __ LoadFromOffset(result, element_address, - RepresentationUtils::OperandSize(rep)); + __ Load(result, element_address, RepresentationUtils::OperandSize(rep)); } #else const Register result = locs()->out(0).reg(); - __ LoadFromOffset(result, element_address, - RepresentationUtils::OperandSize(rep)); + __ Load(result, element_address, RepresentationUtils::OperandSize(rep)); #endif } else if (RepresentationUtils::IsUnboxed(rep)) { const FRegister result = locs()->out(0).fpu_reg(); @@ -2502,11 +2494,10 @@ void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { } else { if (locs()->in(2).IsConstant()) { ASSERT(locs()->in(2).constant_instruction()->HasZeroRepresentation()); - __ StoreToOffset(ZR, element_address, - RepresentationUtils::OperandSize(rep)); + __ Store(ZR, element_address, RepresentationUtils::OperandSize(rep)); } else { - __ StoreToOffset(locs()->in(2).reg(), element_address, - RepresentationUtils::OperandSize(rep)); + __ Store(locs()->in(2).reg(), element_address, + RepresentationUtils::OperandSize(rep)); } } } else if (RepresentationUtils::IsUnboxed(rep)) { diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc index e30359581c80..2a5b57cef08b 100644 --- a/runtime/vm/compiler/backend/il_x64.cc +++ b/runtime/vm/compiler/backend/il_x64.cc @@ -1996,8 +1996,7 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { ASSERT(representation() == Boxing::NativeRepresentation(rep)); if (RepresentationUtils::IsUnboxedInteger(rep)) { Register result = locs()->out(0).reg(); - __ LoadFromOffset(result, element_address, - RepresentationUtils::OperandSize(rep)); + __ Load(result, element_address, RepresentationUtils::OperandSize(rep)); } else if (RepresentationUtils::IsUnboxed(rep)) { XmmRegister result = locs()->out(0).fpu_reg(); if (rep == kUnboxedFloat) { @@ -2216,8 +2215,7 @@ void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { } } else { Register value = locs()->in(2).reg(); - __ StoreToOffset(value, element_address, - RepresentationUtils::OperandSize(rep)); + __ Store(value, element_address, RepresentationUtils::OperandSize(rep)); } } else if (RepresentationUtils::IsUnboxed(rep)) { if (rep == kUnboxedFloat) { diff --git a/runtime/vm/compiler/stub_code_compiler.cc b/runtime/vm/compiler/stub_code_compiler.cc index a02d280316a7..d2e9ffeb0601 100644 --- a/runtime/vm/compiler/stub_code_compiler.cc +++ b/runtime/vm/compiler/stub_code_compiler.cc @@ -1383,7 +1383,7 @@ void StubCodeCompiler::GenerateAllocateRecordStub() { __ AndImmediate(temp_reg, -target::ObjectAlignment::kObjectAlignment); // Now allocate the object. - __ LoadFromOffset(result_reg, Address(THR, target::Thread::top_offset())); + __ LoadFromOffset(result_reg, THR, target::Thread::top_offset()); __ MoveRegister(new_top_reg, temp_reg); __ AddRegisters(new_top_reg, result_reg); // Check if the allocation fits into the remaining space. @@ -1394,7 +1394,7 @@ void StubCodeCompiler::GenerateAllocateRecordStub() { // Successfully allocated the object, now update top to point to // next object start and initialize the object. - __ StoreToOffset(new_top_reg, Address(THR, target::Thread::top_offset())); + __ StoreToOffset(new_top_reg, THR, target::Thread::top_offset()); __ AddImmediate(result_reg, kHeapObjectTag); // Calculate the size tag. @@ -1414,9 +1414,8 @@ void StubCodeCompiler::GenerateAllocateRecordStub() { __ Bind(&done); uword tags = target::MakeTagWordForNewSpaceObject(kRecordCid, 0); __ OrImmediate(temp_reg, tags); - __ StoreToOffset( - temp_reg, - FieldAddress(result_reg, target::Object::tags_offset())); // Tags. + __ StoreFieldToOffset(temp_reg, result_reg, + target::Object::tags_offset()); // Tags. } __ StoreCompressedIntoObjectNoBarrier( @@ -1807,11 +1806,10 @@ static void CallDartCoreLibraryFunction( __ Call(Address(THR, entry_point_offset_in_thread)); } else { __ LoadIsolateGroup(FUNCTION_REG); - __ LoadFromOffset( - FUNCTION_REG, - Address(FUNCTION_REG, target::IsolateGroup::object_store_offset())); - __ LoadFromOffset(FUNCTION_REG, - Address(FUNCTION_REG, function_offset_in_object_store)); + __ LoadFromOffset(FUNCTION_REG, FUNCTION_REG, + target::IsolateGroup::object_store_offset()); + __ LoadFromOffset(FUNCTION_REG, FUNCTION_REG, + function_offset_in_object_store); __ LoadCompressedFieldFromOffset(CODE_REG, FUNCTION_REG, target::Function::code_offset()); if (!uses_args_desc) { @@ -1855,7 +1853,7 @@ static void GenerateAllocateSuspendState(Assembler* assembler, __ AndImmediate(temp_reg, -target::ObjectAlignment::kObjectAlignment); // Now allocate the object. - __ LoadFromOffset(result_reg, Address(THR, target::Thread::top_offset())); + __ LoadFromOffset(result_reg, THR, target::Thread::top_offset()); __ AddRegisters(temp_reg, result_reg); // Check if the allocation fits into the remaining space. __ CompareWithMemoryValue(temp_reg, @@ -1865,7 +1863,7 @@ static void GenerateAllocateSuspendState(Assembler* assembler, // Successfully allocated the object, now update top to point to // next object start and initialize the object. - __ StoreToOffset(temp_reg, Address(THR, target::Thread::top_offset())); + __ StoreToOffset(temp_reg, THR, target::Thread::top_offset()); __ SubRegisters(temp_reg, result_reg); __ AddImmediate(result_reg, kHeapObjectTag); @@ -1873,9 +1871,8 @@ static void GenerateAllocateSuspendState(Assembler* assembler, // Use rounded object size to calculate and save frame capacity. __ AddImmediate(temp_reg, temp_reg, -target::SuspendState::payload_offset()); - __ StoreToOffset( - temp_reg, FieldAddress(result_reg, - target::SuspendState::frame_capacity_offset())); + __ StoreFieldToOffset(temp_reg, result_reg, + target::SuspendState::frame_capacity_offset()); // Restore rounded object size. __ AddImmediate(temp_reg, temp_reg, target::SuspendState::payload_offset()); } @@ -1897,14 +1894,12 @@ static void GenerateAllocateSuspendState(Assembler* assembler, __ Bind(&done); uword tags = target::MakeTagWordForNewSpaceObject(kSuspendStateCid, 0); __ OrImmediate(temp_reg, tags); - __ StoreToOffset( - temp_reg, - FieldAddress(result_reg, target::Object::tags_offset())); // Tags. + __ StoreFieldToOffset(temp_reg, result_reg, + target::Object::tags_offset()); // Tags. } - __ StoreToOffset( - frame_size_reg, - FieldAddress(result_reg, target::SuspendState::frame_size_offset())); + __ StoreFieldToOffset(frame_size_reg, result_reg, + target::SuspendState::frame_size_offset()); } void StubCodeCompiler::GenerateSuspendStub( @@ -1927,7 +1922,7 @@ void StubCodeCompiler::GenerateSuspendStub( SPILLS_LR_TO_FRAME({}); // Simulate entering the caller (Dart) frame. #endif - __ LoadFromOffset(kSuspendState, Address(FPREG, SuspendStateFpOffset())); + __ LoadFromOffset(kSuspendState, FPREG, SuspendStateFpOffset()); __ AddImmediate( kFrameSize, FPREG, @@ -1954,9 +1949,8 @@ void StubCodeCompiler::GenerateSuspendStub( target::SuspendState::frame_capacity_offset())); __ BranchIf(UNSIGNED_GREATER, &resize_suspend_state); - __ StoreToOffset( - kFrameSize, - FieldAddress(kSuspendState, target::SuspendState::frame_size_offset())); + __ StoreFieldToOffset(kFrameSize, kSuspendState, + target::SuspendState::frame_size_offset()); __ Jump(&init_done); __ Bind(&alloc_suspend_state); @@ -1996,9 +1990,8 @@ void StubCodeCompiler::GenerateSuspendStub( __ Bind(&alloc_done); __ Comment("Save SuspendState to frame"); - __ LoadFromOffset( - kTemp, Address(FPREG, kSavedCallerFpSlotFromFp * target::kWordSize)); - __ StoreToOffset(kSuspendState, Address(kTemp, SuspendStateFpOffset())); + __ LoadFromOffset(kTemp, FPREG, kSavedCallerFpSlotFromFp * target::kWordSize); + __ StoreToOffset(kSuspendState, kTemp, SuspendStateFpOffset()); __ Bind(&init_done); __ Comment("Copy frame to SuspendState"); @@ -2007,9 +2000,8 @@ void StubCodeCompiler::GenerateSuspendStub( { // Verify that SuspendState.frame_size == kFrameSize. Label okay; - __ LoadFromOffset( - kTemp, - FieldAddress(kSuspendState, target::SuspendState::frame_size_offset())); + __ LoadFieldFromOffset(kTemp, kSuspendState, + target::SuspendState::frame_size_offset()); __ CompareRegisters(kTemp, kFrameSize); __ BranchIf(EQUAL, &okay); __ Breakpoint(); @@ -2028,23 +2020,21 @@ void StubCodeCompiler::GenerateSuspendStub( __ PopRegister(THR); } - __ LoadFromOffset( - kTemp, Address(FPREG, kSavedCallerPcSlotFromFp * target::kWordSize)); - __ StoreToOffset( - kTemp, FieldAddress(kSuspendState, target::SuspendState::pc_offset())); + __ LoadFromOffset(kTemp, FPREG, kSavedCallerPcSlotFromFp * target::kWordSize); + __ StoreFieldToOffset(kTemp, kSuspendState, + target::SuspendState::pc_offset()); #ifdef DEBUG { // Verify that kSuspendState matches :suspend_state in the copied stack // frame. Label okay; - __ LoadFromOffset( - kTemp, - FieldAddress(kSuspendState, target::SuspendState::frame_size_offset())); + __ LoadFieldFromOffset(kTemp, kSuspendState, + target::SuspendState::frame_size_offset()); __ AddRegisters(kTemp, kSuspendState); - __ LoadFromOffset( - kTemp, FieldAddress(kTemp, target::SuspendState::payload_offset() + - SuspendStateFpOffset())); + __ LoadFieldFromOffset( + kTemp, kTemp, + target::SuspendState::payload_offset() + SuspendStateFpOffset()); __ CompareRegisters(kTemp, kSuspendState); __ BranchIf(EQUAL, &okay); __ Breakpoint(); @@ -2060,7 +2050,7 @@ void StubCodeCompiler::GenerateSuspendStub( // Write barrier. __ AndImmediate(kTemp, kSuspendState, target::kPageMask); - __ LoadFromOffset(kTemp, Address(kTemp, target::Page::original_top_offset())); + __ LoadFromOffset(kTemp, kTemp, target::Page::original_top_offset()); __ CompareRegisters(kSuspendState, kTemp); __ BranchIf(UNSIGNED_LESS, &remember_object); // Assumption: SuspendStates are always on non-image pages. @@ -2097,8 +2087,8 @@ void StubCodeCompiler::GenerateSuspendStub( // will only unwind frame and return. if (!FLAG_precompiled_mode) { __ LoadFromOffset( - PP, Address(FPREG, target::frame_layout.saved_caller_pp_from_fp * - target::kWordSize)); + PP, FPREG, + target::frame_layout.saved_caller_pp_from_fp * target::kWordSize); } #endif __ Ret(); @@ -2225,8 +2215,8 @@ void StubCodeCompiler::GenerateInitSuspendableFunctionStub( __ LeaveStubFrame(); // Set :suspend_state in the caller frame. - __ StoreToOffset(CallingConventions::kReturnReg, - Address(FPREG, SuspendStateFpOffset())); + __ StoreToOffset(CallingConventions::kReturnReg, FPREG, + SuspendStateFpOffset()); __ Ret(); } @@ -2266,8 +2256,7 @@ void StubCodeCompiler::GenerateResumeStub() { const intptr_t param_offset = target::frame_layout.param_end_from_fp * target::kWordSize; - __ LoadFromOffset(kSuspendState, - Address(FPREG, param_offset + 4 * target::kWordSize)); + __ LoadFromOffset(kSuspendState, FPREG, param_offset + 4 * target::kWordSize); #ifdef DEBUG { Label okay; @@ -2278,8 +2267,8 @@ void StubCodeCompiler::GenerateResumeStub() { } { Label okay; - __ LoadFromOffset( - kTemp, FieldAddress(kSuspendState, target::SuspendState::pc_offset())); + __ LoadFieldFromOffset(kTemp, kSuspendState, + target::SuspendState::pc_offset()); __ CompareImmediate(kTemp, 0); __ BranchIf(NOT_EQUAL, &okay); __ Breakpoint(); @@ -2287,17 +2276,16 @@ void StubCodeCompiler::GenerateResumeStub() { } #endif - __ LoadFromOffset( - kFrameSize, - FieldAddress(kSuspendState, target::SuspendState::frame_size_offset())); + __ LoadFieldFromOffset(kFrameSize, kSuspendState, + target::SuspendState::frame_size_offset()); #ifdef DEBUG { Label okay; __ MoveRegister(kTemp, kFrameSize); __ AddRegisters(kTemp, kSuspendState); - __ LoadFromOffset( - kTemp, FieldAddress(kTemp, target::SuspendState::payload_offset() + - SuspendStateFpOffset())); + __ LoadFieldFromOffset( + kTemp, kTemp, + target::SuspendState::payload_offset() + SuspendStateFpOffset()); __ CompareRegisters(kTemp, kSuspendState); __ BranchIf(EQUAL, &okay); __ Breakpoint(); @@ -2310,13 +2298,11 @@ void StubCodeCompiler::GenerateResumeStub() { __ MoveRegister(kTemp, kSuspendState); __ AddRegisters(kTemp, kFrameSize); __ LoadFromOffset( - CODE_REG, - Address(kTemp, - target::SuspendState::payload_offset() - kHeapObjectTag + - target::frame_layout.code_from_fp * target::kWordSize)); - __ StoreToOffset( - CODE_REG, - Address(FPREG, target::frame_layout.code_from_fp * target::kWordSize)); + CODE_REG, kTemp, + target::SuspendState::payload_offset() - kHeapObjectTag + + target::frame_layout.code_from_fp * target::kWordSize); + __ StoreToOffset(CODE_REG, FPREG, + target::frame_layout.code_from_fp * target::kWordSize); #if !defined(TARGET_ARCH_IA32) __ LoadPoolPointer(PP); #endif @@ -2349,8 +2335,8 @@ void StubCodeCompiler::GenerateResumeStub() { __ Comment("Transfer control"); - __ LoadFromOffset(kResumePc, FieldAddress(kSuspendState, - target::SuspendState::pc_offset())); + __ LoadFieldFromOffset(kResumePc, kSuspendState, + target::SuspendState::pc_offset()); __ StoreZero(FieldAddress(kSuspendState, target::SuspendState::pc_offset()), kTemp); @@ -2363,15 +2349,14 @@ void StubCodeCompiler::GenerateResumeStub() { static_assert((kException != CODE_REG) && (kException != PP), "should not interfere"); - __ LoadFromOffset(kException, - Address(FPREG, param_offset + 2 * target::kWordSize)); + __ LoadFromOffset(kException, FPREG, param_offset + 2 * target::kWordSize); __ CompareObject(kException, NullObject()); __ BranchIf(NOT_EQUAL, &call_runtime); if (!FLAG_precompiled_mode) { // Check if Code is disabled. - __ LoadFromOffset( - kTemp, FieldAddress(CODE_REG, target::Code::instructions_offset())); + __ LoadFieldFromOffset(kTemp, CODE_REG, + target::Code::instructions_offset()); __ CompareWithMemoryValue( kTemp, FieldAddress(CODE_REG, target::Code::active_instructions_offset())); @@ -2380,25 +2365,23 @@ void StubCodeCompiler::GenerateResumeStub() { #if !defined(PRODUCT) // Check if there is a breakpoint at resumption. __ LoadIsolate(kTemp); - __ LoadFromOffset( - kTemp, - Address(kTemp, target::Isolate::has_resumption_breakpoints_offset()), - kUnsignedByte); + __ LoadFromOffset(kTemp, kTemp, + target::Isolate::has_resumption_breakpoints_offset(), + kUnsignedByte); __ CompareImmediate(kTemp, 0); __ BranchIf(NOT_EQUAL, &call_runtime); #endif } - __ LoadFromOffset(CallingConventions::kReturnReg, - Address(FPREG, param_offset + 3 * target::kWordSize)); + __ LoadFromOffset(CallingConventions::kReturnReg, FPREG, + param_offset + 3 * target::kWordSize); __ Jump(kResumePc); __ Comment("Call runtime to throw exception or deopt"); __ Bind(&call_runtime); - __ LoadFromOffset(kStackTrace, - Address(FPREG, param_offset + 1 * target::kWordSize)); + __ LoadFromOffset(kStackTrace, FPREG, param_offset + 1 * target::kWordSize); static_assert((kStackTrace != CODE_REG) && (kStackTrace != PP), "should not interfere"); @@ -2421,8 +2404,8 @@ void StubCodeCompiler::GenerateResumeStub() { __ Breakpoint(); } else { __ LeaveStubFrame(); - __ LoadFromOffset(CallingConventions::kReturnReg, - Address(FPREG, param_offset + 3 * target::kWordSize)); + __ LoadFromOffset(CallingConventions::kReturnReg, FPREG, + param_offset + 3 * target::kWordSize); // Lazy deoptimize. __ Ret(); } @@ -2438,7 +2421,7 @@ void StubCodeCompiler::GenerateReturnStub( SPILLS_LR_TO_FRAME({}); // Simulate entering the caller (Dart) frame. #endif - __ LoadFromOffset(kSuspendState, Address(FPREG, SuspendStateFpOffset())); + __ LoadFromOffset(kSuspendState, FPREG, SuspendStateFpOffset()); #ifdef DEBUG { Label okay; @@ -2492,7 +2475,7 @@ void StubCodeCompiler::GenerateAsyncExceptionHandlerStub() { SPILLS_LR_TO_FRAME({}); // Simulate entering the caller (Dart) frame. #endif - __ LoadFromOffset(kSuspendState, Address(FPREG, SuspendStateFpOffset())); + __ LoadFromOffset(kSuspendState, FPREG, SuspendStateFpOffset()); // Check if suspend_state is initialized. Otherwise // exception was thrown from the prologue code and @@ -2546,8 +2529,7 @@ void StubCodeCompiler::GenerateCloneSuspendStateStub() { { // Can only clone _SuspendState objects with copied frames. Label okay; - __ LoadFromOffset(kTemp, - FieldAddress(kSource, target::SuspendState::pc_offset())); + __ LoadFieldFromOffset(kTemp, kSource, target::SuspendState::pc_offset()); __ CompareImmediate(kTemp, 0); __ BranchIf(NOT_EQUAL, &okay); __ Breakpoint(); @@ -2555,18 +2537,15 @@ void StubCodeCompiler::GenerateCloneSuspendStateStub() { } #endif - __ LoadFromOffset( - kFrameSize, - FieldAddress(kSource, target::SuspendState::frame_size_offset())); + __ LoadFieldFromOffset(kFrameSize, kSource, + target::SuspendState::frame_size_offset()); GenerateAllocateSuspendState(assembler, &alloc_slow_case, kDestination, kFrameSize, kTemp); // Copy pc. - __ LoadFromOffset(kTemp, - FieldAddress(kSource, target::SuspendState::pc_offset())); - __ StoreToOffset( - kTemp, FieldAddress(kDestination, target::SuspendState::pc_offset())); + __ LoadFieldFromOffset(kTemp, kSource, target::SuspendState::pc_offset()); + __ StoreFieldToOffset(kTemp, kDestination, target::SuspendState::pc_offset()); // Copy function_data. __ LoadCompressedFieldFromOffset( @@ -2606,13 +2585,12 @@ void StubCodeCompiler::GenerateCloneSuspendStateStub() { // Update value of :suspend_state variable in the copied frame // for the new SuspendState. - __ LoadFromOffset( - kTemp, - FieldAddress(kDestination, target::SuspendState::frame_size_offset())); + __ LoadFieldFromOffset(kTemp, kDestination, + target::SuspendState::frame_size_offset()); __ AddRegisters(kTemp, kDestination); - __ StoreToOffset(kDestination, - FieldAddress(kTemp, target::SuspendState::payload_offset() + - SuspendStateFpOffset())); + __ StoreFieldToOffset( + kDestination, kTemp, + target::SuspendState::payload_offset() + SuspendStateFpOffset()); __ MoveRegister(CallingConventions::kReturnReg, kDestination); EnsureIsNewOrRemembered(); diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc index a840d83f5b9d..929b37eae19a 100644 --- a/runtime/vm/compiler/stub_code_compiler_arm.cc +++ b/runtime/vm/compiler/stub_code_compiler_arm.cc @@ -42,7 +42,7 @@ void StubCodeCompiler::EnsureIsNewOrRemembered() { // Page's TLAB use is always ascending. Label done; __ AndImmediate(TMP, R0, target::kPageMask); - __ LoadFromOffset(TMP, Address(TMP, target::Page::original_top_offset())); + __ LoadFromOffset(TMP, TMP, target::Page::original_top_offset()); __ CompareRegisters(R0, TMP); __ BranchIf(UNSIGNED_GREATER_EQUAL, &done); @@ -322,9 +322,8 @@ void StubCodeCompiler::GenerateLoadFfiCallbackMetadataRuntimeFunction( __ AndImmediate(dst, dst, FfiCallbackMetadata::kPageMask); // Load the function from the function table. - __ LoadFromOffset( - dst, - Address(dst, FfiCallbackMetadata::RuntimeFunctionOffset(function_index))); + __ LoadFromOffset(dst, dst, + FfiCallbackMetadata::RuntimeFunctionOffset(function_index)); } void StubCodeCompiler::GenerateFfiCallbackTrampolineStub() { diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc index 586e2505b4f0..fbcd27b12e2c 100644 --- a/runtime/vm/compiler/stub_code_compiler_arm64.cc +++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc @@ -41,7 +41,7 @@ void StubCodeCompiler::EnsureIsNewOrRemembered() { // Page's TLAB use is always ascending. Label done; __ AndImmediate(TMP, R0, target::kPageMask); - __ LoadFromOffset(TMP, Address(TMP, target::Page::original_top_offset())); + __ LoadFromOffset(TMP, TMP, target::Page::original_top_offset()); __ CompareRegisters(R0, TMP); __ BranchIf(UNSIGNED_GREATER_EQUAL, &done); @@ -465,9 +465,8 @@ void StubCodeCompiler::GenerateLoadFfiCallbackMetadataRuntimeFunction( __ andi(dst, dst, Immediate(FfiCallbackMetadata::kPageMask)); // Load the function from the function table. - __ LoadFromOffset( - dst, - Address(dst, FfiCallbackMetadata::RuntimeFunctionOffset(function_index))); + __ LoadFromOffset(dst, dst, + FfiCallbackMetadata::RuntimeFunctionOffset(function_index)); } void StubCodeCompiler::GenerateFfiCallbackTrampolineStub() { diff --git a/runtime/vm/compiler/stub_code_compiler_ia32.cc b/runtime/vm/compiler/stub_code_compiler_ia32.cc index 73ecde58f643..27b8bd4cc424 100644 --- a/runtime/vm/compiler/stub_code_compiler_ia32.cc +++ b/runtime/vm/compiler/stub_code_compiler_ia32.cc @@ -40,7 +40,7 @@ void StubCodeCompiler::EnsureIsNewOrRemembered() { // Page's TLAB use is always ascending. Label done; __ AndImmediate(ECX, EAX, target::kPageMask); - __ LoadFromOffset(ECX, Address(ECX, target::Page::original_top_offset())); + __ LoadFromOffset(ECX, ECX, target::Page::original_top_offset()); __ CompareRegisters(EAX, ECX); __ BranchIf(UNSIGNED_GREATER_EQUAL, &done); diff --git a/runtime/vm/compiler/stub_code_compiler_riscv.cc b/runtime/vm/compiler/stub_code_compiler_riscv.cc index 266a3435f5dd..f8505e87cb44 100644 --- a/runtime/vm/compiler/stub_code_compiler_riscv.cc +++ b/runtime/vm/compiler/stub_code_compiler_riscv.cc @@ -41,7 +41,7 @@ void StubCodeCompiler::EnsureIsNewOrRemembered() { // Page's TLAB use is always ascending. Label done; __ AndImmediate(TMP, A0, target::kPageMask); - __ LoadFromOffset(TMP, Address(TMP, target::Page::original_top_offset())); + __ LoadFromOffset(TMP, TMP, target::Page::original_top_offset()); __ CompareRegisters(A0, TMP); __ BranchIf(UNSIGNED_GREATER_EQUAL, &done); @@ -333,9 +333,8 @@ void StubCodeCompiler::GenerateLoadFfiCallbackMetadataRuntimeFunction( __ AndImmediate(dst, FfiCallbackMetadata::kPageMask); // Load the function from the function table. - __ LoadFromOffset( - dst, - Address(dst, FfiCallbackMetadata::RuntimeFunctionOffset(function_index))); + __ LoadFromOffset(dst, dst, + FfiCallbackMetadata::RuntimeFunctionOffset(function_index)); } void StubCodeCompiler::GenerateFfiCallbackTrampolineStub() { diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc index 9c685cdba7ef..313c7aa92590 100644 --- a/runtime/vm/compiler/stub_code_compiler_x64.cc +++ b/runtime/vm/compiler/stub_code_compiler_x64.cc @@ -44,7 +44,7 @@ void StubCodeCompiler::EnsureIsNewOrRemembered() { // Page's TLAB use is always ascending. Label done; __ AndImmediate(TMP, RAX, target::kPageMask); - __ LoadFromOffset(TMP, Address(TMP, target::Page::original_top_offset())); + __ LoadFromOffset(TMP, TMP, target::Page::original_top_offset()); __ CompareRegisters(RAX, TMP); __ BranchIf(UNSIGNED_GREATER_EQUAL, &done); @@ -429,9 +429,8 @@ void StubCodeCompiler::GenerateLoadFfiCallbackMetadataRuntimeFunction( __ andq(dst, Immediate(FfiCallbackMetadata::kPageMask)); // Load the function from the function table. - __ LoadFromOffset( - dst, - Address(dst, FfiCallbackMetadata::RuntimeFunctionOffset(function_index))); + __ LoadFromOffset(dst, dst, + FfiCallbackMetadata::RuntimeFunctionOffset(function_index)); } static const RegisterSet kArgumentRegisterSet( From 14e2bf8ce8833063985d835a56c0c170fb682401 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Tue, 2 Apr 2024 15:23:57 +0000 Subject: [PATCH 3/6] [deps] rev async, boolean_selector, browser_launcher, cli_util, clock, convert, crypto, csslib, fixnum, html, http, lints, logging, markdown, matcher, mime, path, pool, shelf, source_map_stack_trace, sse, stack_trace, stream_channel, string_scanner, term_glyph, test, test_descriptor, test_process, test_reflective_loader, typed_data, watcher, web, web_socket_channel, webdriver, yaml, yaml_edit Revisions updated by `dart tools/rev_sdk_deps.dart`. async (https://github.com/dart-lang/async/compare/1556660..4796804): 4796804 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/async#270) boolean_selector (https://github.com/dart-lang/boolean_selector/compare/be88351..24635df): 24635df 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/boolean_selector#57) browser_launcher (https://github.com/dart-lang/browser_launcher/compare/7956230..c4b2c81): c4b2c81 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/browser_launcher#56) cli_util (https://github.com/dart-lang/cli_util/compare/ffeb5d2..12cd216): 12cd216 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/cli_util#98) clock (https://github.com/dart-lang/clock/compare/daf0fad..a732a09): a732a09 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/clock#61) convert (https://github.com/dart-lang/convert/compare/d4d6368..186ac22): 186ac22 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/convert#102) crypto (https://github.com/dart-lang/crypto/compare/69d13c9..1c7fbad): 1c7fbad 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/crypto#166) csslib (https://github.com/dart-lang/csslib/compare/4216525..171ed48): 171ed48 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/csslib#198) fixnum (https://github.com/dart-lang/fixnum/compare/570b28a..dec16eb): dec16eb 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/fixnum#125) html (https://github.com/dart-lang/html/compare/327e37a..5b99b43): 5b99b43 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/html#239) http (https://github.com/dart-lang/http/compare/280d361..5214f76): 5214f76 2024-04-01 dependabot[bot] Bump actions/setup-java from 4.1.0 to 4.2.1 (dart-lang/http#1171) f89813e 2024-04-01 dependabot[bot] Bump actions/cache from 4.0.1 to 4.0.2 (dart-lang/http#1169) c14e440 2024-03-28 Brian Quinlan Make `test` a dev_dependency (dart-lang/http#1166) a283716 2024-03-28 Brian Quinlan Add eq, toString and hash methods to HttpProfileRedirectData (dart-lang/http#1165) 70cf298 2024-03-28 Brian Quinlan Ignore errors added to `bodySink`s (dart-lang/http#1164) lints (https://github.com/dart-lang/lints/compare/ead7708..df9bcbf): df9bcbf 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/lints#182) logging (https://github.com/dart-lang/logging/compare/7a7bd5e..dcaf249): dcaf249 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/logging#160) markdown (https://github.com/dart-lang/markdown/compare/8d07abc..782b180): 782b180 2024-04-01 dependabot[bot] Bump subosito/flutter-action from 2.12.0 to 2.15.0 (dart-lang/markdown#603) 8a480f3 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/markdown#604) matcher (https://github.com/dart-lang/matcher/compare/d954c8d..54c2798): 54c2798 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/matcher#244) mime (https://github.com/dart-lang/mime/compare/9a16871..0a32241): 0a32241 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/mime#117) path (https://github.com/dart-lang/path/compare/a7b6960..a7284b9): a7284b9 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/path#160) pool (https://github.com/dart-lang/pool/compare/c118f69..8055cbb): 8055cbb 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/pool#82) shelf (https://github.com/dart-lang/shelf/compare/1acbc67..68cb864): 68cb864 2024-04-01 dependabot[bot] Bump actions/cache from 4.0.1 to 4.0.2 (dart-lang/shelf#422) 4c55675 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/shelf#421) source_map_stack_trace (https://github.com/dart-lang/source_map_stack_trace/compare/c756496..d03fd9b): d03fd9b 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/source_map_stack_trace#47) sse (https://github.com/dart-lang/sse/compare/b53ba14..1ab266a): 1ab266a 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/sse#106) stack_trace (https://github.com/dart-lang/stack_trace/compare/155f12c..c39ae6e): c39ae6e 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/stack_trace#150) stream_channel (https://github.com/dart-lang/stream_channel/compare/e02a5dd..5f72035): 5f72035 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/stream_channel#102) string_scanner (https://github.com/dart-lang/string_scanner/compare/a2bcdb5..8dbfddf): 8dbfddf 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/string_scanner#70) term_glyph (https://github.com/dart-lang/term_glyph/compare/85a4aa6..2ad48ce): 2ad48ce 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/term_glyph#48) test (https://github.com/dart-lang/test/compare/6a4e75a..ce3c8ca): ce3c8cac 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/test#2199) e70c291e 2024-04-01 dependabot[bot] Bump github/codeql-action from 3.24.6 to 3.24.9 (dart-lang/test#2201) cb8c7a6f 2024-04-01 dependabot[bot] Bump actions/cache from 4.0.1 to 4.0.2 (dart-lang/test#2200) test_descriptor (https://github.com/dart-lang/test_descriptor/compare/35f97af..b61cfb4): b61cfb4 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/test_descriptor#62) test_process (https://github.com/dart-lang/test_process/compare/7fe39af..94ee46d): 94ee46d 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/test_process#54) test_reflective_loader (https://github.com/dart-lang/test_reflective_loader/compare/9862703..d7167a2): d7167a2 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/test_reflective_loader#58) typed_data (https://github.com/dart-lang/typed_data/compare/375efaa..8c7393c): 8c7393c 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/typed_data#83) watcher (https://github.com/dart-lang/watcher/compare/21858a4..1bd2f20): 1bd2f20 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/watcher#163) web (https://github.com/dart-lang/web/compare/c522718..e773de9): e773de9 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/web#218) web_socket_channel (https://github.com/dart-lang/web_socket_channel/compare/3db86bc..19d82db): 19d82db 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/web_socket_channel#338) webdriver (https://github.com/google/webdriver.dart/compare/73a7ac8..c80e01e): c80e01e 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (google/webdriver.dart#295) yaml (https://github.com/dart-lang/yaml/compare/e598443..5a1c4be): 5a1c4be 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/yaml#160) yaml_edit (https://github.com/dart-lang/yaml_edit/compare/54884db..f5a92b3): f5a92b3 2024-04-01 dependabot[bot] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/yaml_edit#70) Change-Id: I26b63038b94c9f9b0420256e3f567d10a40f9582 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/360502 Reviewed-by: Konstantin Shcheglov Commit-Queue: Devon Carew --- DEPS | 72 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/DEPS b/DEPS index 44c07aef6334..4510f1dab9ab 100644 --- a/DEPS +++ b/DEPS @@ -121,18 +121,18 @@ vars = { # revision. "args_rev": "788d93541a578e49f066699e1584bc3ce591c376", - "async_rev": "1556660ca5159d84bf28239825a25dca58f1fde3", + "async_rev": "47968047eb9888f74ca0691640821bd55b47e763", "bazel_worker_rev": "8619b92baa9959e55b9fc49d2afcd6dda2ec1c10", "benchmark_harness_rev": "c8a0c8b1883dc16c7558a43cee1c3f4f9a163418", - "boolean_selector_rev": "be88351e521648d381b96350bfe62c34abacee6d", - "browser_launcher_rev": "79562306c86e5c087359a31a60309c8d65a699d3", + "boolean_selector_rev": "24635df68661bb44c1c13fb405562421e24298e5", + "browser_launcher_rev": "c4b2c81aa9debcce3651eda1b68a9bc5d5adf400", "characters_rev": "7633a16a22c626e19ca750223237396315268a06", - "cli_util_rev": "ffeb5d2869b44b28d1b9035b540d164af44f3f1c", - "clock_rev": "daf0fadabc5b3dc8e6e71bf3fb27ef9c3b79df5c", + "cli_util_rev": "12cd216263be587a648600b40017463341bccaf8", + "clock_rev": "a732a09149708ae0b986bec9931576d22818d158", "collection_rev": "fc616ff8fd7b732c07b2b19e31b6601e59900ccf", - "convert_rev": "d4d6368cffb8f4f25522875ef8e1d5f7d158bbad", - "crypto_rev": "69d13c9903d4134582ce1bbd9a31cfd8a510c22d", - "csslib_rev": "42165256befc3994db510695c17e718e617435c9", + "convert_rev": "186ac2281f0436451b49e1bd8458ff791b42637d", + "crypto_rev": "1c7fbadd92a44322ee1e89eec9747a24dc6c6746", + "csslib_rev": "171ed4885f1db13e22b04b513a169e7a99d2c5d5", # Note: Updates to dart_style have to be coordinated with the infrastructure # team so that the internal formatter `tools/sdks/dart-sdk/bin/dart format` # matches the version here. Please follow this process to make updates: @@ -147,57 +147,57 @@ vars = { "dartdoc_rev": "bf6080c8a12bf3a2f29f517d152bbd5fa1bb0a37", "ecosystem_rev": "5a900ca68466efe8680d3500bc0a6172d07ef5a7", "file_rev": "3aa06490bf34bddf04c7ea964a50c177a4ca0de7", - "fixnum_rev": "570b28adcfbfdd5b8a7230ea1d6ec0f9587493f1", + "fixnum_rev": "dec16eb715f70f2fe0ed509da2e118354bea21d8", "flute_rev": "a531c96a8b43d015c6bfbbfe3ab54867b0763b8b", "glob_rev": "379d60c7cc5c0e9fe7d0d45549ad0b1ca51396c8", - "html_rev": "327e37a6a4dd46599737ee982f280d73a8f646f7", - "http_rev": "280d3615a2d248d155e87766c9d9bcf586af2c3c", + "html_rev": "5b99b43f71da0c6b0f962244c7f5dfa8ca970fef", + "http_rev": "5214f7647ea7a7dd360f12625358bd39f8e6aec0", "http_multi_server_rev": "ba9d07f3596b24718ddf45c9e071d40879cca565", "http_parser_rev": "84db8b029d9b51859a0bb4966859af009f9442e3", "intl_rev": "5d65e3808ce40e6282e40881492607df4e35669f", "json_rpc_2_rev": "639857be892050159f5164c749d7947694976a4a", "leak_tracker_rev": "f5620600a5ce1c44f65ddaa02001e200b096e14c", # manually rolled - "lints_rev": "ead770872e272e25a64315c120950ea8ad5b2509", - "logging_rev": "7a7bd5e31ddfe23e34d37ded82d6d0cd5706862c", - "markdown_rev": "8d07abc6bce001b000097eca35c2f5e37538702a", - "matcher_rev": "d954c8d979579b4b46427b0ea1d9c721117c191e", + "lints_rev": "df9bcbf6dd8964468d0bfa0b1b7286cf850c1656", + "logging_rev": "dcaf2498e5ce34b17b48770b4e78c44fc9e63cd3", + "markdown_rev": "782b1803a29aa964410d93b4437d5d1efa47f6b4", + "matcher_rev": "54c2798d9b75c6db5cdcc7acbf5b9ae215316ed5", "material_color_utilities_rev": "799b6ba2f3f1c28c67cc7e0b4f18e0c7d7f3c03e", - "mime_rev": "9a168712d6db610c3822617c132daea72d4fd2b5", + "mime_rev": "0a32241c4fcd077a945949760b287677e4d7aff4", "mockito_rev": "3ef744f8749864f2a036eba60c4203cc8f638949", "native_rev": "71ada4b5c8001e6b8207ed40331d158e0912cd94", # mosum@ and dacoharkes@ are rolling breaking changes manually while the assets features are in experimental. "package_config_rev": "3d90e6955ef19b7ce4f1b742a06a20ed4260700a", - "path_rev": "a7b696071bd83d3ee0a0f1b57ac94d6b1f05cac4", - "pool_rev": "c118f69d8a6441a8453bf7d455fd7c79d3ee1497", + "path_rev": "a7284b9917830c18618b26d396d0f0bffc92bb01", + "pool_rev": "8055cbb290590e761e1149dfbf7c2283fdd88e4f", "protobuf_rev": "b7613581d847e1e36e76f0e36db3a412d8fea5b1", "pub_rev": "3f0df78417f7c112b933fbcdc1c5c87bde680cb1", # disable tools/rev_sdk_deps.dart "pub_semver_rev": "3175ba0a58a96fb23f8d68b5f5c44d1a5b30cc16", - "shelf_rev": "1acbc673326e5b31280184744f2864a8f92c5b46", - "source_map_stack_trace_rev": "c75649651d01826236e3ab7093d277a70756905a", + "shelf_rev": "68cb8641c3181cc76006887a7e93b9d3a423f590", + "source_map_stack_trace_rev": "d03fd9b1cc11f2ad61ccc2e71bfd8d2558019a6d", "source_maps_rev": "55e92a4b0a8560d5b2b3bb7255249afdb8186ea6", "source_span_rev": "21a403a75b6887fbd811fb53b74b08c2cef67ab6", - "sse_rev": "b53ba14de4fe9823432ebfbb4ec04f23a620ec50", - "stack_trace_rev": "155f12c51226d6372f6722f5e55c38ef39625006", - "stream_channel_rev": "e02a5ddef804f0d546a405ab3917fb27788acaef", - "string_scanner_rev": "a2bcdb575f6bb30b944b4f632ea95d8dc4f914bd", + "sse_rev": "1ab266ad570134294468225d1c2ffe86338005be", + "stack_trace_rev": "c39ae6e955a76a2ff183288f051f4eee7a5e94d1", + "stream_channel_rev": "5f72035464ea675c75982b80db967943a0cfddcb", + "string_scanner_rev": "8dbfddf9a7e8cdd4978ddd3cdab188cfabc543fd", "sync_http_rev": "b849559fedc7c5d19a68950f255b6edde6eec6ef", "tar_rev": "6150a0c88d9bd17e3e961593a9a7a9564866e8b4", - "term_glyph_rev": "85a4aa6bf25cd6ecaa5c56a1b259b2d95264a439", - "test_rev": "6a4e75a6283b1366ea21067f9ced0b6c87745d4a", - "test_descriptor_rev": "35f97afacb2b7fe627f6ed0bede722fd48980848", - "test_process_rev": "7fe39afbb6c444f256c1ec0eef008edebcd44644", - "test_reflective_loader_rev": "9862703a3d14848376c8efde271c88022fba91eb", + "term_glyph_rev": "2ad48ce95b6e6d001251d55b15719ee113caf802", + "test_rev": "ce3c8cac1d8e7f055d5443993ac6c0204da17a45", + "test_descriptor_rev": "b61cfb4479fafd78eb9d365cc2f7cdb43c2aed34", + "test_process_rev": "94ee46d76f89ebb7d73cef3e23bab288b1e43b50", + "test_reflective_loader_rev": "d7167a2375d8a0c02c12b960c059a115a777f238", "tools_rev": "f611290b530123ee2f0a3fda7c440d85dd080a30", # https://github.com/dart-lang/tools/pull/247 - "typed_data_rev": "375efaa02a13dad0785cfbd9bdcb9f09aa8ef529", + "typed_data_rev": "8c7393cbbbba7a5d38c6772371f92d6b38e433fc", "usage_rev": "67ecd7d1328347ec15cbf8d8a46918df75a66af8", "vector_math_rev": "7e705f734e94917e9a5347578e6e496f8db38ac6", - "watcher_rev": "21858a41da1482922e03ee65cdf2169d01d59a67", - "web_rev": "c522718242d535d8040447b0cc1d47df7f2525a4", - "web_socket_channel_rev": "3db86bc0a09e1038a0fa418262c8a92211c5de69", + "watcher_rev": "1bd2f20d0d924c8422aa2b9afdb165bff4f053c0", + "web_rev": "e773de957b289d001c90c6b830e91634e305667d", + "web_socket_channel_rev": "19d82db86acb7309dd08c40a2af3285232751e83", "webdev_rev": "51b5484348b4a8ede351e8dff0428b083495ba78", # https://github.com/flutter/devtools/issues/7231 - "webdriver_rev": "73a7ac8c0dcb0f84eae47e2133805295176aa972", + "webdriver_rev": "c80e01e6ce121e55c31e33a31e5d3950023e6bc9", "webkit_inspection_protocol_rev": "153fea4fe5ac45bebf0c2e76bb3d76b0f1fcdaae", - "yaml_rev": "e5984433a2803d5c67ed0abac5891a55040381ee", - "yaml_edit_rev": "54884db790720ac0f7ca491cb9e6d7a0395ad4cb", + "yaml_rev": "5a1c4be2437bc4122ccf08a3a0f06a7683e62f30", + "yaml_edit_rev": "f5a92b3bc64b4e78ec1fb616ad1dff2174e799b1", # Windows deps "crashpad_rev": "bf327d8ceb6a669607b0dbab5a83a275d03f99ed", From 046f3117b67108374ac363a512560c3f1abf9a10 Mon Sep 17 00:00:00 2001 From: Danny Tuppeny Date: Tue, 2 Apr 2024 16:09:26 +0000 Subject: [PATCH 4/6] [analysis_server] Fix navigation on augmentation directives Change-Id: I0972d6c9aa93f1bac180504da96e63ed9f04e63e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/360260 Commit-Queue: Brian Wilkerson Reviewed-by: Konstantin Shcheglov Reviewed-by: Brian Wilkerson --- .../notification_navigation_test.dart | 32 +++++ .../test/lsp/definition_test.dart | 113 ++++++++++-------- .../lib/utilities/analyzer_converter.dart | 12 +- .../utilities/navigation/navigation_dart.dart | 23 +++- 4 files changed, 121 insertions(+), 59 deletions(-) diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart index ac727cae0d40..4f08a67aa3d1 100644 --- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart +++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart @@ -1709,6 +1709,22 @@ class A { } } + Future test_string_augmentLibrary() async { + var augmentedCode = 'import augment "test.dart";'; + var augmentedFile = + newFile('$testPackageLibPath/augmented.dart', augmentedCode).path; + addTestFile('library augment "augmented.dart";'); + await prepareNavigation(); + assertHasRegionString('"augmented.dart"'); + assertHasFileTarget(augmentedFile, 0, 0); + } + + Future test_string_augmentLibrary_unresolvedUri() async { + addTestFile('library augment "no.dart";'); + await prepareNavigation(); + assertNoRegionString('"no.dart"'); + } + Future test_string_configuration() async { newFile('$testPackageLibPath/lib.dart', '').path; var lib2File = newFile('$testPackageLibPath/lib2.dart', '').path; @@ -1755,6 +1771,22 @@ class A { assertNoRegionString('"no.dart"'); } + Future test_string_importAugment() async { + var augmentCode = 'library augment "test.dart";'; + var augmentFile = + newFile('$testPackageLibPath/augment.dart', augmentCode).path; + addTestFile('import augment "augment.dart";'); + await prepareNavigation(); + assertHasRegionString('"augment.dart"'); + assertHasFileTarget(augmentFile, 0, 0); + } + + Future test_string_importAugment_unresolvedUri() async { + addTestFile('import augment "no.dart";'); + await prepareNavigation(); + assertNoRegionString('"no.dart"'); + } + Future test_string_part() async { var unitCode = 'part of lib; f() {}'; var unitFile = newFile('$testPackageLibPath/test_unit.dart', unitCode).path; diff --git a/pkg/analysis_server/test/lsp/definition_test.dart b/pkg/analysis_server/test/lsp/definition_test.dart index b6626321e269..6230389e900c 100644 --- a/pkg/analysis_server/test/lsp/definition_test.dart +++ b/pkg/analysis_server/test/lsp/definition_test.dart @@ -268,6 +268,46 @@ class [!A!] { await testContents(contents); } + Future test_directive_augmentLibrary() async { + await verifyDirective( + source: "library augment 'destin^ation.dart';", + destination: "import augment 'source.dart';", + ); + } + + Future test_directive_export() async { + await verifyDirective( + source: "export 'destin^ation.dart';", + ); + } + + Future test_directive_import() async { + await verifyDirective( + source: "import 'desti^nation.dart';", + ); + } + + Future test_directive_importAugment() async { + await verifyDirective( + source: "import augment 'destin^ation.dart';", + destination: "library augment 'source.dart';", + ); + } + + Future test_directive_part() async { + await verifyDirective( + source: "part 'desti^nation.dart';", + destination: "part of 'source.dart';", + ); + } + + Future test_directive_partOf() async { + await verifyDirective( + source: "part of 'destin^ation.dart';", + destination: "part 'source.dart';", + ); + } + Future test_fieldFormalParam() async { final contents = ''' class A { @@ -571,54 +611,6 @@ class A {} ); } - Future test_partFilename() async { - final mainContents = ''' -part 'pa^rt.dart'; - '''; - - final partContents = ''' -part of 'main.dart'; - '''; - - final partFilePath = join(projectFolderPath, 'lib', 'part.dart'); - final partFileUri = toUri(partFilePath); - - final mainCode = TestCode.parse(mainContents); - final partCode = TestCode.parse(partContents); - - newFile(mainFilePath, mainCode.code); - newFile(partFilePath, partCode.code); - await initialize(); - final res = - await getDefinitionAsLocation(mainFileUri, mainCode.position.position); - - expect(res.single.uri, equals(partFileUri)); - } - - Future test_partOfFilename() async { - final mainContents = ''' -part 'part.dart'; - '''; - - final partContents = ''' -part of 'ma^in.dart'; - '''; - - final partFilePath = join(projectFolderPath, 'lib', 'part.dart'); - final partFileUri = toUri(partFilePath); - - final mainCode = TestCode.parse(mainContents); - final partCode = TestCode.parse(partContents); - - newFile(mainFilePath, mainCode.code); - newFile(partFilePath, partCode.code); - await initialize(); - final res = - await getDefinitionAsLocation(partFileUri, partCode.position.position); - - expect(res.single.uri, equals(mainFileUri)); - } - Future test_sameLine() async { final contents = ''' int plusOne(int [!value!]) => 1 + val^ue; @@ -714,4 +706,29 @@ foo() { expect(loc.range, equals(code.range.range)); expect(loc.uri, equals(mainFileUri)); } + + /// Verifies that invoking Definition at `^` in [source] (which will be + /// written into `source.dart`) navigate to `destination.dart` (with the + /// content [destination]). + Future verifyDirective({ + required String source, + String destination = '', + }) async { + final destinationCode = TestCode.parse(destination); + final sourceCode = TestCode.parse(source); + + final sourceFilePath = join(projectFolderPath, 'lib', 'source.dart'); + final sourceFileUri = toUri(sourceFilePath); + final destinationFilePath = + join(projectFolderPath, 'lib', 'destination.dart'); + final destinationFileUri = toUri(destinationFilePath); + + newFile(sourceFilePath, sourceCode.code); + newFile(destinationFilePath, destinationCode.code); + await initialize(); + final res = await getDefinitionAsLocation( + sourceFileUri, sourceCode.position.position); + + expect(res.single.uri, equals(destinationFileUri)); + } } diff --git a/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart b/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart index 86e209ef2c2a..f564f702f5a6 100644 --- a/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart +++ b/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart @@ -318,21 +318,13 @@ extension ElementExtensions on analyzer.Element? { /// Return the compilation unit containing the given [element]. analyzer.CompilationUnitElement? get _unitElement { var currentElement = this; - if (currentElement is analyzer.CompilationUnitElement) { - return currentElement; - } - if (currentElement?.enclosingElement - is analyzer.LibraryOrAugmentationElement) { - currentElement = currentElement?.enclosingElement; - } - if (currentElement is analyzer.LibraryOrAugmentationElement) { - return currentElement.definingCompilationUnit; - } for (; currentElement != null; currentElement = currentElement.enclosingElement) { if (currentElement is analyzer.CompilationUnitElement) { return currentElement; + } else if (currentElement is analyzer.LibraryOrAugmentationElement) { + return currentElement.definingCompilationUnit; } } return null; diff --git a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart index 3f7f5585d872..f78d8153e47a 100644 --- a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart +++ b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart @@ -219,6 +219,12 @@ class _DartNavigationComputerVisitor extends RecursiveAstVisitor { node.rightHandSide.accept(this); } + @override + void visitAugmentationImportDirective(AugmentationImportDirective node) { + super.visitAugmentationImportDirective(node); + _addUriDirectiveRegion(node, node.element?.importedAugmentation); + } + @override void visitBinaryExpression(BinaryExpression node) { node.leftOperand.accept(this); @@ -431,6 +437,18 @@ class _DartNavigationComputerVisitor extends RecursiveAstVisitor { computer._addRegionForToken(node.rightBracket, element); } + @override + void visitLibraryAugmentationDirective(LibraryAugmentationDirective node) { + super.visitLibraryAugmentationDirective(node); + var element = node.element; + var library = element?.library; + // If the library URI is unresolved, library will be the augmentation + // itself, so don't create a navigation region in that case. + if (element != library) { + _addUriDirectiveRegion(node, library); + } + } + @override void visitLibraryDirective(LibraryDirective node) { computer._addRegionForNode(node.name2, node.element); @@ -619,7 +637,10 @@ class _DartNavigationComputerVisitor extends RecursiveAstVisitor { /// If the source of the given [element] (referenced by the [node]) exists, /// then add the navigation region from the [node] to the [element]. - void _addUriDirectiveRegion(UriBasedDirective node, LibraryElement? element) { + void _addUriDirectiveRegion( + UriBasedDirective node, + LibraryOrAugmentationElement? element, + ) { var source = element?.source; if (source != null) { if (resourceProvider.getResource(source.fullName).exists) { From c5f876b7aaca65c6bdc6d718cf18d0ee9c335afb Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Tue, 2 Apr 2024 16:12:00 +0000 Subject: [PATCH 5/6] Augment. Use ExtensionOnClause in ExtensionDeclaration, make it optional. Change-Id: I696ffd0b8e8f3bf9017b583d480313ec7c7753f7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/360561 Reviewed-by: Brian Wilkerson Reviewed-by: Johnni Winther Commit-Queue: Konstantin Shcheglov --- .../lib/src/messages/codes_generated.dart | 12 +++ .../lib/src/parser/forwarding_listener.dart | 2 +- .../lib/src/parser/listener.dart | 2 +- .../lib/src/parser/parser_impl.dart | 38 +++++--- .../lib/src/computer/computer_highlights.dart | 13 +-- .../lib/src/computer/computer_outline.dart | 12 ++- .../completion/dart/completion_state.dart | 2 +- .../dart/in_scope_completion_pass.dart | 20 +++-- .../completion/dart/keyword_helper.dart | 3 +- .../correction/dart/import_library.dart | 2 +- .../services/correction/error_fix_status.yaml | 4 + .../notification_highlights2_test.dart | 37 ++++++-- .../tool/code_completion/code_metrics.dart | 2 +- .../code_completion/relevance_metrics.dart | 2 +- .../relevance_table_generator.dart | 2 +- .../tool/code_completion/visitors.dart | 2 +- pkg/analyzer/lib/dart/ast/ast.dart | 1 + pkg/analyzer/lib/dart/ast/visitor.dart | 26 ++++++ pkg/analyzer/lib/src/dart/ast/ast.dart | 88 +++++++++++++++---- .../lib/src/dart/ast/to_source_visitor.dart | 11 ++- pkg/analyzer/lib/src/dart/ast/utilities.dart | 13 +-- .../src/dart/error/syntactic_errors.g.dart | 9 ++ .../src/dart/resolver/resolution_visitor.dart | 2 +- .../lib/src/error/error_code_values.g.dart | 1 + pkg/analyzer/lib/src/fasta/ast_builder.dart | 20 +++-- pkg/analyzer/lib/src/generated/resolver.dart | 8 +- pkg/analyzer/lib/src/lint/linter_visitor.dart | 12 +++ .../lib/src/summary2/element_builder.dart | 5 ++ .../lib/src/summary2/macro_declarations.dart | 6 +- .../lib/src/summary2/reference_resolver.dart | 7 +- .../lib/src/summary2/types_builder.dart | 6 +- .../extension_methods_parser_test.dart | 61 ++++++------- .../test/generated/parser_fasta_listener.dart | 2 +- .../src/dart/ast/to_source_visitor_test.dart | 8 ++ .../test/src/dart/parser/extension_test.dart | 58 ++++-------- .../test/src/fasta/ast_builder_test.dart | 23 ++--- .../src/summary/resolved_ast_printer.dart | 8 ++ .../lib/src/utilities/completion/optype.dart | 10 ++- .../src/utilities/completion/optype_test.dart | 5 +- .../fasta/kernel/macro/annotation_parser.dart | 2 +- .../lib/src/fasta/source/diet_listener.dart | 2 +- .../lib/src/fasta/source/outline_builder.dart | 2 +- .../lib/src/fasta/util/parser_ast_helper.dart | 6 +- .../lib/src/fasta/util/textual_outline.dart | 2 +- pkg/front_end/messages.status | 2 + pkg/front_end/messages.yaml | 9 ++ pkg/front_end/test/parser_test_listener.dart | 2 +- .../collection_methods_unrelated_type.dart | 2 +- .../library_private_types_in_public_api.dart | 2 +- .../lib/src/rules/prefer_void_to_null.dart | 2 +- .../lib/src/rules/test_types_in_equals.dart | 4 +- .../test/rules/prefer_void_to_null_test.dart | 6 ++ .../test_data/rules/prefer_void_to_null.dart | 3 - 53 files changed, 404 insertions(+), 187 deletions(-) diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart index 0bbd8926aa22..f1dd247b3b5c 100644 --- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart +++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart @@ -5160,6 +5160,18 @@ const MessageCode messageExtendsVoid = const MessageCode( problemMessage: r"""The type 'void' can't be used in an 'extends' clause.""", ); +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Code codeExtensionAugmentationHasOnClause = + messageExtensionAugmentationHasOnClause; + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const MessageCode messageExtensionAugmentationHasOnClause = const MessageCode( + "ExtensionAugmentationHasOnClause", + index: 179, + problemMessage: r"""Extension augmentations can't have 'on' clauses.""", + correctionMessage: r"""Try removing the 'on' clause.""", +); + // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. const Code codeExtensionDeclaresAbstractMember = messageExtensionDeclaresAbstractMember; diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart index 872f03c62579..cae695e7bb03 100644 --- a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart +++ b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart @@ -835,7 +835,7 @@ class ForwardingListener implements Listener { @override void endExtensionDeclaration(Token beginToken, Token extensionKeyword, - Token onKeyword, Token endToken) { + Token? onKeyword, Token endToken) { listener?.endExtensionDeclaration( beginToken, extensionKeyword, onKeyword, endToken); } diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart index 24b825e818ea..d4cc3e87ed41 100644 --- a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart +++ b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart @@ -259,7 +259,7 @@ class Listener implements UnescapeErrorListener { /// - on type /// - body void endExtensionDeclaration(Token beginToken, Token extensionKeyword, - Token onKeyword, Token endToken) { + Token? onKeyword, Token endToken) { logEvent('ExtensionDeclaration'); } diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart index cd12e448b8c5..a510ff0d00ca 100644 --- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart +++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart @@ -3106,22 +3106,36 @@ class Parser { token = computeTypeParamOrArg(token, /* inDeclaration = */ true) .parseVariables(token, this); listener.beginExtensionDeclaration(augmentToken, extensionKeyword, name); - Token onKeyword = token.next!; - if (!optional('on', onKeyword)) { - // Recovery - if (optional('extends', onKeyword) || - optional('implements', onKeyword) || - optional('with', onKeyword)) { - reportRecoverableError( - onKeyword, codes.templateExpectedInstead.withArguments('on')); + + Token? onKeyword = token.next!; + if (augmentToken != null) { + if (!optional('on', onKeyword)) { + // Extension augmentations should not provide `on` clauses. + onKeyword = null; } else { + // If `on` clause is provided, report, but parse it. reportRecoverableError( - token, codes.templateExpectedAfterButGot.withArguments('on')); - onKeyword = rewriter.insertSyntheticKeyword(token, Keyword.ON); + onKeyword, codes.messageExtensionAugmentationHasOnClause); + TypeInfo typeInfo = computeType(onKeyword, /* required = */ true); + token = typeInfo.ensureTypeOrVoid(onKeyword, this); + } + } else { + if (!optional('on', onKeyword)) { + // Recovery + if (optional('extends', onKeyword) || + optional('implements', onKeyword) || + optional('with', onKeyword)) { + reportRecoverableError( + onKeyword, codes.templateExpectedInstead.withArguments('on')); + } else { + reportRecoverableError( + token, codes.templateExpectedAfterButGot.withArguments('on')); + onKeyword = rewriter.insertSyntheticKeyword(token, Keyword.ON); + } } + TypeInfo typeInfo = computeType(onKeyword, /* required = */ true); + token = typeInfo.ensureTypeOrVoid(onKeyword, this); } - TypeInfo typeInfo = computeType(onKeyword, /* required = */ true); - token = typeInfo.ensureTypeOrVoid(onKeyword, this); if (!optional('{', token.next!)) { // Recovery diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart index 9095ac95f3b5..6ec38ae65ab8 100644 --- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart +++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart @@ -881,17 +881,20 @@ class _DartUnitHighlightsComputerVisitor extends RecursiveAstVisitor { @override void visitExtensionDeclaration(ExtensionDeclaration node) { - // TODO(brianwilkerson): Uncomment the following lines when the token is - // supported. - // computer._addRegion_token( - // node.augmentKeyword, HighlightRegionType.BUILT_IN); + computer._addRegion_token( + node.augmentKeyword, HighlightRegionType.BUILT_IN); computer._addRegion_token( node.extensionKeyword, HighlightRegionType.KEYWORD); computer._addRegion_token(node.name, HighlightRegionType.EXTENSION); - computer._addRegion_token(node.onKeyword, HighlightRegionType.BUILT_IN); super.visitExtensionDeclaration(node); } + @override + void visitExtensionOnClause(ExtensionOnClause node) { + computer._addRegion_token(node.onKeyword, HighlightRegionType.BUILT_IN); + super.visitExtensionOnClause(node); + } + @override void visitExtensionOverride(ExtensionOverride node) { computer._addRegion_token( diff --git a/pkg/analysis_server/lib/src/computer/computer_outline.dart b/pkg/analysis_server/lib/src/computer/computer_outline.dart index 635e4e4b9d75..17d2c74bc986 100644 --- a/pkg/analysis_server/lib/src/computer/computer_outline.dart +++ b/pkg/analysis_server/lib/src/computer/computer_outline.dart @@ -185,15 +185,21 @@ class DartUnitOutlineComputer { ExtensionDeclaration node, List extensionContents) { var nameToken = node.name; var name = nameToken?.lexeme ?? ''; + + Location? location; + if (nameToken != null) { + location = _getLocationToken(nameToken); + } else if (node.onClause case var onClause?) { + location = _getLocationNode(onClause.extendedType); + } + var element = Element( ElementKind.EXTENSION, name, Element.makeFlags( isPrivate: Identifier.isPrivateName(name), isDeprecated: _isDeprecated(node)), - location: nameToken != null - ? _getLocationToken(nameToken) - : _getLocationNode(node.extendedType), + location: location, typeParameters: _getTypeParametersStr(node.typeParameters)); return _nodeOutline(node, element, extensionContents); } diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_state.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_state.dart index 862fe5fe7312..ea4b2f81bd28 100644 --- a/pkg/analysis_server/lib/src/services/completion/dart/completion_state.dart +++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_state.dart @@ -58,7 +58,7 @@ class CompletionState { return element.thisType; } case ExtensionDeclaration(): - return node.extendedType.type; + return node.onClause?.extendedType.type; case MixinDeclaration(): var element = node.declaredElement; if (element != null) { diff --git a/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart b/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart index 20c2b40c40a2..41dbdd8c3108 100644 --- a/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart +++ b/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart @@ -1075,11 +1075,10 @@ class InScopeCompletionPass extends SimpleAstVisitor { identifierHelper(includePrivateIdentifiers: false).addTopLevelName(); } if (offset <= node.leftBracket.offset) { - if (node.onKeyword.isSynthetic) { - keywordHelper.addExtensionDeclarationKeywords(node); - } else { - collector.completionLocation = 'ExtensionDeclaration_extendedType'; - _forTypeAnnotation(node); + if (node.onClause case var onClause?) { + if (onClause.onKeyword.isSynthetic) { + keywordHelper.addExtensionDeclarationKeywords(node); + } } return; } @@ -1089,6 +1088,17 @@ class InScopeCompletionPass extends SimpleAstVisitor { } } + @override + void visitExtensionOnClause(ExtensionOnClause node) { + if (offset <= node.onKeyword.end) { + keywordHelper.addKeyword(Keyword.ON); + return; + } + + collector.completionLocation = 'ExtensionOnClause_extendedType'; + _forTypeAnnotation(node); + } + @override void visitExtensionOverride(ExtensionOverride node) { _forExpression(node); diff --git a/pkg/analysis_server/lib/src/services/completion/dart/keyword_helper.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_helper.dart index 73e3a325118e..f9f8793954b8 100644 --- a/pkg/analysis_server/lib/src/services/completion/dart/keyword_helper.dart +++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_helper.dart @@ -318,7 +318,8 @@ class KeywordHelper { /// extension declaration between the name of the extension and the body. The /// [node] is the extension declaration containing the selection point. void addExtensionDeclarationKeywords(ExtensionDeclaration node) { - if (node.onKeyword.isSynthetic) { + var onClause = node.onClause; + if (onClause == null || onClause.onKeyword.isSynthetic) { addKeyword(Keyword.ON); if (node.name == null && featureSet.isEnabled(Feature.inline_class)) { addText('type'); diff --git a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart index 7ff234605163..94f6b7da9f79 100644 --- a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart +++ b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart @@ -367,7 +367,7 @@ class ImportLibrary extends MultiCorrectionProducer { if (parent is ClassDeclaration) { return parent.declaredElement?.thisType; } else if (parent is ExtensionDeclaration) { - return parent.extendedType.type; + return parent.onClause?.extendedType.type; } else if (parent is MixinDeclaration) { return parent.declaredElement?.thisType; } else { diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml index 732751ecaa3f..72917e9862de 100644 --- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml +++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml @@ -2778,6 +2778,10 @@ ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE: status: needsFix notes: |- Move the directive to a valid place. +ParserErrorCode.EXTENSION_AUGMENTATION_HAS_ON_CLAUSE: + status: needsFix + notes: |- + Remove the 'on' clause. ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER: status: needsFix notes: |- diff --git a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart index b29d57ecd755..9bcc407ff001 100644 --- a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart +++ b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart @@ -143,15 +143,6 @@ augment enum E {a, b} assertHasRegion(HighlightRegionType.BUILT_IN, 'augment'); } - @SkippedTest(reason: 'The token is not supported') - Future test_BUILT_IN_augment_onExtension() async { - addTestFile(''' -augment extension on int {} -'''); - await prepareHighlights(); - assertHasRegion(HighlightRegionType.BUILT_IN, 'augment'); - } - Future test_BUILT_IN_augment_onImport() async { addTestFile(''' import augment 'a.dart'; @@ -1254,6 +1245,34 @@ void f() { assertHasRegion(HighlightRegionType.EXTENSION, 'E.bar()'); } + Future test_extension_augment() async { + final testCode = TestCode.parse(r''' +augment extension E {} +'''); + addTestFile(testCode.code); + await prepareHighlights(); + assertHighlightText(testCode, -1, r''' +0 + 7 |augment| BUILT_IN +8 + 9 |extension| KEYWORD +18 + 1 |E| EXTENSION +'''); + } + + Future test_extension_augment_hasOnClause() async { + final testCode = TestCode.parse(r''' +augment extension E on int {} +'''); + addTestFile(testCode.code); + await prepareHighlights(); + assertHighlightText(testCode, -1, r''' +0 + 7 |augment| BUILT_IN +8 + 9 |extension| KEYWORD +18 + 1 |E| EXTENSION +20 + 2 |on| BUILT_IN +23 + 3 |int| CLASS +'''); + } + Future test_extensionType() async { final testCode = TestCode.parse(r''' extension type const A.named(int it) implements num {} diff --git a/pkg/analysis_server/tool/code_completion/code_metrics.dart b/pkg/analysis_server/tool/code_completion/code_metrics.dart index 93fbf4bb7f70..2d04916ac728 100644 --- a/pkg/analysis_server/tool/code_completion/code_metrics.dart +++ b/pkg/analysis_server/tool/code_completion/code_metrics.dart @@ -541,7 +541,7 @@ class CodeShapeDataCollector extends RecursiveAstVisitor { _visitChildren(node, { 'name': node.name, 'typeParameters': node.typeParameters, - 'extendedType': node.extendedType, + 'onClause': node.onClause, 'member': node.members, }); super.visitExtensionDeclaration(node); diff --git a/pkg/analysis_server/tool/code_completion/relevance_metrics.dart b/pkg/analysis_server/tool/code_completion/relevance_metrics.dart index e55a76928612..3d90f886d9b5 100644 --- a/pkg/analysis_server/tool/code_completion/relevance_metrics.dart +++ b/pkg/analysis_server/tool/code_completion/relevance_metrics.dart @@ -656,7 +656,7 @@ class RelevanceDataCollector extends RecursiveAstVisitor { inGenericContext = inGenericContext || node.typeParameters != null; data.recordPercentage( 'Extensions with type parameters', node.typeParameters != null); - _recordDataForNode('ExtensionDeclaration (type)', node.extendedType); + _recordDataForNode('ExtensionDeclaration (onClause)', node.onClause); for (var member in node.members) { _recordDataForNode('ExtensionDeclaration (member)', member, allowedKeywords: memberKeywords); diff --git a/pkg/analysis_server/tool/code_completion/relevance_table_generator.dart b/pkg/analysis_server/tool/code_completion/relevance_table_generator.dart index 143fa285e769..32bb9e225172 100644 --- a/pkg/analysis_server/tool/code_completion/relevance_table_generator.dart +++ b/pkg/analysis_server/tool/code_completion/relevance_table_generator.dart @@ -649,7 +649,7 @@ class RelevanceDataCollector extends RecursiveAstVisitor { @override void visitExtensionDeclaration(ExtensionDeclaration node) { - _recordDataForNode('ExtensionDeclaration_extendedType', node.extendedType); + _recordDataForNode('ExtensionDeclaration_onClause', node.onClause); for (var member in node.members) { _recordDataForNode('ExtensionDeclaration_member', member, allowedKeywords: memberKeywords); diff --git a/pkg/analysis_server/tool/code_completion/visitors.dart b/pkg/analysis_server/tool/code_completion/visitors.dart index 0f47648d830f..b5c10faa8cc1 100644 --- a/pkg/analysis_server/tool/code_completion/visitors.dart +++ b/pkg/analysis_server/tool/code_completion/visitors.dart @@ -409,7 +409,7 @@ class ExpectedCompletionsVisitor extends RecursiveAstVisitor { @override void visitExtensionDeclaration(ExtensionDeclaration node) { safelyRecordKeywordCompletion(node.extensionKeyword); - safelyRecordKeywordCompletion(node.onKeyword); + safelyRecordKeywordCompletion(node.onClause); super.visitExtensionDeclaration(node); } diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart index 590e78340d19..a0ac1beb6088 100644 --- a/pkg/analyzer/lib/dart/ast/ast.dart +++ b/pkg/analyzer/lib/dart/ast/ast.dart @@ -104,6 +104,7 @@ export 'package:analyzer/src/dart/ast/ast.dart' ExpressionStatement, ExtendsClause, ExtensionDeclaration, + ExtensionOnClause, ExtensionOverride, ExtensionTypeDeclaration, FieldDeclaration, diff --git a/pkg/analyzer/lib/dart/ast/visitor.dart b/pkg/analyzer/lib/dart/ast/visitor.dart index 03e37f886389..772a9a396b46 100644 --- a/pkg/analyzer/lib/dart/ast/visitor.dart +++ b/pkg/analyzer/lib/dart/ast/visitor.dart @@ -318,6 +318,9 @@ class GeneralizingAstVisitor implements AstVisitor { R? visitExtensionDeclaration(ExtensionDeclaration node) => visitCompilationUnitMember(node); + @override + R? visitExtensionOnClause(ExtensionOnClause node) => visitNode(node); + @override R? visitExtensionOverride(ExtensionOverride node) => visitExpression(node); @@ -1093,6 +1096,12 @@ class RecursiveAstVisitor implements AstVisitor { return null; } + @override + R? visitExtensionOnClause(ExtensionOnClause node) { + node.visitChildren(this); + return null; + } + @override R? visitExtensionOverride(ExtensionOverride node) { node.visitChildren(this); @@ -1978,6 +1987,9 @@ class SimpleAstVisitor implements AstVisitor { @override R? visitExtensionDeclaration(ExtensionDeclaration node) => null; + @override + R? visitExtensionOnClause(ExtensionOnClause node) => null; + @override R? visitExtensionOverride(ExtensionOverride node) => null; @@ -2518,6 +2530,9 @@ class ThrowingAstVisitor implements AstVisitor { @override R? visitExtensionDeclaration(ExtensionDeclaration node) => _throw(node); + @override + R? visitExtensionOnClause(ExtensionOnClause node) => _throw(node); + @override R? visitExtensionOverride(ExtensionOverride node) => _throw(node); @@ -3327,6 +3342,14 @@ class TimedAstVisitor implements AstVisitor { return result; } + @override + T? visitExtensionOnClause(ExtensionOnClause node) { + stopwatch.start(); + T? result = _baseVisitor.visitExtensionOnClause(node); + stopwatch.stop(); + return result; + } + @override T? visitExtensionOverride(ExtensionOverride node) { stopwatch.start(); @@ -4465,6 +4488,9 @@ class UnifyingAstVisitor implements AstVisitor { @override R? visitExtensionDeclaration(ExtensionDeclaration node) => visitNode(node); + @override + R? visitExtensionOnClause(ExtensionOnClause node) => visitNode(node); + @override R? visitExtensionOverride(ExtensionOverride node) => visitNode(node); diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart index 2a8413a11517..1e1269b7d7d3 100644 --- a/pkg/analyzer/lib/src/dart/ast/ast.dart +++ b/pkg/analyzer/lib/src/dart/ast/ast.dart @@ -1347,6 +1347,8 @@ abstract class AstVisitor { R? visitExtensionDeclaration(ExtensionDeclaration node); + R? visitExtensionOnClause(ExtensionOnClause node); + R? visitExtensionOverride(ExtensionOverride node); R? visitExtensionTypeDeclaration(ExtensionTypeDeclaration node); @@ -6454,7 +6456,8 @@ abstract final class ExtensionDeclaration implements CompilationUnitMember { @override ExtensionElement? get declaredElement; - /// Return the type that is being extended. + /// The type that is being extended. + @Deprecated('Use onClause instead') TypeAnnotation get extendedType; /// Return the token representing the 'extension' keyword. @@ -6470,7 +6473,11 @@ abstract final class ExtensionDeclaration implements CompilationUnitMember { /// a name. Token? get name; - /// Return the token representing the 'on' keyword. + /// The `on` clause, `null` if an augmentation. + ExtensionOnClause? get onClause; + + /// The token representing the 'on' keyword. + @Deprecated('Use onClause instead') Token get onKeyword; /// Return the right curly bracket. @@ -6508,10 +6515,7 @@ final class ExtensionDeclarationImpl extends CompilationUnitMemberImpl TypeParameterListImpl? _typeParameters; @override - final Token onKeyword; - - /// The type that is being extended. - TypeAnnotationImpl _extendedType; + ExtensionOnClauseImpl? onClause; @override final Token leftBracket; @@ -6533,26 +6537,23 @@ final class ExtensionDeclarationImpl extends CompilationUnitMemberImpl required this.typeKeyword, required this.name, required TypeParameterListImpl? typeParameters, - required this.onKeyword, - required TypeAnnotationImpl extendedType, + required this.onClause, required this.leftBracket, required List members, required this.rightBracket, - }) : _typeParameters = typeParameters, - _extendedType = extendedType { + }) : _typeParameters = typeParameters { _becomeParentOf(_typeParameters); - _becomeParentOf(_extendedType); + _becomeParentOf(onClause); _members._initialize(this, members); } @override Token get endToken => rightBracket; + @Deprecated('Use onClause instead') @override - TypeAnnotationImpl get extendedType => _extendedType; - - set extendedType(TypeAnnotationImpl extendedClass) { - _extendedType = _becomeParentOf(extendedClass); + TypeAnnotationImpl get extendedType { + return onClause!.extendedType; } @override @@ -6562,6 +6563,10 @@ final class ExtensionDeclarationImpl extends CompilationUnitMemberImpl @override NodeListImpl get members => _members; + @Deprecated('Use onClause instead') + @override + Token get onKeyword => onClause!.onKeyword; + @override TypeParameterListImpl? get typeParameters => _typeParameters; @@ -6575,8 +6580,7 @@ final class ExtensionDeclarationImpl extends CompilationUnitMemberImpl ..addToken('extensionKeyword', extensionKeyword) ..addToken('name', name) ..addNode('typeParameters', typeParameters) - ..addToken('onKeyword', onKeyword) - ..addNode('extendedType', extendedType) + ..addNode('onClause', onClause) ..addToken('leftBracket', leftBracket) ..addNodeList('members', members) ..addToken('rightBracket', rightBracket); @@ -6589,11 +6593,59 @@ final class ExtensionDeclarationImpl extends CompilationUnitMemberImpl void visitChildren(AstVisitor visitor) { super.visitChildren(visitor); _typeParameters?.accept(visitor); - _extendedType.accept(visitor); + onClause?.accept(visitor); _members.accept(visitor); } } +/// The `on` clause in an extension declaration. +/// +/// onClause ::= 'on' [TypeAnnotation] +abstract final class ExtensionOnClause implements AstNode { + /// The extended type. + TypeAnnotation get extendedType; + + /// The 'on' keyword. + Token get onKeyword; +} + +final class ExtensionOnClauseImpl extends AstNodeImpl + implements ExtensionOnClause { + @override + final Token onKeyword; + + @override + final TypeAnnotationImpl extendedType; + + ExtensionOnClauseImpl({ + required this.onKeyword, + required this.extendedType, + }) { + _becomeParentOf(extendedType); + } + + @override + Token get beginToken => onKeyword; + + @override + Token get endToken => extendedType.endToken; + + @override + ChildEntities get _childEntities => ChildEntities() + ..addToken('onKeyword', onKeyword) + ..addNode('extendedType', extendedType); + + @override + E? accept(AstVisitor visitor) { + return visitor.visitExtensionOnClause(this); + } + + @override + void visitChildren(AstVisitor visitor) { + extendedType.accept(visitor); + } +} + /// An override to force resolution to choose a member from a specific /// extension. /// diff --git a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart index 851c27291658..bfcfae829af9 100644 --- a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart +++ b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart @@ -436,19 +436,24 @@ class ToSourceVisitor implements AstVisitor { @override void visitExtensionDeclaration(ExtensionDeclaration node) { _visitNodeList(node.metadata, separator: ' ', suffix: ' '); + _visitToken(node.augmentKeyword, suffix: ' '); _visitToken(node.extensionKeyword, suffix: ' '); _visitToken(node.typeKeyword, suffix: ' '); _visitToken(node.name); _visitNode(node.typeParameters); sink.write(' '); - _visitToken(node.onKeyword); - sink.write(' '); - _visitNode(node.extendedType, suffix: ' '); + _visitNode(node.onClause, suffix: ' '); _visitToken(node.leftBracket); _visitNodeList(node.members, separator: ' '); _visitToken(node.rightBracket); } + @override + void visitExtensionOnClause(ExtensionOnClause node) { + sink.write('on '); + _visitNode(node.extendedType); + } + @override void visitExtensionOverride(ExtensionOverride node) { _visitNode(node.importPrefix); diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart index e99f6cb3292a..14d1fff6fa12 100644 --- a/pkg/analyzer/lib/src/dart/ast/utilities.dart +++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart @@ -544,13 +544,19 @@ class AstComparator implements AstVisitor { isEqualTokens(node.extensionKeyword, other.extensionKeyword) && isEqualTokens(node.name, other.name) && isEqualNodes(node.typeParameters, other.typeParameters) && - isEqualTokens(node.onKeyword, other.onKeyword) && - isEqualNodes(node.extendedType, other.extendedType) && + isEqualNodes(node.onClause, other.onClause) && isEqualTokens(node.leftBracket, other.leftBracket) && _isEqualNodeLists(node.members, other.members) && isEqualTokens(node.rightBracket, other.rightBracket); } + @override + bool visitExtensionOnClause(ExtensionOnClause node) { + var other = _other as ExtensionOnClause; + return isEqualTokens(node.onKeyword, other.onKeyword) && + isEqualNodes(node.extendedType, other.extendedType); + } + @override bool visitExtensionOverride(ExtensionOverride node) { ExtensionOverride other = _other as ExtensionOverride; @@ -2499,9 +2505,6 @@ class NodeReplacer extends ThrowingAstVisitor { } else if (identical(node.typeParameters, _oldNode)) { node.typeParameters = _newNode as TypeParameterListImpl; return true; - } else if (identical(node.extendedType, _oldNode)) { - node.extendedType = _newNode as TypeAnnotationImpl; - return true; } else if (_replaceInList(node.members)) { return true; } diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart index b1cba4f3ec5a..2c4dd38fddb9 100644 --- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart +++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart @@ -200,6 +200,7 @@ final fastaAnalyzerErrorCodes = [ ParserErrorCode.ABSTRACT_FINAL_BASE_CLASS, ParserErrorCode.ABSTRACT_FINAL_INTERFACE_CLASS, ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_FIELD_INITIALIZERS, + ParserErrorCode.EXTENSION_AUGMENTATION_HAS_ON_CLAUSE, ]; class ParserErrorCode extends ErrorCode { @@ -761,6 +762,14 @@ class ParserErrorCode extends ErrorCode { "Try moving the export directives before the part directives.", ); + /// No parameters. + static const ParserErrorCode EXTENSION_AUGMENTATION_HAS_ON_CLAUSE = + ParserErrorCode( + 'EXTENSION_AUGMENTATION_HAS_ON_CLAUSE', + "Extension augmentations can't have 'on' clauses.", + correctionMessage: "Try removing the 'on' clause.", + ); + /// No parameters. static const ParserErrorCode EXTENSION_DECLARES_ABSTRACT_MEMBER = ParserErrorCode( diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart index 6b2918812150..7d0561f7b9a5 100644 --- a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart +++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart @@ -577,7 +577,7 @@ class ResolutionVisitor extends RecursiveAstVisitor { _withNameScope(() { _buildTypeParameterElements(node.typeParameters); node.typeParameters?.accept(this); - node.extendedType.accept(this); + node.onClause?.accept(this); _defineElements(element.accessors); _defineElements(element.methods); diff --git a/pkg/analyzer/lib/src/error/error_code_values.g.dart b/pkg/analyzer/lib/src/error/error_code_values.g.dart index f3573989ea2f..359bcc902da4 100644 --- a/pkg/analyzer/lib/src/error/error_code_values.g.dart +++ b/pkg/analyzer/lib/src/error/error_code_values.g.dart @@ -729,6 +729,7 @@ const List errorCodeValues = [ ParserErrorCode.EXPERIMENT_NOT_ENABLED, ParserErrorCode.EXPERIMENT_NOT_ENABLED_OFF_BY_DEFAULT, ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, + ParserErrorCode.EXTENSION_AUGMENTATION_HAS_ON_CLAUSE, ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, ParserErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD, diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart index bd53fb1283d8..65b701ad230d 100644 --- a/pkg/analyzer/lib/src/fasta/ast_builder.dart +++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart @@ -1557,16 +1557,22 @@ class AstBuilder extends StackListener { @override void endExtensionDeclaration( - Token beginToken, Token extensionKeyword, Token onKeyword, Token token) { + Token beginToken, Token extensionKeyword, Token? onKeyword, Token token) { final builder = _classLikeBuilder as _ExtensionDeclarationBuilder; - final type = pop() as TypeAnnotationImpl; + ExtensionOnClauseImpl? onClause; + if (onKeyword != null) { + var extendedType = pop() as TypeAnnotationImpl; + onClause = ExtensionOnClauseImpl( + onKeyword: onKeyword, + extendedType: extendedType, + ); + } declarations.add( builder.build( - extendedType: type, - onKeyword: onKeyword, typeKeyword: null, + onClause: onClause, ), ); @@ -6118,8 +6124,7 @@ class _ExtensionDeclarationBuilder extends _ClassLikeDeclarationBuilder { ExtensionDeclarationImpl build({ required Token? typeKeyword, - required Token onKeyword, - required TypeAnnotationImpl extendedType, + required ExtensionOnClauseImpl? onClause, }) { return ExtensionDeclarationImpl( comment: comment, @@ -6129,8 +6134,7 @@ class _ExtensionDeclarationBuilder extends _ClassLikeDeclarationBuilder { typeKeyword: typeKeyword, name: name, typeParameters: typeParameters, - onKeyword: onKeyword, - extendedType: extendedType, + onClause: onClause, leftBracket: leftBracket, members: members, rightBracket: rightBracket, diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart index 4919becefd54..872d92e09aee 100644 --- a/pkg/analyzer/lib/src/generated/resolver.dart +++ b/pkg/analyzer/lib/src/generated/resolver.dart @@ -2351,6 +2351,12 @@ class ResolverVisitor extends ThrowingAstVisitor } } + @override + void visitExtensionOnClause(ExtensionOnClause node) { + checkUnreachableNode(node); + node.visitChildren(this); + } + @override void visitExtensionOverride(covariant ExtensionOverrideImpl node) { var whyNotPromotedList = Function()>[]; @@ -4296,7 +4302,7 @@ class ScopeResolverVisitor extends UnifyingAstVisitor { void visitExtensionDeclarationInScope(ExtensionDeclaration node) { node.typeParameters?.accept(this); - node.extendedType.accept(this); + node.onClause?.accept(this); } void visitExtensionMembersInScope(ExtensionDeclaration node) { diff --git a/pkg/analyzer/lib/src/lint/linter_visitor.dart b/pkg/analyzer/lib/src/lint/linter_visitor.dart index 78674bd89da3..255f3baf6f0e 100644 --- a/pkg/analyzer/lib/src/lint/linter_visitor.dart +++ b/pkg/analyzer/lib/src/lint/linter_visitor.dart @@ -323,6 +323,12 @@ class LinterVisitor implements AstVisitor { node.visitChildren(this); } + @override + void visitExtensionOnClause(ExtensionOnClause node) { + _runSubscriptions(node, registry._forExtensionOnClause); + node.visitChildren(this); + } + @override void visitExtensionOverride(ExtensionOverride node) { _runSubscriptions(node, registry._forExtensionOverride); @@ -1132,6 +1138,7 @@ class NodeLintRegistry { final List<_Subscription> _forExtensionDeclaration = []; final List<_Subscription> _forExtensionTypeDeclaration = []; + final List<_Subscription> _forExtensionOnClause = []; final List<_Subscription> _forExtensionOverride = []; final List<_Subscription> _forObjectPattern = []; final List<_Subscription> _forFieldDeclaration = []; @@ -1503,6 +1510,11 @@ class NodeLintRegistry { .add(_Subscription(linter, visitor, _getTimer(linter))); } + void addExtensionOnClause(LintRule linter, AstVisitor visitor) { + _forExtensionOnClause + .add(_Subscription(linter, visitor, _getTimer(linter))); + } + void addExtensionOverride(LintRule linter, AstVisitor visitor) { _forExtensionOverride .add(_Subscription(linter, visitor, _getTimer(linter))); diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart index 25c16134046c..ff9c64ffb91a 100644 --- a/pkg/analyzer/lib/src/summary2/element_builder.dart +++ b/pkg/analyzer/lib/src/summary2/element_builder.dart @@ -474,6 +474,11 @@ class ElementBuilder extends ThrowingAstVisitor { element.methods = holder.methods; } + node.onClause?.accept(this); + } + + @override + void visitExtensionOnClause(ExtensionOnClause node) { node.extendedType.accept(this); } diff --git a/pkg/analyzer/lib/src/summary2/macro_declarations.dart b/pkg/analyzer/lib/src/summary2/macro_declarations.dart index 9e966c0a7ffe..d1a2f640de62 100644 --- a/pkg/analyzer/lib/src/summary2/macro_declarations.dart +++ b/pkg/analyzer/lib/src/summary2/macro_declarations.dart @@ -1326,6 +1326,10 @@ class DeclarationBuilderFromNode { ) { final element = node.declaredElement!; + final declarationElement = element.augmented!.declaration; + final declarationNode = builder.nodeOfElement(declarationElement) + as ast.ExtensionDeclarationImpl; + return ExtensionDeclarationImpl._( id: macro.RemoteInstance.uniqueId, identifier: _declaredIdentifier2(node.name?.lexeme ?? '', element), @@ -1333,7 +1337,7 @@ class DeclarationBuilderFromNode { metadata: _buildMetadata(element), typeParameters: _typeParameterDeclarations(node.typeParameters), onType: _typeAnnotation( - node.extendedType, + declarationNode.onClause!.extendedType, ExtensionElementOnTypeLocation(element), ), element: element, diff --git a/pkg/analyzer/lib/src/summary2/reference_resolver.dart b/pkg/analyzer/lib/src/summary2/reference_resolver.dart index d0edaa0ed84d..2a0e32b88635 100644 --- a/pkg/analyzer/lib/src/summary2/reference_resolver.dart +++ b/pkg/analyzer/lib/src/summary2/reference_resolver.dart @@ -147,7 +147,7 @@ class ReferenceResolver extends ThrowingAstVisitor { scope = TypeParameterScope(scope, element.typeParameters); node.typeParameters?.accept(this); - node.extendedType.accept(this); + node.onClause?.accept(this); scope = ExtensionScope(scope, element); LinkingNodeContext(node, scope); @@ -158,6 +158,11 @@ class ReferenceResolver extends ThrowingAstVisitor { scope = outerScope; } + @override + void visitExtensionOnClause(ExtensionOnClause node) { + node.extendedType.accept(this); + } + @override void visitExtensionTypeDeclaration(ExtensionTypeDeclaration node) { var outerScope = scope; diff --git a/pkg/analyzer/lib/src/summary2/types_builder.dart b/pkg/analyzer/lib/src/summary2/types_builder.dart index 1497a4019715..6175f0449752 100644 --- a/pkg/analyzer/lib/src/summary2/types_builder.dart +++ b/pkg/analyzer/lib/src/summary2/types_builder.dart @@ -271,7 +271,11 @@ class TypesBuilder { void _extensionDeclaration(ExtensionDeclaration node) { var element = node.declaredElement as ExtensionElementImpl; - element.extendedType = node.extendedType.typeOrThrow; + if (node.onClause case var onClause?) { + element.extendedType = onClause.extendedType.typeOrThrow; + } else { + element.extendedType = InvalidTypeImpl.instance; + } } void _extensionTypeDeclaration(ExtensionTypeDeclarationImpl node) {} diff --git a/pkg/analyzer/test/generated/extension_methods_parser_test.dart b/pkg/analyzer/test/generated/extension_methods_parser_test.dart index b266eea7c120..be852fcb25cb 100644 --- a/pkg/analyzer/test/generated/extension_methods_parser_test.dart +++ b/pkg/analyzer/test/generated/extension_methods_parser_test.dart @@ -30,8 +30,8 @@ class ExtensionMethodsParserTest extends FastaParserTestCase { expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name!.lexeme, 'E'); - expect(extension.onKeyword.lexeme, 'extends'); - expect((extension.extendedType as NamedType).name2.lexeme, 'A'); + expect(extension.onClause!.onKeyword.lexeme, 'extends'); + expect((extension.onClause!.extendedType as NamedType).name2.lexeme, 'A'); expect(extension.members, hasLength(0)); } @@ -43,8 +43,8 @@ class ExtensionMethodsParserTest extends FastaParserTestCase { expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name!.lexeme, 'E'); - expect(extension.onKeyword.lexeme, 'implements'); - expect((extension.extendedType as NamedType).name2.lexeme, 'C'); + expect(extension.onClause!.onKeyword.lexeme, 'implements'); + expect((extension.onClause!.extendedType as NamedType).name2.lexeme, 'C'); expect(extension.members, hasLength(0)); } @@ -53,8 +53,8 @@ class ExtensionMethodsParserTest extends FastaParserTestCase { expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name!.lexeme, 'E'); - expect(extension.onKeyword.lexeme, 'on'); - var namedType = extension.extendedType as NamedType; + expect(extension.onClause!.onKeyword.lexeme, 'on'); + var namedType = extension.onClause!.extendedType as NamedType; expect(namedType.name2.lexeme, 'C'); expect(namedType.typeArguments!.arguments, hasLength(1)); expect(extension.members, hasLength(0)); @@ -65,8 +65,8 @@ class ExtensionMethodsParserTest extends FastaParserTestCase { expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name!.lexeme, 'E'); - expect(extension.onKeyword.lexeme, 'on'); - var namedType = extension.extendedType as NamedType; + expect(extension.onClause!.onKeyword.lexeme, 'on'); + var namedType = extension.onClause!.extendedType as NamedType; expect(namedType.name2.lexeme, 'C'); expect(namedType.typeArguments!.arguments, hasLength(1)); expect(extension.members, hasLength(0)); @@ -77,8 +77,8 @@ class ExtensionMethodsParserTest extends FastaParserTestCase { expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name, isNull); - expect(extension.onKeyword.lexeme, 'on'); - var namedType = extension.extendedType as NamedType; + expect(extension.onClause!.onKeyword.lexeme, 'on'); + var namedType = extension.onClause!.extendedType as NamedType; expect(namedType.name2.lexeme, 'C'); expect(namedType.typeArguments!.arguments, hasLength(1)); expect(extension.members, hasLength(0)); @@ -121,8 +121,8 @@ class C {} expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name!.lexeme, 'E'); - expect(extension.onKeyword.lexeme, 'on'); - expect((extension.extendedType as NamedType).name2.lexeme, ''); + expect(extension.onClause!.onKeyword.lexeme, 'on'); + expect((extension.onClause!.extendedType as NamedType).name2.lexeme, ''); expect(extension.members, hasLength(0)); } @@ -134,8 +134,8 @@ class C {} expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name!.lexeme, 'E'); - expect(extension.onKeyword.lexeme, 'on'); - expect((extension.extendedType as NamedType).name2.lexeme, ''); + expect(extension.onClause!.onKeyword.lexeme, 'on'); + expect((extension.onClause!.extendedType as NamedType).name2.lexeme, ''); expect(extension.members, hasLength(0)); } @@ -146,8 +146,8 @@ class C {} expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name!.lexeme, 'E'); - expect(extension.onKeyword.lexeme, 'on'); - expect((extension.extendedType as NamedType).name2.lexeme, 'C'); + expect(extension.onClause!.onKeyword.lexeme, 'on'); + expect((extension.onClause!.extendedType as NamedType).name2.lexeme, 'C'); expect(extension.members, hasLength(0)); } @@ -174,9 +174,9 @@ class C {} expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name!.lexeme, 'E'); - expect(extension.onKeyword.lexeme, 'on'); - expect((extension.extendedType as NamedType).name2.lexeme, 'C'); - var namedType = extension.extendedType as NamedType; + expect(extension.onClause!.onKeyword.lexeme, 'on'); + expect((extension.onClause!.extendedType as NamedType).name2.lexeme, 'C'); + var namedType = extension.onClause!.extendedType as NamedType; expect(namedType.name2.lexeme, 'C'); expect(namedType.typeArguments, isNull); expect(extension.members, hasLength(0)); @@ -189,8 +189,8 @@ class C {} expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name!.lexeme, 'E'); - expect(extension.onKeyword.lexeme, 'extends'); - expect((extension.extendedType as NamedType).name2.lexeme, 'C'); + expect(extension.onClause!.onKeyword.lexeme, 'extends'); + expect((extension.onClause!.extendedType as NamedType).name2.lexeme, 'C'); expect(extension.members, hasLength(0)); } @@ -201,8 +201,8 @@ class C {} expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name!.lexeme, 'E'); - expect(extension.onKeyword.lexeme, 'implements'); - expect((extension.extendedType as NamedType).name2.lexeme, 'C'); + expect(extension.onClause!.onKeyword.lexeme, 'implements'); + expect((extension.onClause!.extendedType as NamedType).name2.lexeme, 'C'); expect(extension.members, hasLength(0)); } @@ -211,9 +211,9 @@ class C {} expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name, isNull); - expect(extension.onKeyword.lexeme, 'on'); - expect((extension.extendedType as NamedType).name2.lexeme, 'C'); - var namedType = extension.extendedType as NamedType; + expect(extension.onClause!.onKeyword.lexeme, 'on'); + expect((extension.onClause!.extendedType as NamedType).name2.lexeme, 'C'); + var namedType = extension.onClause!.extendedType as NamedType; expect(namedType.name2.lexeme, 'C'); expect(namedType.typeArguments, isNull); expect(extension.members, hasLength(0)); @@ -237,8 +237,8 @@ class C {} expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name!.lexeme, 'E'); - expect(extension.onKeyword.lexeme, 'with'); - expect((extension.extendedType as NamedType).name2.lexeme, 'C'); + expect(extension.onClause!.onKeyword.lexeme, 'with'); + expect((extension.onClause!.extendedType as NamedType).name2.lexeme, 'C'); expect(extension.members, hasLength(0)); } @@ -247,8 +247,9 @@ class C {} expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name!.lexeme, 'E'); - expect(extension.onKeyword.lexeme, 'on'); - expect((extension.extendedType as NamedType).name2.lexeme, 'void'); + expect(extension.onClause!.onKeyword.lexeme, 'on'); + expect( + (extension.onClause!.extendedType as NamedType).name2.lexeme, 'void'); expect(extension.members, hasLength(0)); } } diff --git a/pkg/analyzer/test/generated/parser_fasta_listener.dart b/pkg/analyzer/test/generated/parser_fasta_listener.dart index 14791c5a752f..8e0eddef1aa1 100644 --- a/pkg/analyzer/test/generated/parser_fasta_listener.dart +++ b/pkg/analyzer/test/generated/parser_fasta_listener.dart @@ -848,7 +848,7 @@ class ForwardingTestListener extends ForwardingListener { @override void endExtensionDeclaration( - Token beginToken, Token extensionKeyword, Token onKeyword, Token token) { + Token beginToken, Token extensionKeyword, Token? onKeyword, Token token) { super.endExtensionDeclaration( beginToken, extensionKeyword, onKeyword, token); end('ExtensionDeclaration'); diff --git a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart index a87b7bf9c540..1c94d191a9de 100644 --- a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart +++ b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart @@ -1213,6 +1213,14 @@ class C $code {} _assertSource(code, findNode.extendsClause(code)); } + void test_visitExtensionDeclaration_augment() { + final code = 'augment extension E {}'; + final findNode = _parseStringToFindNode(''' +$code +'''); + _assertSource(code, findNode.extensionDeclaration(code)); + } + void test_visitExtensionDeclaration_empty() { final code = 'extension E on C {}'; final findNode = _parseStringToFindNode(''' diff --git a/pkg/analyzer/test/src/dart/parser/extension_test.dart b/pkg/analyzer/test/src/dart/parser/extension_test.dart index 0db4a4376cab..ccd4b5469f19 100644 --- a/pkg/analyzer/test/src/dart/parser/extension_test.dart +++ b/pkg/analyzer/test/src/dart/parser/extension_test.dart @@ -2,6 +2,7 @@ // 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. +import 'package:analyzer/src/dart/error/syntactic_errors.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; import '../../diagnostics/parser_diagnostics.dart'; @@ -14,11 +15,11 @@ main() { @reflectiveTest class ExtensionDeclarationParserTest extends ParserDiagnosticsTest { - test_augment_named() { + test_augment() { final parseResult = parseStringWithErrors(r''' library augment 'a.dart'; -augment extension E on int {} +augment extension E {} '''); parseResult.assertNoErrors(); @@ -28,19 +29,16 @@ ExtensionDeclaration augmentKeyword: augment extensionKeyword: extension name: E - onKeyword: on - extendedType: NamedType - name: int leftBracket: { rightBracket: } '''); } - test_augment_named_generic() { + test_augment_generic() { final parseResult = parseStringWithErrors(r''' library augment 'a.dart'; -augment extension E on int {} +augment extension E {} '''); parseResult.assertNoErrors(); @@ -56,57 +54,31 @@ ExtensionDeclaration TypeParameter name: T rightBracket: > - onKeyword: on - extendedType: NamedType - name: int - leftBracket: { - rightBracket: } -'''); - } - - test_augment_unnamed() { - final parseResult = parseStringWithErrors(r''' -library augment 'a.dart'; - -augment extension on int {} -'''); - parseResult.assertNoErrors(); - - final node = parseResult.findNode.singleExtensionDeclaration; - assertParsedNodeText(node, r''' -ExtensionDeclaration - augmentKeyword: augment - extensionKeyword: extension - onKeyword: on - extendedType: NamedType - name: int leftBracket: { rightBracket: } '''); } - test_augment_unnamed_generic() { + test_augment_hasOnClause() { final parseResult = parseStringWithErrors(r''' library augment 'a.dart'; -augment extension on int {} +augment extension E on int {} '''); - parseResult.assertNoErrors(); + parseResult.assertErrors([ + error(ParserErrorCode.EXTENSION_AUGMENTATION_HAS_ON_CLAUSE, 47, 2), + ]); final node = parseResult.findNode.singleExtensionDeclaration; assertParsedNodeText(node, r''' ExtensionDeclaration augmentKeyword: augment extensionKeyword: extension - typeParameters: TypeParameterList - leftBracket: < - typeParameters - TypeParameter - name: T - rightBracket: > - onKeyword: on - extendedType: NamedType - name: int + name: E + onClause: ExtensionOnClause + onKeyword: on + extendedType: NamedType + name: int leftBracket: { rightBracket: } '''); diff --git a/pkg/analyzer/test/src/fasta/ast_builder_test.dart b/pkg/analyzer/test/src/fasta/ast_builder_test.dart index 8e639e1939a4..cc34815f9bd4 100644 --- a/pkg/analyzer/test/src/fasta/ast_builder_test.dart +++ b/pkg/analyzer/test/src/fasta/ast_builder_test.dart @@ -1264,17 +1264,18 @@ extension E on (int, int) {} ExtensionDeclaration extensionKeyword: extension @0 name: E @10 - onKeyword: on @12 - extendedType: RecordTypeAnnotation - leftParenthesis: ( @15 - positionalFields - RecordTypeAnnotationPositionalField - type: NamedType - name: int @16 - RecordTypeAnnotationPositionalField - type: NamedType - name: int @21 - rightParenthesis: ) @24 + onClause: ExtensionOnClause + onKeyword: on @12 + extendedType: RecordTypeAnnotation + leftParenthesis: ( @15 + positionalFields + RecordTypeAnnotationPositionalField + type: NamedType + name: int @16 + RecordTypeAnnotationPositionalField + type: NamedType + name: int @21 + rightParenthesis: ) @24 leftBracket: { @26 rightBracket: } @27 ''', diff --git a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart index 4c8e5d0259ec..d9a3040a9886 100644 --- a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart +++ b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart @@ -552,6 +552,14 @@ class ResolvedAstPrinter extends ThrowingAstVisitor { }); } + @override + void visitExtensionOnClause(ExtensionOnClause node) { + _sink.writeln('ExtensionOnClause'); + _sink.withIndent(() { + _writeNamedChildEntities(node); + }); + } + @override void visitExtensionOverride(ExtensionOverride node) { _sink.writeln('ExtensionOverride'); diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart index f2f5437dd32f..e7184fcf8ca8 100644 --- a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart +++ b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart @@ -697,8 +697,8 @@ class _OpTypeAstVisitor extends GeneralizingAstVisitor { @override void visitExtensionDeclaration(ExtensionDeclaration node) { - if (identical(entity, node.extendedType)) { - optype.completionLocation = 'ExtensionDeclaration_extendedType'; + if (identical(entity, node.onClause)) { + optype.completionLocation = 'ExtensionDeclaration_onClause'; optype.includeTypeNameSuggestions = true; } else if (node.members.contains(entity) || identical(entity, node.rightBracket)) { @@ -708,6 +708,12 @@ class _OpTypeAstVisitor extends GeneralizingAstVisitor { } } + @override + void visitExtensionOnClause(ExtensionOnClause node) { + optype.completionLocation = 'ExtensionOnClause_extendedType'; + optype.includeTypeNameSuggestions = true; + } + @override void visitExtensionTypeDeclaration(ExtensionTypeDeclaration node) { // Make suggestions in the body of the extension type declaration diff --git a/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart b/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart index d78feaec4928..e14bfc5f307c 100644 --- a/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart +++ b/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart @@ -1144,12 +1144,11 @@ void g(void Function() f) {} completionLocation: 'ExtensionDeclaration_member', typeNames: true); } - Future test_extensionDeclaration_extendedType() async { + Future test_extensionOnClause_extendedType() async { // SimpleIdentifier MethodDeclaration ExtensionDeclaration addTestSource('extension E on ^ {}'); await assertOpType( - completionLocation: 'ExtensionDeclaration_extendedType', - typeNames: true); + completionLocation: 'ExtensionOnClause_extendedType', typeNames: true); } Future test_extensionOverride_argumentList() async { diff --git a/pkg/front_end/lib/src/fasta/kernel/macro/annotation_parser.dart b/pkg/front_end/lib/src/fasta/kernel/macro/annotation_parser.dart index 76d37e24cea3..93201fde4fe6 100644 --- a/pkg/front_end/lib/src/fasta/kernel/macro/annotation_parser.dart +++ b/pkg/front_end/lib/src/fasta/kernel/macro/annotation_parser.dart @@ -1232,7 +1232,7 @@ class _MacroListener implements Listener { @override void endExtensionDeclaration(Token beginToken, Token extensionKeyword, - Token onKeyword, Token endToken) { + Token? onKeyword, Token endToken) { _unexpected(); } diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart index 1619f6f73d0d..8a0594866e6a 100644 --- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart +++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart @@ -1013,7 +1013,7 @@ class DietListener extends StackListenerImpl { @override void endExtensionDeclaration(Token beginToken, Token extensionKeyword, - Token onKeyword, Token endToken) { + Token? onKeyword, Token endToken) { debugEvent("endExtensionDeclaration"); checkEmpty(extensionKeyword.charOffset); } diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart index 1619ff025160..14c1bbabeb3d 100644 --- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart @@ -1512,7 +1512,7 @@ class OutlineBuilder extends StackListenerImpl { @override void endExtensionDeclaration(Token beginToken, Token extensionKeyword, - Token onKeyword, Token endToken) { + Token? onKeyword, Token endToken) { assert(checkState(extensionKeyword, [ unionOfKinds([ValueKinds.ParserRecovery, ValueKinds.TypeBuilder]), ValueKinds.NominalVariableListOrNull, diff --git a/pkg/front_end/lib/src/fasta/util/parser_ast_helper.dart b/pkg/front_end/lib/src/fasta/util/parser_ast_helper.dart index 45c8db6d0881..084bcc860ba9 100644 --- a/pkg/front_end/lib/src/fasta/util/parser_ast_helper.dart +++ b/pkg/front_end/lib/src/fasta/util/parser_ast_helper.dart @@ -305,7 +305,7 @@ abstract class AbstractParserAstListener implements Listener { @override void endExtensionDeclaration(Token beginToken, Token extensionKeyword, - Token onKeyword, Token endToken) { + Token? onKeyword, Token endToken) { ExtensionDeclarationEnd data = new ExtensionDeclarationEnd( ParserAstType.END, beginToken: beginToken, @@ -3590,13 +3590,13 @@ class ExtensionDeclarationBegin extends ParserAstNode { class ExtensionDeclarationEnd extends ParserAstNode { final Token beginToken; final Token extensionKeyword; - final Token onKeyword; + final Token? onKeyword; final Token endToken; ExtensionDeclarationEnd(ParserAstType type, {required this.beginToken, required this.extensionKeyword, - required this.onKeyword, + this.onKeyword, required this.endToken}) : super("ExtensionDeclaration", type); diff --git a/pkg/front_end/lib/src/fasta/util/textual_outline.dart b/pkg/front_end/lib/src/fasta/util/textual_outline.dart index 76cef82a2767..dfe7884383ca 100644 --- a/pkg/front_end/lib/src/fasta/util/textual_outline.dart +++ b/pkg/front_end/lib/src/fasta/util/textual_outline.dart @@ -810,7 +810,7 @@ class TextualOutlineListener extends Listener { @override void endExtensionDeclaration(Token beginToken, Token extensionKeyword, - Token onKeyword, Token endToken) { + Token? onKeyword, Token endToken) { classStartToChunk[beginToken] = new _ExtensionDeclarationChunk(beginToken, endToken); } diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status index 4cb0eccf3bae..f1cfa2ffa130 100644 --- a/pkg/front_end/messages.status +++ b/pkg/front_end/messages.status @@ -321,6 +321,8 @@ ExtendsVoid/analyzerCode: Fail # Feature not yet in analyzer. ExtendsVoid/example: Fail # Feature not yet enabled by default. ExtensionInNullAwareReceiver/analyzerCode: Fail ExtensionMemberConflictsWithObjectMember/analyzerCode: Fail +ExtensionAugmentationHasOnClause/part_wrapped_script: Fail +ExtensionAugmentationHasOnClause/script: Fail ExtensionTypeImplementsDeferred/part_wrapped_script: Fail # Uses imports ExtensionTypeImplementsDeferred/script: Fail # Uses imports ExtensionTypePrimaryConstructorFunctionFormalParameterSyntax/analyzerCode: Fail diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml index 98df5912b784..252cc885c994 100644 --- a/pkg/front_end/messages.yaml +++ b/pkg/front_end/messages.yaml @@ -2807,6 +2807,15 @@ ExtensionDeclaresInstanceField: setter, or method. hasPublishedDocs: true +ExtensionAugmentationHasOnClause: + index: 179 + problemMessage: "Extension augmentations can't have 'on' clauses." + correctionMessage: "Try removing the 'on' clause." + analyzerCode: ParserErrorCode.EXTENSION_AUGMENTATION_HAS_ON_CLAUSE + script: | + augment extension E on int {} + comment: No parameters. + ExtensionTypeDeclaresInstanceField: problemMessage: "Extension types can't declare instance fields" correctionMessage: "Try removing the field declaration or making it a static field" diff --git a/pkg/front_end/test/parser_test_listener.dart b/pkg/front_end/test/parser_test_listener.dart index e6367cc2e357..05ecfaf73bc0 100644 --- a/pkg/front_end/test/parser_test_listener.dart +++ b/pkg/front_end/test/parser_test_listener.dart @@ -351,7 +351,7 @@ class ParserTestListener implements Listener { @override void endExtensionDeclaration(Token beginToken, Token extensionKeyword, - Token onKeyword, Token endToken) { + Token? onKeyword, Token endToken) { indent--; seen(beginToken); seen(extensionKeyword); diff --git a/pkg/linter/lib/src/rules/collection_methods_unrelated_type.dart b/pkg/linter/lib/src/rules/collection_methods_unrelated_type.dart index 42778edd1ef1..9f47d7d73687 100644 --- a/pkg/linter/lib/src/rules/collection_methods_unrelated_type.dart +++ b/pkg/linter/lib/src/rules/collection_methods_unrelated_type.dart @@ -344,7 +344,7 @@ class _Visitor extends SimpleAstVisitor { } else if (parent is EnumDeclaration) { return parent.declaredElement?.thisType; } else if (parent is ExtensionDeclaration) { - return parent.extendedType.type; + return parent.onClause?.extendedType.type; } } return null; diff --git a/pkg/linter/lib/src/rules/library_private_types_in_public_api.dart b/pkg/linter/lib/src/rules/library_private_types_in_public_api.dart index 26043d78e223..c2cd2faf8838 100644 --- a/pkg/linter/lib/src/rules/library_private_types_in_public_api.dart +++ b/pkg/linter/lib/src/rules/library_private_types_in_public_api.dart @@ -127,8 +127,8 @@ class Validator extends SimpleAstVisitor { if (name == null || Identifier.isPrivateName(name.lexeme)) { return; } - node.extendedType.accept(this); node.typeParameters?.accept(this); + node.onClause?.extendedType.accept(this); node.members.accept(this); } diff --git a/pkg/linter/lib/src/rules/prefer_void_to_null.dart b/pkg/linter/lib/src/rules/prefer_void_to_null.dart index 3e33ff07bd23..fb6e78cc7c4e 100644 --- a/pkg/linter/lib/src/rules/prefer_void_to_null.dart +++ b/pkg/linter/lib/src/rules/prefer_void_to_null.dart @@ -138,7 +138,7 @@ class _Visitor extends SimpleAstVisitor { } // extension _ on Null {} - if (parent is ExtensionDeclaration) { + if (parent is ExtensionOnClause) { return; } diff --git a/pkg/linter/lib/src/rules/test_types_in_equals.dart b/pkg/linter/lib/src/rules/test_types_in_equals.dart index 1d2c43db6779..0dd7dd22a5a6 100644 --- a/pkg/linter/lib/src/rules/test_types_in_equals.dart +++ b/pkg/linter/lib/src/rules/test_types_in_equals.dart @@ -120,7 +120,9 @@ class _Visitor extends SimpleAstVisitor { } else if (parent is MixinDeclaration) { return parent.name.lexeme; } else if (parent is ExtensionDeclaration) { - return parent.extendedType.toSource(); + if (parent.onClause case var onClause?) { + return onClause.extendedType.toSource(); + } } return 'unknown'; } diff --git a/pkg/linter/test/rules/prefer_void_to_null_test.dart b/pkg/linter/test/rules/prefer_void_to_null_test.dart index b6a7976c9d1f..885f43ef3859 100644 --- a/pkg/linter/test/rules/prefer_void_to_null_test.dart +++ b/pkg/linter/test/rules/prefer_void_to_null_test.dart @@ -142,6 +142,12 @@ void f(int a) { ]); } + test_extension() async { + await assertNoDiagnostics(r''' +extension _ on Null {} +'''); + } + /// https://github.com/dart-lang/linter/issues/4759 test_extensionTypeRepresentation() async { await assertNoDiagnostics(r''' diff --git a/pkg/linter/test_data/rules/prefer_void_to_null.dart b/pkg/linter/test_data/rules/prefer_void_to_null.dart index 9ec9392ef0ba..6c2d59adb325 100644 --- a/pkg/linter/test_data/rules/prefer_void_to_null.dart +++ b/pkg/linter/test_data/rules/prefer_void_to_null.dart @@ -167,6 +167,3 @@ class AsMembers { class MemberNamedNull { final Null = null; // OK } - -extension _ on Null { // OK -} From add2f411e68319be2c0abc7ac0bd93b5cd2836fc Mon Sep 17 00:00:00 2001 From: Nicholas Shahan Date: Tue, 2 Apr 2024 17:03:12 +0000 Subject: [PATCH 6/6] [web] Add static js interop `.call()` tests These tests should help: - avoid regressions in the existing behavior - highlight incremental improvements towards implementing the desired behavior (with corresponding changes to the expectations) - identify the differences between the JavaScript and wasm compilers Change-Id: Ie95233868a13b7ffffc2688ab7c973dcd14ed721 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/359246 Reviewed-by: Srujan Gaddam Reviewed-by: Sigmund Cherem Commit-Queue: Nicholas Shahan Reviewed-by: Bob Nystrom --- .../static_interop_test/call_getter_test.dart | 217 ++++++++++++++++++ .../static_interop_test/call_method_test.dart | 190 +++++++++++++++ .../js/static_interop_test/call_utils.dart | 57 +++++ tests/lib/lib.status | 2 + 4 files changed, 466 insertions(+) create mode 100644 tests/lib/js/static_interop_test/call_getter_test.dart create mode 100644 tests/lib/js/static_interop_test/call_method_test.dart create mode 100644 tests/lib/js/static_interop_test/call_utils.dart diff --git a/tests/lib/js/static_interop_test/call_getter_test.dart b/tests/lib/js/static_interop_test/call_getter_test.dart new file mode 100644 index 000000000000..b908cf4ad58a --- /dev/null +++ b/tests/lib/js/static_interop_test/call_getter_test.dart @@ -0,0 +1,217 @@ +// 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. + +/// WARNING +/// +/// Not all of the expectations in this test match the language specification. +/// +/// This is part of a set of tests covering "callable objects". Please consider +/// them all together when making changes: +/// +/// ``` +/// tests/lib/js/static_interop_test/call_getter_test.dart +/// tests/lib/js/static_interop_test/call_method_test.dart +/// ``` +/// +/// This test was created with expectations that match the current behavior to +/// make it more clear when something changes and when the results in the web +/// compilers differ. +/// +/// If your change causes an expectation to fail you should decide if the +/// new result is desireable and update the expectation accordingly. + +import 'dart:js_interop'; + +import 'package:expect/expect.dart'; + +import 'call_utils.dart'; + +@JS('jsFunction') +external JSFunction get jsFunctionAsJSFunction; + +@JS('jsObject') +external JSFunction get jsObjectAsJSFunction; + +@JS('jsClass') +external JSFunction get jsClassAsJSFunction; + +extension on JSFunction { + @JS('call') + external String _call(JSAny? self, String s); + + String Function(String) get call => (String s) => _call(globalContext, s); +} + +extension type ExtOnJSObject._(JSObject _) { + @JS('call') + external String _call(String s); + + String Function(String) get call => (String s) => _call(s); +} + +@JS('jsFunction') +external ExtOnJSObject get jsFunctionAsExtOnJSObject; + +@JS('jsObject') +external ExtOnJSObject get jsObjectAsExtOnJSObject; + +@JS('jsClass') +external ExtOnJSObject get jsClassAsExtOnJSObject; + +extension type ExtOnJSObject2._(JSObject _) { + external JSFunction get call; +} + +@JS('jsFunction') +external ExtOnJSObject2 get jsFunctionAsExtOnJSObject2; + +@JS('jsObject') +external ExtOnJSObject2 get jsObjectAsExtOnJSObject2; + +@JS('jsClass') +external ExtOnJSObject2 get jsClassAsExtOnJSObject2; + +extension type ExtOnJSFunction._(JSFunction _) { + external JSFunction get call; +} + +@JS('jsFunction') +external ExtOnJSFunction get jsFunctionAsExtOnJSFunction; + +@JS('jsObject') +external ExtOnJSFunction get jsObjectAsExtOnJSFunction; + +@JS('jsClass') +external ExtOnJSFunction get jsClassAsExtOnJSFunction; + +void main() { + injectJS(); + testJSFunction(); + testExtOnJSObject(); + testExtOnJSObject2(); + testExtOnJSFunction(); + testAsDynamic(); +} + +void testJSFunction() { + var obj = jsFunctionAsJSFunction; + Expect.equals('C', + (obj.callAsFunction(globalContext, 'Cello'.toJS) as JSString).toDart); + Expect.equals('C', obj.call('Cello')); + Expect.equals('C', (obj.call)('Cello')); + + if (dart2wasm) { + obj = jsObjectAsJSFunction; + Expect.throws(() => obj.callAsFunction(globalContext, 'Cello'.toJS)); + Expect.throws(() => obj.call('Cello')); + Expect.throws(() => (obj.call)('Cello')); + } else { + Expect.throwsTypeError(() => jsObjectAsJSFunction); + } + + if (dart2wasm) { + obj = jsClassAsJSFunction; + Expect.throws(() => obj.callAsFunction(globalContext, 'Cello'.toJS)); + Expect.throws(() => obj.call('Cello')); + Expect.throws(() => (obj.call)('Cello')); + } else { + Expect.throwsTypeError(() => jsClassAsJSFunction); + } +} + +void testExtOnJSObject() { + var obj = jsFunctionAsExtOnJSObject; + Expect.throws( + () => obj.call('Cello'), dart2wasm ? null : jsArgIsNotStringCheck); + Expect.throws( + () => (obj.call)('Cello'), dart2wasm ? null : jsArgIsNotStringCheck); + + obj = jsObjectAsExtOnJSObject; + Expect.equals('C', obj.call('Cello')); + Expect.equals('C', (obj.call)('Cello')); + + obj = jsClassAsExtOnJSObject; + Expect.equals('C', obj.call('Cello')); + Expect.equals('C', (obj.call)('Cello')); +} + +void testExtOnJSObject2() { + var obj = jsFunctionAsExtOnJSObject2; + Expect.throws(() => + obj.call.callAsFunction(globalContext, globalContext, 'Cello'.toJS)); + + obj = jsObjectAsExtOnJSObject2; + Expect.equals( + 'C', + (obj.call.callAsFunction(globalContext, 'Cello'.toJS) as JSString) + .toDart); + + obj = jsClassAsExtOnJSObject2; + Expect.equals( + 'C', + (obj.call.callAsFunction(globalContext, 'Cello'.toJS) as JSString) + .toDart); +} + +void testExtOnJSFunction() { + var obj = jsFunctionAsExtOnJSFunction; + Expect.throws(() => obj.call.callAsFunction(globalContext, 'Cello'.toJS)); + + if (dart2wasm) { + obj = jsObjectAsExtOnJSFunction; + Expect.equals( + 'C', + (obj.call.callAsFunction(globalContext, 'Cello'.toJS) as JSString) + .toDart); + } else { + Expect.throwsTypeError(() => jsObjectAsExtOnJSFunction); + } + + if (dart2wasm) { + obj = jsClassAsExtOnJSFunction; + Expect.equals( + 'C', + (obj.call.callAsFunction(globalContext, 'Cello'.toJS) as JSString) + .toDart); + } else { + Expect.throwsTypeError(() => jsClassAsExtOnJSFunction); + } +} + +testAsDynamic() { + dynamic d = confuse(jsFunctionAsJSFunction); + if (dart2wasm) { + Expect.throwsNoSuchMethodError(() => d.call('Fosse')); + } else { + Expect.equals('F', d.call('Fosse')); + } + if (ddc) { + Expect.equals('F', (d.call)('Fosse')); + } else { + Expect.throwsNoSuchMethodError(() => (d.call)('Fosse')); + } + if (dart2wasm) { + Expect.throwsNoSuchMethodError(() => d('Fosse')); + } else { + Expect.equals('F', d('Fosse')); + } + + d = confuse(jsObjectAsExtOnJSObject); + Expect.throwsNoSuchMethodError(() => d.call('Fosse')); + if (ddc) { + Expect.equals('F', (d.call)('Fosse')); + } else { + Expect.throwsNoSuchMethodError(() => (d.call)('Fosse')); + } + Expect.throwsNoSuchMethodError(() => d('Fosse')); + + d = confuse(jsClassAsExtOnJSObject); + Expect.throwsNoSuchMethodError(() => d.call('Fosse')); + if (ddc) { + Expect.throws(() => (d.call)('Fosse'), jsThisIsNullCheck); + } else { + Expect.throwsNoSuchMethodError(() => (d.call)('Fosse')); + } + Expect.throwsNoSuchMethodError(() => d('Fosse')); +} diff --git a/tests/lib/js/static_interop_test/call_method_test.dart b/tests/lib/js/static_interop_test/call_method_test.dart new file mode 100644 index 000000000000..33fef8b1288f --- /dev/null +++ b/tests/lib/js/static_interop_test/call_method_test.dart @@ -0,0 +1,190 @@ +// 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. + +/// WARNING +/// +/// Not all of the expectations in this test match the language specification. +/// +/// This is part of a set of tests covering "callable objects". Please consider +/// them all together when making changes: +/// +/// ``` +/// tests/lib/js/static_interop_test/call_getter_test.dart +/// tests/lib/js/static_interop_test/call_method_test.dart +/// ``` +/// +/// This test was created with expectations that match the current behavior to +/// make it more clear when something changes and when the results in the web +/// compilers differ. +/// +/// If your change causes an expectation to fail you should decide if the +/// new result is desireable and update the expectation accordingly. + +import 'dart:js_interop'; + +import 'package:expect/expect.dart'; + +import 'call_utils.dart'; + +@JS('jsFunction') +external JSFunction get jsFunctionAsJSFunction; + +@JS('jsObject') +external JSFunction get jsObjectAsJSFunction; + +@JS('jsClass') +external JSFunction get jsClassAsJSFunction; + +extension on JSFunction { + @JS('call') + external String _call(JSAny? self, String s); + + String call(String s) => _call(globalContext, s); +} + +extension type ExtOnJSObject._(JSObject _) implements JSObject { + external String call(String s); +} + +@JS('jsFunction') +external ExtOnJSObject get jsFunctionAsExtOnJSObject; + +@JS('jsObject') +external ExtOnJSObject get jsObjectAsExtOnJSObject; + +@JS('jsClass') +external ExtOnJSObject get jsClassAsExtOnJSObject; + +extension type ExtOnJSFunction._(JSFunction _) implements JSFunction { + external String call(String s); +} + +@JS('jsFunction') +external ExtOnJSFunction get jsFunctionAsExtOnJSFunction; + +@JS('jsObject') +external ExtOnJSFunction get jsObjectAsExtOnJSFunction; + +@JS('jsClass') +external ExtOnJSFunction get jsClassAsExtOnJSFunction; + +void main() { + injectJS(); + testJSFunction(); + testExtOnJSObject(); + testExtOnJSFunction(); + testAsDynamic(); +} + +void testJSFunction() { + var obj = jsFunctionAsJSFunction; + Expect.equals('C', + (obj.callAsFunction(globalContext, 'Cello'.toJS) as JSString).toDart); + Expect.equals('C', obj.call('Cello')); + Expect.equals('C', (obj.call)('Cello')); + Expect.equals('C', obj('Cello')); + + if (dart2wasm) { + obj = jsObjectAsJSFunction; + Expect.throws(() => + (obj.callAsFunction(globalContext, 'Cello'.toJS) as JSString).toDart); + Expect.throws(() => obj.call('Cello')); + Expect.throws(() => (obj.call)('Cello')); + Expect.throws(() => obj('Cello')); + } else { + Expect.throwsTypeError(() => jsObjectAsJSFunction); + } + + if (dart2wasm) { + obj = jsClassAsJSFunction; + Expect.throws(() => + (obj.callAsFunction(globalContext, 'Cello'.toJS) as JSString).toDart); + Expect.throws(() => obj.call('Cello')); + Expect.throws(() => (obj.call)('Cello')); + Expect.throws(() => obj('Cello')); + } else { + Expect.throwsTypeError(() => jsClassAsJSFunction); + } +} + +void testExtOnJSObject() { + var obj = jsFunctionAsExtOnJSObject; + Expect.throws( + () => obj.call('Cello'), dart2wasm ? null : jsArgIsNotStringCheck); + Expect.throws(() => obj('Cello'), dart2wasm ? null : jsArgIsNotStringCheck); + + obj = jsObjectAsExtOnJSObject; + Expect.equals('C', obj.call('Cello')); + Expect.equals('C', obj('Cello')); + + obj = jsClassAsExtOnJSObject; + Expect.equals('C', obj.call('Cello')); + Expect.equals('C', obj('Cello')); +} + +void testExtOnJSFunction() { + var obj = jsFunctionAsExtOnJSFunction; + Expect.equals('C', + (obj.callAsFunction(globalContext, 'Cello'.toJS) as JSString).toDart); + Expect.throws( + () => obj.call('Cello'), dart2wasm ? null : jsArgIsNotStringCheck); + Expect.throws(() => obj('Cello'), dart2wasm ? null : jsArgIsNotStringCheck); + + if (dart2wasm) { + obj = jsObjectAsExtOnJSFunction; + Expect.throws(() => + (obj.callAsFunction(globalContext, 'Cello'.toJS) as JSString).toDart); + Expect.equals('C', obj.call('Cello')); + Expect.equals('C', obj('Cello')); + } else { + Expect.throwsTypeError(() => jsObjectAsExtOnJSFunction); + } + + if (dart2wasm) { + obj = jsClassAsExtOnJSFunction; + Expect.throws(() => + (obj.callAsFunction(globalContext, 'Cello'.toJS) as JSString).toDart); + Expect.equals('C', obj.call('Cello')); + Expect.equals('C', obj('Cello')); + } else { + Expect.throwsTypeError(() => jsClassAsExtOnJSFunction); + } +} + +testAsDynamic() { + dynamic d = confuse(jsFunctionAsJSFunction); + if (dart2wasm) { + Expect.throwsNoSuchMethodError(() => d.call('Fosse')); + } else { + Expect.equals('F', d.call('Fosse')); + } + if (ddc) { + Expect.equals('F', (d.call)('Fosse')); + } else { + Expect.throwsNoSuchMethodError(() => (d.call)('Fosse')); + } + if (dart2wasm) { + Expect.throwsNoSuchMethodError(() => d('Fosse')); + } else { + Expect.equals('F', d('Fosse')); + } + + d = confuse(jsObjectAsExtOnJSObject); + Expect.throwsNoSuchMethodError(() => d.call('Fosse')); + if (ddc) { + Expect.equals('F', (d.call)('Fosse')); + } else { + Expect.throwsNoSuchMethodError(() => (d.call)('Fosse')); + } + Expect.throwsNoSuchMethodError(() => d('Fosse')); + + d = confuse(jsClassAsExtOnJSObject); + Expect.throwsNoSuchMethodError(() => d.call('Fosse')); + if (ddc) { + Expect.throws(() => (d.call)('Fosse'), jsThisIsNullCheck); + } else { + Expect.throwsNoSuchMethodError(() => (d.call)('Fosse')); + } + Expect.throwsNoSuchMethodError(() => d('Fosse')); +} diff --git a/tests/lib/js/static_interop_test/call_utils.dart b/tests/lib/js/static_interop_test/call_utils.dart new file mode 100644 index 000000000000..fdd268db5249 --- /dev/null +++ b/tests/lib/js/static_interop_test/call_utils.dart @@ -0,0 +1,57 @@ +// 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. + +import 'dart:js_interop'; + +const dart2wasm = !bool.fromEnvironment('dart.library.html'); +const ddc = const bool.fromEnvironment('dart.library._ddc_only'); + +@pragma('dart2js:noInline') +@pragma('dart2js:assumeDynamic') +dynamic confuse(dynamic x) => x; + +@JS() +external JSAny? eval(String script); + +void injectJS() { + eval( + ''' + self.jsFunction = function(s) { + if (this == null) { + throw "`this` is null or undefined"; + } + if (typeof s != 'string') { + throw "`s` is not a string"; + } + return s.at(0); + }; + self.jsObject = { call: function(s) { + if (this == null) { + throw "`this` is null or undefined"; + } + if (typeof s != 'string') { + throw "`s` is not a string"; + } + return s.at(0); + } }; + self.NamedClass = class NamedClass { + call(s) { + if (this == null) { + throw "`this` is null or undefined"; + } + if (typeof s != 'string') { + throw "`s` is not a string"; + } + return s.at(0); + } + } + self.jsClass = new NamedClass(); + ''', + ); +} + +bool jsThisIsNullCheck(e) => + e.toString().contains('`this` is null or undefined'); + +bool jsArgIsNotStringCheck(e) => e.toString().contains('`s` is not a string'); diff --git a/tests/lib/lib.status b/tests/lib/lib.status index b54fa9d1efbc..ec2de91ca64c 100644 --- a/tests/lib/lib.status +++ b/tests/lib/lib.status @@ -79,6 +79,8 @@ js/js_util/properties_test: SkipByDesign # Issue 42085. CSP policy disallows inj js/method_call_on_object_test: SkipByDesign # Issue 42085. js/mock_test/*: SkipByDesign # Issue 42085. js/parameters_test: SkipByDesign # Issue 42085. +js/static_interop_test/call_getter_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code +js/static_interop_test/call_method_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code js/static_interop_test/extension_type/external_extension_member_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code js/static_interop_test/extension_type/external_member_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code js/static_interop_test/extension_type/external_static_member_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code