From 5010df50fe54aa9afc946d6510ad6b2a606a1991 Mon Sep 17 00:00:00 2001 From: Alexander Markov Date: Fri, 18 Feb 2022 16:06:12 +0000 Subject: [PATCH] [vm] Replace asm intrinsic _GrowableList._withData with flow graph implementation _GrowableList._withData constructor can be implemented in flow graph and inlined, instead of having an asm intrinsic implementation. This change also adds a specialized allocation stub for _GrowableList class to offset slower general-purpose allocation stub. TEST=ci Fixes https://github.com/dart-lang/sdk/issues/48255 Change-Id: Ice0ca9156d7a504960cce1718ffd9aca24a9a3d1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/231527 Reviewed-by: Slava Egorov Commit-Queue: Alexander Markov --- runtime/vm/compiler/asm_intrinsifier_arm.cc | 35 ------------------ runtime/vm/compiler/asm_intrinsifier_arm64.cc | 34 ----------------- runtime/vm/compiler/asm_intrinsifier_ia32.cc | 36 ------------------ runtime/vm/compiler/asm_intrinsifier_riscv.cc | 34 ----------------- runtime/vm/compiler/asm_intrinsifier_x64.cc | 36 ------------------ runtime/vm/compiler/frontend/kernel_to_il.cc | 21 +++++++++++ runtime/vm/compiler/recognized_methods_list.h | 2 +- runtime/vm/compiler/stub_code_compiler.cc | 37 +++++++++++++++++++ runtime/vm/compiler/stub_code_compiler_arm.cc | 8 ++-- .../vm/compiler/stub_code_compiler_arm64.cc | 11 +++--- .../vm/compiler/stub_code_compiler_riscv.cc | 11 +++--- runtime/vm/compiler/stub_code_compiler_x64.cc | 11 +++--- runtime/vm/constants_arm.h | 1 + runtime/vm/constants_arm64.h | 1 + runtime/vm/constants_ia32.h | 1 + runtime/vm/constants_riscv.h | 1 + runtime/vm/constants_x64.h | 1 + runtime/vm/object_store.h | 2 + runtime/vm/stub_code.cc | 4 ++ runtime/vm/stub_code_list.h | 1 + sdk/lib/_internal/vm/lib/growable_array.dart | 2 +- 21 files changed, 91 insertions(+), 199 deletions(-) diff --git a/runtime/vm/compiler/asm_intrinsifier_arm.cc b/runtime/vm/compiler/asm_intrinsifier_arm.cc index 7702c24ee69..3b6b7071477 100644 --- a/runtime/vm/compiler/asm_intrinsifier_arm.cc +++ b/runtime/vm/compiler/asm_intrinsifier_arm.cc @@ -26,41 +26,6 @@ namespace compiler { #define __ assembler-> -// Allocate a GrowableObjectArray:: using the backing array specified. -// On stack: type argument (+1), data (+0). -void AsmIntrinsifier::GrowableArray_Allocate(Assembler* assembler, - Label* normal_ir_body) { - // The newly allocated object is returned in R0. - const intptr_t kTypeArgumentsOffset = 1 * target::kWordSize; - const intptr_t kArrayOffset = 0 * target::kWordSize; - - // Try allocating in new space. - const Class& cls = GrowableObjectArrayClass(); - __ TryAllocate(cls, normal_ir_body, Assembler::kFarJump, R0, R1); - - // Store backing array object in growable array object. - __ ldr(R1, Address(SP, kArrayOffset)); // Data argument. - // R0 is new, no barrier needed. - __ StoreIntoObjectNoBarrier( - R0, FieldAddress(R0, target::GrowableObjectArray::data_offset()), R1); - - // R0: new growable array object start as a tagged pointer. - // Store the type argument field in the growable array object. - __ ldr(R1, Address(SP, kTypeArgumentsOffset)); // Type argument. - __ StoreIntoObjectNoBarrier( - R0, - FieldAddress(R0, target::GrowableObjectArray::type_arguments_offset()), - R1); - - // Set the length field in the growable array object to 0. - __ LoadImmediate(R1, 0); - __ StoreIntoObjectNoBarrier( - R0, FieldAddress(R0, target::GrowableObjectArray::length_offset()), R1); - __ Ret(); // Returns the newly allocated object in R0. - - __ Bind(normal_ir_body); -} - // Loads args from stack into R0 and R1 // Tests if they are smis, jumps to label not_smi if not. static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { diff --git a/runtime/vm/compiler/asm_intrinsifier_arm64.cc b/runtime/vm/compiler/asm_intrinsifier_arm64.cc index 429099cb3ff..eb5cacc4b0f 100644 --- a/runtime/vm/compiler/asm_intrinsifier_arm64.cc +++ b/runtime/vm/compiler/asm_intrinsifier_arm64.cc @@ -26,40 +26,6 @@ namespace compiler { #define __ assembler-> -// Allocate a GrowableObjectArray:: using the backing array specified. -// On stack: type argument (+1), data (+0). -void AsmIntrinsifier::GrowableArray_Allocate(Assembler* assembler, - Label* normal_ir_body) { - // The newly allocated object is returned in R0. - const intptr_t kTypeArgumentsOffset = 1 * target::kWordSize; - const intptr_t kArrayOffset = 0 * target::kWordSize; - - // Try allocating in new space. - const Class& cls = GrowableObjectArrayClass(); - __ TryAllocate(cls, normal_ir_body, Assembler::kFarJump, R0, R1); - - // Store backing array object in growable array object. - __ ldr(R1, Address(SP, kArrayOffset)); // Data argument. - // R0 is new, no barrier needed. - __ StoreCompressedIntoObjectNoBarrier( - R0, FieldAddress(R0, target::GrowableObjectArray::data_offset()), R1); - - // R0: new growable array object start as a tagged pointer. - // Store the type argument field in the growable array object. - __ ldr(R1, Address(SP, kTypeArgumentsOffset)); // Type argument. - __ StoreCompressedIntoObjectNoBarrier( - R0, - FieldAddress(R0, target::GrowableObjectArray::type_arguments_offset()), - R1); - - // Set the length field in the growable array object to 0. - __ StoreCompressedIntoObjectNoBarrier( - R0, FieldAddress(R0, target::GrowableObjectArray::length_offset()), ZR); - __ ret(); // Returns the newly allocated object in R0. - - __ Bind(normal_ir_body); -} - // Loads args from stack into R0 and R1 // Tests if they are smis, jumps to label not_smi if not. static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { diff --git a/runtime/vm/compiler/asm_intrinsifier_ia32.cc b/runtime/vm/compiler/asm_intrinsifier_ia32.cc index 7d264aa703a..815a2e012cd 100644 --- a/runtime/vm/compiler/asm_intrinsifier_ia32.cc +++ b/runtime/vm/compiler/asm_intrinsifier_ia32.cc @@ -31,42 +31,6 @@ namespace compiler { #define __ assembler-> -// Allocate a GrowableObjectArray:: using the backing array specified. -// On stack: type argument (+2), data (+1), return-address (+0). -void AsmIntrinsifier::GrowableArray_Allocate(Assembler* assembler, - Label* normal_ir_body) { - // This snippet of inlined code uses the following registers: - // EAX, EBX - // and the newly allocated object is returned in EAX. - const intptr_t kTypeArgumentsOffset = 2 * target::kWordSize; - - const intptr_t kArrayOffset = 1 * target::kWordSize; - - // Try allocating in new space. - const Class& cls = GrowableObjectArrayClass(); - __ TryAllocate(cls, normal_ir_body, Assembler::kNearJump, EAX, EBX); - - // Store backing array object in growable array object. - __ movl(EBX, Address(ESP, kArrayOffset)); // data argument. - // EAX is new, no barrier needed. - __ StoreIntoObjectNoBarrier( - EAX, FieldAddress(EAX, target::GrowableObjectArray::data_offset()), EBX); - - // EAX: new growable array object start as a tagged pointer. - // Store the type argument field in the growable array object. - __ movl(EBX, Address(ESP, kTypeArgumentsOffset)); // type argument. - __ StoreIntoObjectNoBarrier( - EAX, - FieldAddress(EAX, target::GrowableObjectArray::type_arguments_offset()), - EBX); - - __ ZeroInitSmiField( - FieldAddress(EAX, target::GrowableObjectArray::length_offset())); - __ ret(); // returns the newly allocated object in EAX. - - __ Bind(normal_ir_body); -} - // Tests if two top most arguments are smis, jumps to label not_smi if not. // Topmost argument is in EAX. static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { diff --git a/runtime/vm/compiler/asm_intrinsifier_riscv.cc b/runtime/vm/compiler/asm_intrinsifier_riscv.cc index 0e2da821f7c..db03989c6eb 100644 --- a/runtime/vm/compiler/asm_intrinsifier_riscv.cc +++ b/runtime/vm/compiler/asm_intrinsifier_riscv.cc @@ -26,40 +26,6 @@ namespace compiler { #define __ assembler-> -// Allocate a GrowableObjectArray:: using the backing array specified. -// On stack: type argument (+1), data (+0). -void AsmIntrinsifier::GrowableArray_Allocate(Assembler* assembler, - Label* normal_ir_body) { - // The newly allocated object is returned in R0. - const intptr_t kTypeArgumentsOffset = 1 * target::kWordSize; - const intptr_t kArrayOffset = 0 * target::kWordSize; - - // Try allocating in new space. - const Class& cls = GrowableObjectArrayClass(); - __ TryAllocate(cls, normal_ir_body, Assembler::kFarJump, A0, A1); - - // Store backing array object in growable array object. - __ lx(A1, Address(SP, kArrayOffset)); // Data argument. - // R0 is new, no barrier needed. - __ StoreCompressedIntoObjectNoBarrier( - A0, FieldAddress(A0, target::GrowableObjectArray::data_offset()), A1); - - // R0: new growable array object start as a tagged pointer. - // Store the type argument field in the growable array object. - __ lx(A1, Address(SP, kTypeArgumentsOffset)); // Type argument. - __ StoreCompressedIntoObjectNoBarrier( - A0, - FieldAddress(A0, target::GrowableObjectArray::type_arguments_offset()), - A1); - - // Set the length field in the growable array object to 0. - __ StoreCompressedIntoObjectNoBarrier( - A0, FieldAddress(A0, target::GrowableObjectArray::length_offset()), ZR); - __ ret(); // Returns the newly allocated object in A0. - - __ Bind(normal_ir_body); -} - // Loads args from stack into A0 and A1 // Tests if they are smis, jumps to label not_smi if not. static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { diff --git a/runtime/vm/compiler/asm_intrinsifier_x64.cc b/runtime/vm/compiler/asm_intrinsifier_x64.cc index 48bfe54496f..0a47313b244 100644 --- a/runtime/vm/compiler/asm_intrinsifier_x64.cc +++ b/runtime/vm/compiler/asm_intrinsifier_x64.cc @@ -26,42 +26,6 @@ namespace compiler { #define __ assembler-> -// Allocate a GrowableObjectArray using the backing array specified. -// On stack: type argument (+2), data (+1), return-address (+0). -void AsmIntrinsifier::GrowableArray_Allocate(Assembler* assembler, - Label* normal_ir_body) { - // This snippet of inlined code uses the following registers: - // RAX, RCX, R13 - // and the newly allocated object is returned in RAX. - const intptr_t kTypeArgumentsOffset = 2 * target::kWordSize; - const intptr_t kArrayOffset = 1 * target::kWordSize; - - // Try allocating in new space. - const Class& cls = GrowableObjectArrayClass(); - __ TryAllocate(cls, normal_ir_body, Assembler::kFarJump, RAX, R13); - - // Store backing array object in growable array object. - __ movq(RCX, Address(RSP, kArrayOffset)); // data argument. - // RAX is new, no barrier needed. - __ StoreCompressedIntoObjectNoBarrier( - RAX, FieldAddress(RAX, target::GrowableObjectArray::data_offset()), RCX); - - // RAX: new growable array object start as a tagged pointer. - // Store the type argument field in the growable array object. - __ movq(RCX, Address(RSP, kTypeArgumentsOffset)); // type argument. - __ StoreCompressedIntoObjectNoBarrier( - RAX, - FieldAddress(RAX, target::GrowableObjectArray::type_arguments_offset()), - RCX); - - // Set the length field in the growable array object to 0. - __ ZeroInitCompressedSmiField( - FieldAddress(RAX, target::GrowableObjectArray::length_offset())); - __ ret(); // returns the newly allocated object in RAX. - - __ Bind(normal_ir_body); -} - // Tests if two top most arguments are smis, jumps to label not_smi if not. // Topmost argument is in RAX. static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc index 0311465b745..6fd0db28009 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.cc +++ b/runtime/vm/compiler/frontend/kernel_to_il.cc @@ -877,6 +877,7 @@ bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph( case MethodRecognizer::kByteDataViewTypedData: case MethodRecognizer::kTypedDataViewTypedData: case MethodRecognizer::kClassIDgetID: + case MethodRecognizer::kGrowableArrayAllocateWithData: case MethodRecognizer::kGrowableArrayCapacity: case MethodRecognizer::kListFactory: case MethodRecognizer::kObjectArrayAllocate: @@ -1124,6 +1125,26 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod( body += LoadLocal(parsed_function_->RawParameterVariable(0)); body += LoadClassId(); break; + case MethodRecognizer::kGrowableArrayAllocateWithData: { + ASSERT(function.IsFactory()); + ASSERT_EQUAL(function.NumParameters(), 2); + const Class& cls = + Class::ZoneHandle(Z, compiler::GrowableObjectArrayClass().ptr()); + body += LoadLocal(parsed_function_->RawParameterVariable(0)); + body += AllocateObject(TokenPosition::kNoSource, cls, 1); + LocalVariable* object = MakeTemporary(); + body += LoadLocal(object); + body += LoadLocal(parsed_function_->RawParameterVariable(1)); + body += StoreNativeField(Slot::GrowableObjectArray_data(), + StoreInstanceFieldInstr::Kind::kInitializing, + kNoStoreBarrier); + body += LoadLocal(object); + body += IntConstant(0); + body += StoreNativeField(Slot::GrowableObjectArray_length(), + StoreInstanceFieldInstr::Kind::kInitializing, + kNoStoreBarrier); + break; + } case MethodRecognizer::kGrowableArrayCapacity: ASSERT_EQUAL(function.NumParameters(), 1); body += LoadLocal(parsed_function_->RawParameterVariable(0)); diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h index 6c67e4cc9e4..5d42253ab69 100644 --- a/runtime/vm/compiler/recognized_methods_list.h +++ b/runtime/vm/compiler/recognized_methods_list.h @@ -18,6 +18,7 @@ namespace dart { V(List, ., ListFactory, 0xbc820cf9) \ V(_List, ., ObjectArrayAllocate, 0xd693eee6) \ V(_List, []=, ObjectArraySetIndexed, 0xd7b48abc) \ + V(_GrowableList, ._withData, GrowableArrayAllocateWithData, 0xa32d060b) \ V(_GrowableList, []=, GrowableArraySetIndexed, 0xd7b48abc) \ V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0x1623dc34) \ V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0x177ffe2a) \ @@ -274,7 +275,6 @@ namespace dart { V(_Double, get:isNegative, Double_getIsNegative, 0xd4715091) \ V(_Double, _mulFromInteger, Double_mulFromInteger, 0x0a50d2cf) \ V(_Double, .fromInteger, DoubleFromInteger, 0x7d0fd999) \ - V(_GrowableList, ._withData, GrowableArray_Allocate, 0xa32d060b) \ V(_RegExp, _ExecuteMatch, RegExp_ExecuteMatch, 0x9911d549) \ V(_RegExp, _ExecuteMatchSticky, RegExp_ExecuteMatchSticky, 0x91dd880f) \ V(Object, ==, ObjectEquals, 0x46587030) \ diff --git a/runtime/vm/compiler/stub_code_compiler.cc b/runtime/vm/compiler/stub_code_compiler.cc index b70a40e9cf7..199ae30d78e 100644 --- a/runtime/vm/compiler/stub_code_compiler.cc +++ b/runtime/vm/compiler/stub_code_compiler.cc @@ -899,6 +899,43 @@ void StubCodeCompiler::GenerateAllocateClosureStub(Assembler* assembler) { __ Ret(); } +// Generates allocation stub for _GrowableList class. +// This stub exists solely for performance reasons: default allocation +// stub is slower as it doesn't use specialized inline allocation. +void StubCodeCompiler::GenerateAllocateGrowableArrayStub(Assembler* assembler) { +#if defined(TARGET_ARCH_IA32) + // This stub is not used on IA32 because IA32 version of + // StubCodeCompiler::GenerateAllocationStubForClass uses inline + // allocation. Also, AllocateObjectSlow stub is not generated on IA32. + __ Breakpoint(); +#else + const intptr_t instance_size = target::RoundedAllocationSize( + target::GrowableObjectArray::InstanceSize()); + + if (!FLAG_use_slow_path && FLAG_inline_alloc) { + Label slow_case; + __ Comment("Inline allocation of GrowableList"); + __ TryAllocateObject(kGrowableObjectArrayCid, instance_size, &slow_case, + Assembler::kNearJump, AllocateObjectABI::kResultReg, + /*temp_reg=*/AllocateObjectABI::kTagsReg); + __ StoreIntoObjectNoBarrier( + AllocateObjectABI::kResultReg, + FieldAddress(AllocateObjectABI::kResultReg, + target::GrowableObjectArray::type_arguments_offset()), + AllocateObjectABI::kTypeArgumentsReg); + + __ Ret(); + __ Bind(&slow_case); + } + + const uword tags = target::MakeTagWordForNewSpaceObject( + kGrowableObjectArrayCid, instance_size); + __ LoadImmediate(AllocateObjectABI::kTagsReg, tags); + __ Jump( + Address(THR, target::Thread::allocate_object_slow_entry_point_offset())); +#endif // defined(TARGET_ARCH_IA32) +} + // The UnhandledException class lives in the VM isolate, so it cannot cache // an allocation stub for itself. Instead, we cache it in the stub code list. void StubCodeCompiler::GenerateAllocateUnhandledExceptionStub( diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc index 5174ca837b9..a37565a2044 100644 --- a/runtime/vm/compiler/stub_code_compiler_arm.cc +++ b/runtime/vm/compiler/stub_code_compiler_arm.cc @@ -1728,7 +1728,7 @@ void StubCodeCompiler::GenerateArrayWriteBarrierStub(Assembler* assembler) { static void GenerateAllocateObjectHelper(Assembler* assembler, bool is_cls_parameterized) { - const Register kTagsReg = R2; + const Register kTagsReg = AllocateObjectABI::kTagsReg; { Label slow_case; @@ -1845,7 +1845,6 @@ void StubCodeCompiler::GenerateAllocateObjectParameterizedStub( void StubCodeCompiler::GenerateAllocateObjectSlowStub(Assembler* assembler) { const Register kClsReg = R1; - const Register kTagsReg = R2; if (!FLAG_precompiled_mode) { __ ldr(CODE_REG, @@ -1856,7 +1855,8 @@ void StubCodeCompiler::GenerateAllocateObjectSlowStub(Assembler* assembler) { // calling into the runtime. __ EnterStubFrame(); - __ ExtractClassIdFromTags(AllocateObjectABI::kResultReg, kTagsReg); + __ ExtractClassIdFromTags(AllocateObjectABI::kResultReg, + AllocateObjectABI::kTagsReg); __ LoadClassById(kClsReg, AllocateObjectABI::kResultReg); __ LoadObject(AllocateObjectABI::kResultReg, NullObject()); @@ -1903,7 +1903,7 @@ void StubCodeCompiler::GenerateAllocationStubForClass( const uword tags = target::MakeTagWordForNewSpaceObject(cls_id, instance_size); - const Register kTagsReg = R2; + const Register kTagsReg = AllocateObjectABI::kTagsReg; __ LoadImmediate(kTagsReg, tags); diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc index e5fe61ffb75..6dc4dbe909d 100644 --- a/runtime/vm/compiler/stub_code_compiler_arm64.cc +++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc @@ -1904,7 +1904,7 @@ void StubCodeCompiler::GenerateArrayWriteBarrierStub(Assembler* assembler) { static void GenerateAllocateObjectHelper(Assembler* assembler, bool is_cls_parameterized) { - const Register kTagsReg = R2; + const Register kTagsReg = AllocateObjectABI::kTagsReg; { Label slow_case; @@ -2014,20 +2014,19 @@ void StubCodeCompiler::GenerateAllocateObjectParameterizedStub( } void StubCodeCompiler::GenerateAllocateObjectSlowStub(Assembler* assembler) { - const Register kTagsToClsIdReg = R2; - if (!FLAG_precompiled_mode) { __ ldr(CODE_REG, Address(THR, target::Thread::call_to_runtime_stub_offset())); } - __ ExtractClassIdFromTags(kTagsToClsIdReg, kTagsToClsIdReg); + __ ExtractClassIdFromTags(AllocateObjectABI::kTagsReg, + AllocateObjectABI::kTagsReg); // Create a stub frame as we are pushing some objects on the stack before // calling into the runtime. __ EnterStubFrame(); - __ LoadClassById(R0, kTagsToClsIdReg); + __ LoadClassById(R0, AllocateObjectABI::kTagsReg); __ PushPair(R0, NULL_REG); // Pushes result slot, then class object. // Should be Object::null() if class is non-parameterized. @@ -2072,7 +2071,7 @@ void StubCodeCompiler::GenerateAllocationStubForClass( target::MakeTagWordForNewSpaceObject(cls_id, instance_size); // Note: Keep in sync with helper function. - const Register kTagsReg = R2; + const Register kTagsReg = AllocateObjectABI::kTagsReg; __ LoadImmediate(kTagsReg, tags); diff --git a/runtime/vm/compiler/stub_code_compiler_riscv.cc b/runtime/vm/compiler/stub_code_compiler_riscv.cc index c9f604bc54d..14dd9f3b4d5 100644 --- a/runtime/vm/compiler/stub_code_compiler_riscv.cc +++ b/runtime/vm/compiler/stub_code_compiler_riscv.cc @@ -1831,7 +1831,7 @@ void StubCodeCompiler::GenerateArrayWriteBarrierStub(Assembler* assembler) { static void GenerateAllocateObjectHelper(Assembler* assembler, bool is_cls_parameterized) { - const Register kTagsReg = T2; + const Register kTagsReg = AllocateObjectABI::kTagsReg; { Label slow_case; @@ -1936,8 +1936,6 @@ void StubCodeCompiler::GenerateAllocateObjectParameterizedStub( } void StubCodeCompiler::GenerateAllocateObjectSlowStub(Assembler* assembler) { - const Register kTagsToClsIdReg = T2; - if (!FLAG_precompiled_mode) { __ lx(CODE_REG, Address(THR, target::Thread::call_to_runtime_stub_offset())); @@ -1947,8 +1945,9 @@ void StubCodeCompiler::GenerateAllocateObjectSlowStub(Assembler* assembler) { // calling into the runtime. __ EnterStubFrame(); - __ ExtractClassIdFromTags(kTagsToClsIdReg, kTagsToClsIdReg); - __ LoadClassById(A0, kTagsToClsIdReg); + __ ExtractClassIdFromTags(AllocateObjectABI::kTagsReg, + AllocateObjectABI::kTagsReg); + __ LoadClassById(A0, AllocateObjectABI::kTagsReg); __ subi(SP, SP, 3 * target::kWordSize); __ sx(ZR, Address(SP, 2 * target::kWordSize)); // Result slot. @@ -1993,7 +1992,7 @@ void StubCodeCompiler::GenerateAllocationStubForClass( target::MakeTagWordForNewSpaceObject(cls_id, instance_size); // Note: Keep in sync with helper function. - const Register kTagsReg = T2; + const Register kTagsReg = AllocateObjectABI::kTagsReg; ASSERT(kTagsReg != AllocateObjectABI::kTypeArgumentsReg); __ LoadImmediate(kTagsReg, tags); diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc index 5e3ba12bc29..de422365b21 100644 --- a/runtime/vm/compiler/stub_code_compiler_x64.cc +++ b/runtime/vm/compiler/stub_code_compiler_x64.cc @@ -1938,7 +1938,7 @@ void StubCodeCompiler::GenerateArrayWriteBarrierStub(Assembler* assembler) { static void GenerateAllocateObjectHelper(Assembler* assembler, bool is_cls_parameterized) { // Note: Keep in sync with calling function. - const Register kTagsReg = R8; + const Register kTagsReg = AllocateObjectABI::kTagsReg; { Label slow_case; @@ -2049,14 +2049,13 @@ void StubCodeCompiler::GenerateAllocateObjectParameterizedStub( } void StubCodeCompiler::GenerateAllocateObjectSlowStub(Assembler* assembler) { - const Register kTagsToClsIdReg = R8; - if (!FLAG_precompiled_mode) { __ movq(CODE_REG, Address(THR, target::Thread::call_to_runtime_stub_offset())); } - __ ExtractClassIdFromTags(kTagsToClsIdReg, kTagsToClsIdReg); + __ ExtractClassIdFromTags(AllocateObjectABI::kTagsReg, + AllocateObjectABI::kTagsReg); // Create a stub frame. // Ensure constant pool is allowed so we can e.g. load class object. @@ -2067,7 +2066,7 @@ void StubCodeCompiler::GenerateAllocateObjectSlowStub(Assembler* assembler) { __ pushq(AllocateObjectABI::kResultReg); // Push class of object to be allocated. - __ LoadClassById(AllocateObjectABI::kResultReg, kTagsToClsIdReg); + __ LoadClassById(AllocateObjectABI::kResultReg, AllocateObjectABI::kTagsReg); __ pushq(AllocateObjectABI::kResultReg); // Must be Object::null() if non-parameterized class. @@ -2118,7 +2117,7 @@ void StubCodeCompiler::GenerateAllocationStubForClass( const uword tags = target::MakeTagWordForNewSpaceObject(cls_id, instance_size); - const Register kTagsReg = R8; + const Register kTagsReg = AllocateObjectABI::kTagsReg; __ movq(kTagsReg, Immediate(tags)); diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h index 94b214a6948..b7f23744358 100644 --- a/runtime/vm/constants_arm.h +++ b/runtime/vm/constants_arm.h @@ -470,6 +470,7 @@ struct RangeErrorABI { struct AllocateObjectABI { static const Register kResultReg = R0; static const Register kTypeArgumentsReg = R3; + static const Register kTagsReg = R2; }; // ABI for AllocateClosureStub. diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h index 9e4213d02c7..b2f4e6edfd5 100644 --- a/runtime/vm/constants_arm64.h +++ b/runtime/vm/constants_arm64.h @@ -309,6 +309,7 @@ struct RangeErrorABI { struct AllocateObjectABI { static const Register kResultReg = R0; static const Register kTypeArgumentsReg = R1; + static const Register kTagsReg = R2; }; // ABI for AllocateClosureStub. diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h index bac9dd51279..d06f97f9f0d 100644 --- a/runtime/vm/constants_ia32.h +++ b/runtime/vm/constants_ia32.h @@ -206,6 +206,7 @@ struct RangeErrorABI { struct AllocateObjectABI { static const Register kResultReg = EAX; static const Register kTypeArgumentsReg = EDX; + static const Register kTagsReg = kNoRegister; // Not used. }; // ABI for Allocate{Mint,Double,Float32x4,Float64x2}Stub. diff --git a/runtime/vm/constants_riscv.h b/runtime/vm/constants_riscv.h index d04317b3a71..a03694cbccd 100644 --- a/runtime/vm/constants_riscv.h +++ b/runtime/vm/constants_riscv.h @@ -326,6 +326,7 @@ struct RangeErrorABI { struct AllocateObjectABI { static constexpr Register kResultReg = A0; static constexpr Register kTypeArgumentsReg = T1; + static const Register kTagsReg = T2; }; // ABI for AllocateClosureStub. diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h index 2bc94443e18..aae0a4c49ba 100644 --- a/runtime/vm/constants_x64.h +++ b/runtime/vm/constants_x64.h @@ -281,6 +281,7 @@ struct RangeErrorABI { struct AllocateObjectABI { static const Register kResultReg = RAX; static const Register kTypeArgumentsReg = RDX; + static const Register kTagsReg = R8; }; // ABI for AllocateClosureStub. diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h index b8eaf218491..88d7a2e672f 100644 --- a/runtime/vm/object_store.h +++ b/runtime/vm/object_store.h @@ -208,6 +208,7 @@ class ObjectPointerVisitor; RW(Code, allocate_float64x2_array_stub) \ RW(Code, allocate_closure_stub) \ RW(Code, allocate_context_stub) \ + RW(Code, allocate_growable_array_stub) \ RW(Code, allocate_object_stub) \ RW(Code, allocate_object_parametrized_stub) \ RW(Code, allocate_unhandled_exception_stub) \ @@ -284,6 +285,7 @@ class ObjectPointerVisitor; DO(allocate_float64x2_array_stub, AllocateFloat64x2Array) \ DO(allocate_closure_stub, AllocateClosure) \ DO(allocate_context_stub, AllocateContext) \ + DO(allocate_growable_array_stub, AllocateGrowableArray) \ DO(allocate_object_stub, AllocateObject) \ DO(allocate_object_parametrized_stub, AllocateObjectParameterized) \ DO(allocate_unhandled_exception_stub, AllocateUnhandledException) \ diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc index 6303447de44..be405225502 100644 --- a/runtime/vm/stub_code.cc +++ b/runtime/vm/stub_code.cc @@ -172,6 +172,10 @@ CodePtr StubCode::GetAllocationStubForClass(const Class& cls) { switch (cls.id()) { case kArrayCid: return object_store->allocate_array_stub(); +#if !defined(TARGET_ARCH_IA32) + case kGrowableObjectArrayCid: + return object_store->allocate_growable_array_stub(); +#endif // !defined(TARGET_ARCH_IA32) case kContextCid: return object_store->allocate_context_stub(); case kUnhandledExceptionCid: diff --git a/runtime/vm/stub_code_list.h b/runtime/vm/stub_code_list.h index 778e08c76c8..3607cbcc401 100644 --- a/runtime/vm/stub_code_list.h +++ b/runtime/vm/stub_code_list.h @@ -52,6 +52,7 @@ namespace dart { V(AllocateMintSharedWithoutFPURegs) \ V(AllocateClosure) \ V(AllocateContext) \ + V(AllocateGrowableArray) \ V(AllocateObject) \ V(AllocateObjectParameterized) \ V(AllocateObjectSlow) \ diff --git a/sdk/lib/_internal/vm/lib/growable_array.dart b/sdk/lib/_internal/vm/lib/growable_array.dart index c6d9e461c64..2c47725ee4f 100644 --- a/sdk/lib/_internal/vm/lib/growable_array.dart +++ b/sdk/lib/_internal/vm/lib/growable_array.dart @@ -222,7 +222,7 @@ class _GrowableList extends ListBase { return list; } - @pragma("vm:recognized", "asm-intrinsic") + @pragma("vm:recognized", "other") @pragma("vm:exact-result-type", [_GrowableList, "result-type-uses-passed-type-arguments"]) @pragma("vm:external-name", "GrowableList_allocate")