diff options
author | sergey ignatov <sergign60@mail.ru> | 2017-07-06 22:26:59 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2017-07-06 22:26:59 +0300 |
commit | 9c4aa0d63785ac0668def4b60c90e9dc80846db0 (patch) | |
tree | d1fcb9bf6fd58647d46d3e81e139b7cabfa23ff1 /src/Native/Runtime/arm | |
parent | efc14f988432b4e6d25a5d64b37d9211e7af8494 (diff) |
[arm tizen] Implemented AllocFast.s stubs (#4068)
* [arm tizen] Implemented AllocFast.s stubs
* Rollbacked portable.cpp(from #3989)
* Added changes in CallDescrWorker.S
Diffstat (limited to 'src/Native/Runtime/arm')
-rw-r--r-- | src/Native/Runtime/arm/AllocFast.S | 501 | ||||
-rw-r--r-- | src/Native/Runtime/arm/CallDescrWorker.S | 36 |
2 files changed, 434 insertions, 103 deletions
diff --git a/src/Native/Runtime/arm/AllocFast.S b/src/Native/Runtime/arm/AllocFast.S index 364a46afc..992e6c350 100644 --- a/src/Native/Runtime/arm/AllocFast.S +++ b/src/Native/Runtime/arm/AllocFast.S @@ -2,115 +2,470 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#include <unixasmmacros.inc> - .syntax unified .thumb -#ifdef _DEBUG -.rodata -AssertMsg: .asciz "__FILE__:%s: %s is not implemented\n" -FileName: .asciz "AllocFast.S" -RhpNewFastName: .asciz "RhpNewFast" -RhpNewFinalizableName: .asciz "RhpNewFinalizable" -RhpNewObjectName: .asciz "RhpNewObject" -RhpNewArrayName: .asciz "RhpNewArray" -RhpNewArrayRareName: .asciz "RhpNewArrayRare" -RhpNewFastAlign8Name: .asciz "RhpNewFastAlign8" -RhpNewFinalizableAlign8Name: .asciz "RhpNewFinalizableAlign8" -RhpNewFastMisalignName: .asciz "RhpNewFastMisalign" -RhpNewArrayAlign8Name: .asciz "RhpNewArrayAlign8" - -.text -.macro GEN_ASSERT_FUNC func - GEN_ASSERT AssertMsg, FileName, \func -.endm -#endif - -// TODO: Implement Arm support +#include <unixasmmacros.inc> +#include <AsmOffsets.inc> // generated by the build from AsmOffsets.cpp // Allocate non-array, non-finalizable object. If the allocation doesn't fit into the current thread's // allocation context then automatically fallback to the slow allocation path. // r0 == EEType -// -// LEAF_ENTRY RhpNewFast, _TEXT -//#ifdef _DEBUG -// GEN_ASSERT_FUNC RhpNewFastName -//#endif -// LEAF_END RhpNewFast, _TEXT -// +LEAF_ENTRY RhpNewFast, _TEXT + PROLOG_PUSH "{r4,lr}" + mov r4, r0 // save EEType + + // r0 = GetThread() + INLINE_GETTHREAD + + // r4 contains EEType pointer + ldr r2, [r4, #OFFSETOF__EEType__m_uBaseSize] + + // r0: Thread pointer + // r4: EEType pointer + // r2: base size + + ldr r3, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_ptr] + add r2, r3 + ldr r1, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_limit] + cmp r2, r1 + bhi LOCAL_LABEL(RhpNewFast_RarePath) + + // set the new alloc pointer + str r2, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_ptr] + + mov r0, r3 + + EPILOG_POP "{r4,pc}" + +LOCAL_LABEL(RhpNewFast_RarePath): + mov r0, r4 // restore EEType + mov r1, #0 + EPILOG_POP "{r4,lr}" + b C_FUNC(RhpNewObject) + +LEAF_END RhpNewFast, _TEXT // Allocate non-array object with finalizer. // r0 == EEType // -// LEAF_ENTRY RhpNewFinalizable, _TEXT -//#ifdef _DEBUG -// GEN_ASSERT_FUNC RhpNewFinalizableName -//#endif -// LEAF_END RhpNewFinalizable, _TEXT -// +LEAF_ENTRY RhpNewFinalizable, _TEXT + mov r1, #GC_ALLOC_FINALIZE + b C_FUNC(RhpNewObject) +LEAF_END RhpNewFinalizable, _TEXT + // Allocate non-array object. // r0 == EEType // r1 == alloc flags - NESTED_ENTRY RhpNewObject, _TEXT, NoHandler -#ifdef _DEBUG - GEN_ASSERT_FUNC RhpNewObjectName -#endif - NESTED_END RhpNewObject, _TEXT +NESTED_ENTRY RhpNewObject, _TEXT, NoHandler + + PUSH_COOP_PINVOKE_FRAME r3 + + // r0: EEType + // r1: alloc flags + // r3: transition frame + + // Preserve the EEType in r5. + mov r5, r0 + + ldr r2, [r0, #OFFSETOF__EEType__m_uBaseSize] // cbSize + + // void* RhpGcAlloc(EEType *pEEType, UInt32 uFlags, UIntNative cbSize, void * pTransitionFrame) + blx C_FUNC(RhpGcAlloc) + + // Set the new object's EEType pointer on success. + cbz r0, LOCAL_LABEL(NewOutOfMemory) + str r5, [r0, #OFFSETOF__Object__m_pEEType] + + // If the object is bigger than RH_LARGE_OBJECT_SIZE, we must publish it to the BGC + ldr r1, [r5, #OFFSETOF__EEType__m_uBaseSize] + movw r2, #(RH_LARGE_OBJECT_SIZE & 0xFFFF) + movt r2, #(RH_LARGE_OBJECT_SIZE >> 16) + cmp r1, r2 + blo LOCAL_LABEL(New_SkipPublish) + + // r0: already contains object + // r1: already contains object size + + bl C_FUNC(RhpPublishObject) + // r0: function returned the passed-in object + +LOCAL_LABEL(New_SkipPublish): + + POP_COOP_PINVOKE_FRAME + bx lr + +LOCAL_LABEL(NewOutOfMemory): + // This is the OOM failure path. We're going to tail-call to a managed helper that will throw + // an out of memory exception that the caller of this allocator understands. + + mov r0, r5 // EEType pointer + mov r1, #0 // Indicate that we should throw OOM. + + POP_COOP_PINVOKE_FRAME + + b C_FUNC(RhExceptionHandling_FailedAllocation) + +NESTED_END RhpNewObject, _TEXT // Allocate one dimensional, zero based array (SZARRAY). // r0 == EEType // r1 == element count -// -// LEAF_ENTRY RhpNewArray, _TEXT -//#ifdef _DEBUG -// GEN_ASSERT_FUNC RhpNewArrayName -//#endif -// LEAF_END RhpNewArray, _TEXT -// +LEAF_ENTRY RhpNewArray, _TEXT + PROLOG_PUSH "{r4,lr}" + // we want to limit the element count to the non-negative 32-bit int range + movw r12, 0xffff + movt r12, (0x7fff >> 16) + cmp r1, r12 + bhi LOCAL_LABEL(ArraySizeOverflow) + // if the element count is negative, it's an overflow error + cmp r1, #0 + blt LOCAL_LABEL(ArraySizeOverflow) + + // Compute overall allocation size (align(base size + (element size * elements), 4)). + // if the element count is <= 0x10000, no overflow is possible because the component + // size is <= 0xffff (it's an unsigned 16-bit value) and thus the product is <= 0xffff0000 + // and the base size is only 12 bytes. + ldrh r2, [r0, #OFFSETOF__EEType__m_usComponentSize] + cmp r1, #0x10000 + bhi LOCAL_LABEL(ArraySizeBig) + umull r2, r3, r2, r1 + ldr r3, [r0, #OFFSETOF__EEType__m_uBaseSize] + adds r2, r3 + adds r2, #3 +LOCAL_LABEL(ArrayAlignSize): + bic r2, r2, #3 + + mov r4, r0 // save EEType + + // r0 = GetThread() + INLINE_GETTHREAD + + // r4 == EEType + // r1 == element count + // r2 == array size + // r0 == Thread* + + // Load potential new object address into r12. + ldr r12, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_ptr] + + // Determine whether the end of the object would lie outside of the current allocation context. If so, + // we abandon the attempt to allocate the object directly and fall back to the slow helper. + adds r2, r12 + bcs LOCAL_LABEL(RhpNewArray_RarePath) // if we get a carry here, the array is too large to fit below 4 GB + + ldr r12, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_limit] + cmp r2, r12 + bhi LOCAL_LABEL(RhpNewArray_RarePath) + + // Reload new object address into r12. + ldr r12, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_ptr] + + // Update the alloc pointer to account for the allocation. + str r2, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_ptr] + + // Set the new object's EEType pointer and element count. + str r4, [r12, #OFFSETOF__Object__m_pEEType] + str r1, [r12, #OFFSETOF__Array__m_Length] + + // Return the object allocated in r0. + mov r0, r12 + EPILOG_POP "{r4,pc}" + +LOCAL_LABEL(ArraySizeBig): + + // now we know the element count is in the signed int range [0..0x7fffffff] + // overflow in computing the total size of the array size gives an out of memory exception, + // NOT an overflow exception + // we already have the component size in r2 + umull r2, r3, r2, r1 + cbnz r3, LOCAL_LABEL(ArrayOutOfMemoryFinal) + ldr r3, [r4, #OFFSETOF__EEType__m_uBaseSize] + adds r2, r3 + bcs LOCAL_LABEL(ArrayOutOfMemoryFinal) + adds r2, #3 + bcs LOCAL_LABEL(ArrayOutOfMemoryFinal) + b LOCAL_LABEL(ArrayAlignSize) + +LOCAL_LABEL(ArrayOutOfMemoryFinal): + + mov r0, r4 // restore EEType + mov r1, #0 // Indicate that we should throw OOM. + EPILOG_POP "{r4,lr}" + b C_FUNC(RhExceptionHandling_FailedAllocation) + +LOCAL_LABEL(ArraySizeOverflow): + // We get here if the size of the final array object can't be represented as an unsigned + // 32-bit value. We're going to tail-call to a managed helper that will throw + // an overflow exception that the caller of this allocator understands. + + mov r0, r4 // restore EEType + mov r1, #1 // Indicate that we should throw OverflowException + EPILOG_POP "{r4,lr}" + b C_FUNC(RhExceptionHandling_FailedAllocation) + +LOCAL_LABEL(RhpNewArray_RarePath): + mov r0, r4 // restore EEType + mov r1, #0 + EPILOG_POP "{r4,lr}" + b C_FUNC(RhpNewArrayRare) + +LEAF_END RhpNewArray, _TEXT + // Allocate one dimensional, zero based array (SZARRAY) using the slow path that calls a runtime helper. // r0 == EEType // r1 == element count // r2 == array size + Thread::m_alloc_context::alloc_ptr // r3 == Thread - NESTED_ENTRY RhpNewArrayRare, _TEXT, NoHandler -#ifdef _DEBUG - GEN_ASSERT_FUNC RhpNewArrayRareName -#endif - NESTED_END RhpNewArrayRare, _TEXT +NESTED_ENTRY RhpNewArrayRare, _TEXT, NoHandler + + // Recover array size by subtracting the alloc_ptr from r2. + ldr r12, [r3, #OFFSETOF__Thread__m_alloc_context__alloc_ptr] + sub r2, r12 + + PUSH_COOP_PINVOKE_FRAME r3 + + // Preserve the EEType in r5 and element count in r6. + mov r5, r0 + mov r6, r1 + + mov r7, r2 // Save array size in r7 + + mov r1, #0 // uFlags + + // void* RhpGcAlloc(EEType *pEEType, UInt32 uFlags, UIntNative cbSize, void * pTransitionFrame) + blx C_FUNC(RhpGcAlloc) + + // Test for failure (NULL return). + cbz r0, LOCAL_LABEL(ArrayOutOfMemory) + + // Success, set the array's type and element count in the new object. + str r5, [r0, #OFFSETOF__Object__m_pEEType] + str r6, [r0, #OFFSETOF__Array__m_Length] + + // If the object is bigger than RH_LARGE_OBJECT_SIZE, we must publish it to the BGC + movw r2, #(RH_LARGE_OBJECT_SIZE & 0xFFFF) + movt r2, #(RH_LARGE_OBJECT_SIZE >> 16) + cmp r7, r2 + blo LOCAL_LABEL(NewArray_SkipPublish) + + // r0: already contains object + mov r1, r7 // r1: object size + bl C_FUNC(RhpPublishObject) + // r0: function returned the passed-in object + +LOCAL_LABEL(NewArray_SkipPublish): + + POP_COOP_PINVOKE_FRAME + bx lr + +LOCAL_LABEL(ArrayOutOfMemory): + + mov r0, r5 // EEType + mov r1, #0 // Indicate that we should throw OOM. + + POP_COOP_PINVOKE_FRAME + + b C_FUNC(RhExceptionHandling_FailedAllocation) + +NESTED_END RhpNewArrayRare, _TEXT // Allocate simple object (not finalizable, array or value type) on an 8 byte boundary. // r0 == EEType - LEAF_ENTRY RhpNewFastAlign8, _TEXT -#ifdef _DEBUG - GEN_ASSERT_FUNC RhpNewFastAlign8Name -#endif - LEAF_END RhpNewFastAlign8, _TEXT +LEAF_ENTRY RhpNewFastAlign8, _TEXT + PROLOG_PUSH "{r4,lr}" + + mov r4, r0 // save EEType + + // r0 = GetThread() + INLINE_GETTHREAD + + // Fetch object size into r2. + ldr r2, [r4, #OFFSETOF__EEType__m_uBaseSize] + + // r4: EEType pointer + // r0: Thread pointer + // r2: base size + + // Load potential new object address into r3. Cache this result in r12 as well for the common case + // where the allocation succeeds (r3 will be overwritten in the following bounds check). + ldr r3, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_ptr] + mov r12, r3 + + // Check whether the current allocation context is already aligned for us. + tst r3, #0x7 + bne LOCAL_LABEL(Alloc8Failed) + + // Determine whether the end of the object would lie outside of the current allocation context. If so, + // we abandon the attempt to allocate the object directly and fall back to the slow helper. + add r2, r3 + ldr r3, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_limit] + cmp r2, r3 + bhi LOCAL_LABEL(Alloc8Failed) + + // Update the alloc pointer to account for the allocation. + str r2, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_ptr] + + // Set the new object's EEType pointer. + str r4, [r12, #OFFSETOF__Object__m_pEEType] + + // Return the object allocated in r0. + mov r0, r12 + + EPILOG_POP "{r4,pc}" + +LOCAL_LABEL(Alloc8Failed): + // Fast allocation failed. Call slow helper with flags set to indicate an 8-byte alignment and no + // finalization. + mov r0, r4 // restore EEType + mov r1, #GC_ALLOC_ALIGN8 + EPILOG_POP "{r4,lr}" + b C_FUNC(RhpNewObject) + +LEAF_END RhpNewFastAlign8, _TEXT // Allocate a finalizable object (by definition not an array or value type) on an 8 byte boundary. // r0 == EEType - LEAF_ENTRY RhpNewFinalizableAlign8, _TEXT -#ifdef _DEBUG - GEN_ASSERT_FUNC RhpNewFinalizableAlign8Name -#endif - LEAF_END RhpNewFinalizableAlign8, _TEXT +LEAF_ENTRY RhpNewFinalizableAlign8, _TEXT + mov r1, #(GC_ALLOC_FINALIZE | GC_ALLOC_ALIGN8) + b C_FUNC(RhpNewObject) +LEAF_END RhpNewFinalizableAlign8, _TEXT // Allocate a value type object (i.e. box it) on an 8 byte boundary + 4 (so that the value type payload // itself is 8 byte aligned). // r0 == EEType - LEAF_ENTRY RhpNewFastMisalign, _TEXT -#ifdef _DEBUG - GEN_ASSERT_FUNC RhpNewFastMisalignName -#endif - LEAF_END RhpNewFastMisalign, _TEXT +LEAF_ENTRY RhpNewFastMisalign, _TEXT + PROLOG_PUSH "{r4,lr}" + + mov r4, r0 // save EEType + + // r0 = GetThread() + INLINE_GETTHREAD + + // Fetch object size into r2. + ldr r2, [r4, #OFFSETOF__EEType__m_uBaseSize] + + // r4: EEType pointer + // r0: Thread pointer + // r2: base size + + // Load potential new object address into r3. Cache this result in r12 as well for the common case + // where the allocation succeeds (r3 will be overwritten in the following bounds check). + ldr r3, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_ptr] + mov r12, r3 + + // Check whether the current allocation context is already aligned for us (for boxing that means the + // address % 8 == 4, so the value type payload following the EEType* is actually 8-byte aligned). + tst r3, #0x7 + beq LOCAL_LABEL(BoxAlloc8Failed) + + // Determine whether the end of the object would lie outside of the current allocation context. If so, + // we abandon the attempt to allocate the object directly and fall back to the slow helper. + add r2, r3 + ldr r3, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_limit] + cmp r2, r3 + bhi LOCAL_LABEL(BoxAlloc8Failed) + + // Update the alloc pointer to account for the allocation. + str r2, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_ptr] + + // Set the new object's EEType pointer. + str r4, [r12, #OFFSETOF__Object__m_pEEType] + + // Return the object allocated in r0. + mov r0, r12 + + EPILOG_POP "{r4,pc}" + +LOCAL_LABEL(BoxAlloc8Failed): + // Fast allocation failed. Call slow helper with flags set to indicate an 8+4 byte alignment and no + // finalization. + mov r0, r4 // restore EEType + mov r1, #(GC_ALLOC_ALIGN8 | GC_ALLOC_ALIGN8_BIAS) + EPILOG_POP "{r4,pc}" + b C_FUNC(RhpNewObject) + +LEAF_END RhpNewFastMisalign, _TEXT // Allocate an array on an 8 byte boundary. // r0 == EEType // r1 == element count - NESTED_ENTRY RhpNewArrayAlign8, _TEXT, NoHandler -#ifdef _DEBUG - GEN_ASSERT_FUNC RhpNewArrayAlign8Name -#endif - NESTED_END RhpNewArrayAlign8, _TEXT +NESTED_ENTRY RhpNewArrayAlign8, _TEXT, NoHandler + + PUSH_COOP_PINVOKE_FRAME r3 + + // Compute overall allocation size (base size + align((element size * elements), 4)). + ldrh r2, [r0, #OFFSETOF__EEType__m_usComponentSize] + umull r2, r4, r2, r1 + cbnz r4, LOCAL_LABEL(Array8SizeOverflow) + adds r2, #3 + bcs LOCAL_LABEL(Array8SizeOverflow) + bic r2, r2, #3 + ldr r4, [r0, #OFFSETOF__EEType__m_uBaseSize] + adds r2, r4 + bcs LOCAL_LABEL(Array8SizeOverflow) + + // Preserve the EEType in r5 and element count in r6. + mov r5, r0 + mov r6, r1 + mov r7, r2 // Save array size in r7 + + mov r1, #GC_ALLOC_ALIGN8 // uFlags + + // void* RhpGcAlloc(EEType *pEEType, UInt32 uFlags, UIntNative cbSize, void * pTransitionFrame) + blx C_FUNC(RhpGcAlloc) + + // Test for failure (NULL return). + cbz r0, LOCAL_LABEL(Array8OutOfMemory) + + // Success, set the array's type and element count in the new object. + str r5, [r0, #OFFSETOF__Object__m_pEEType] + str r6, [r0, #OFFSETOF__Array__m_Length] + + // If the object is bigger than RH_LARGE_OBJECT_SIZE, we must publish it to the BGC + movw r2, #(RH_LARGE_OBJECT_SIZE & 0xFFFF) + movt r2, #(RH_LARGE_OBJECT_SIZE >> 16) + cmp r7, r2 + blo LOCAL_LABEL(NewArray8_SkipPublish) + + // r0: already contains object + mov r1, r7 // r1: object size + bl C_FUNC(RhpPublishObject) + // r0: function returned the passed-in object +LOCAL_LABEL(NewArray8_SkipPublish): + + POP_COOP_PINVOKE_FRAME + + bx lr + +LOCAL_LABEL(Array8SizeOverflow): + // We get here if the size of the final array object can't be represented as an unsigned + // 32-bit value. We're going to tail-call to a managed helper that will throw + // an OOM or overflow exception that the caller of this allocator understands. + + // if the element count is non-negative, it's an OOM error + cmp r1, #0 + bge Array8OutOfMemory1 + + // r0 holds EEType pointer already + mov r1, #1 // Indicate that we should throw OverflowException + + POP_COOP_PINVOKE_FRAME + b C_FUNC(RhExceptionHandling_FailedAllocation) + +LOCAL_LABEL(Array8OutOfMemory): + // This is the OOM failure path. We're going to tail-call to a managed helper that will throw + // an out of memory exception that the caller of this allocator understands. + + mov r0, r5 // EEType pointer + +LOCAL_LABEL(Array8OutOfMemory1): + + mov r1, #0 // Indicate that we should throw OOM. + + POP_COOP_PINVOKE_FRAME + b C_FUNC(RhExceptionHandling_FailedAllocation) + +NESTED_END RhpNewArrayAlign8, _TEXT diff --git a/src/Native/Runtime/arm/CallDescrWorker.S b/src/Native/Runtime/arm/CallDescrWorker.S index 26768253d..3c1e81ad1 100644 --- a/src/Native/Runtime/arm/CallDescrWorker.S +++ b/src/Native/Runtime/arm/CallDescrWorker.S @@ -2,44 +2,20 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#include <unixasmmacros.inc> - .syntax unified .thumb -#ifdef _DEBUG -.rodata -AssertMsg: .asciz "__FILE__:%s: %s is not implemented\n" -FileName: .asciz "CallDescrWorker.S" -RhCallDescrWorkerName: .asciz "RhCallDescrWorker" -PointerToReturnFromCallDescrThunkName: .asciz "PointerToReturnFromCallDescrThunk" - -.text -.macro GEN_ASSERT_FUNC func - GEN_ASSERT AssertMsg, FileName, \func -.endm -#endif +#include <unixasmmacros.inc> +#include <AsmOffsets.inc> // generated by the build from AsmOffsets.cpp // TODO: Implement Arm support NESTED_ENTRY RhCallDescrWorker, _TEXT, NoHandler LOCAL_LABEL(ReturnFromCallDescrThunk): - // UNIXTODO: Implement this function - // int 3 -#ifdef _DEBUG - GEN_ASSERT_FUNC RhCallDescrWorkerName -#endif -NESTED_END RhCallDescrWorker, _TEXT + EXPORT_POINTER_TO_ADDRESS PointerToReturnFromCallDescrThunk -//.text -//.align 8 -//C_FUNC(PointerToReturnFromCallDescrThunk): -//.quad LOCAL_LABEL(ReturnFromCallDescrThunk) -//.global C_FUNC(PointerToReturnFromCallDescrThunk) + // UNIXTODO: Implement this function + EMIT_BREAKPOINT +NESTED_END RhCallDescrWorker, _TEXT -LEAF_ENTRY PointerToReturnFromCallDescrThunk, _TEXT -#ifdef _DEBUG - GEN_ASSERT_FUNC PointerToReturnFromCallDescrThunk -#endif -LEAF_END PointerToReturnFromCallDescrThunk, _TEXT |