mirror of
https://github.com/VSadov/Satori.git
synced 2025-06-08 03:27:04 +09:00
Delete Windows arm32 support (#86065)
This commit is contained in:
parent
0b5f137ab0
commit
418aa8ab6b
32 changed files with 21 additions and 3084 deletions
|
@ -41,7 +41,6 @@
|
|||
"Microsoft.VisualStudio.Component.VC.CMake.Project",
|
||||
"Microsoft.VisualStudio.Component.VC.CoreIde",
|
||||
"Microsoft.VisualStudio.Component.VC.Redist.14.Latest",
|
||||
"Microsoft.VisualStudio.Component.VC.Tools.ARM",
|
||||
"Microsoft.VisualStudio.Component.VC.Tools.ARM64",
|
||||
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
||||
"Microsoft.VisualStudio.Component.Windows10SDK.19041",
|
||||
|
|
|
@ -29,7 +29,6 @@ All builds are
|
|||
- Windows 10 x64 Client VS2019
|
||||
- x64 Release
|
||||
- x86 Release
|
||||
- arm32 Release
|
||||
- arm64 Release
|
||||
- Ubuntu 18.04 x64
|
||||
- Linux x64 Release
|
||||
|
|
|
@ -17,8 +17,8 @@ The repo can be built for the following platforms, using the provided setup and
|
|||
| :---- | :------: | :------: | :------: | :------: |
|
||||
| x64 | ✔ | ✔ | ✔ | ✔ |
|
||||
| x86 | ✔ | | | |
|
||||
| ARM | ✔ | ✔ | | |
|
||||
| ARM64 | ✔ | ✔ | ✔ | |
|
||||
| Arm32 | | ✔ | | |
|
||||
| Arm64 | ✔ | ✔ | ✔ | |
|
||||
| | [Requirements](requirements/windows-requirements.md) | [Requirements](requirements/linux-requirements.md) | [Requirements](requirements/macos-requirements.md) | [Requirements](requirements/freebsd-requirements.md)
|
||||
|
||||
Additionally, keep in mind that cloning the full history of this repo takes roughly 400-500 MB of network transfer, inflating to a repository that can consume somewhere between 1 to 1.5 GB. A build of the repo can take somewhere between 10 and 20 GB of space for a single OS and Platform configuration depending on the portions of the product built. This might increase over time, so consider this to be a minimum bar for working with this codebase.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Cross-Building for Different Architectures and Operating Systems
|
||||
|
||||
* [Windows Cross-Building](#windows-cross-building)
|
||||
* [Cross-Compiling for ARM32 and ARM64 on Windows](#cross-compiling-for-arm32-and-arm64-on-windows)
|
||||
* [Cross-Compiling for ARM64 on Windows](#cross-compiling-for-arm64-on-windows)
|
||||
* [Cross-Compiling for x86 on Windows](#cross-compiling-for-x86-on-windows)
|
||||
* [macOS Cross-Building](#macos-cross-building)
|
||||
* [Linux Cross-Building](#linux-cross-building)
|
||||
|
@ -21,9 +21,9 @@ This guide will go more in-depth on how to do cross-building across multiple ope
|
|||
|
||||
This section will go over cross-compiling on Windows. Currently, Windows allows you to cross-compile from x64 to basically any other architecture.
|
||||
|
||||
### Cross-Compiling for ARM32 and ARM64 on Windows
|
||||
### Cross-Compiling for ARM64 on Windows
|
||||
|
||||
To do cross-compilation for ARM32/ARM64 on Windows, first make sure you have the appropriate tools and Windows SDK installed. This is described in detail in the [Windows requirements doc](/docs/workflow/requirements/windows-requirements.md#visual-studio).
|
||||
To do cross-compilation for ARM64 on Windows, first make sure you have the appropriate tools and Windows SDK installed. This is described in detail in the [Windows requirements doc](/docs/workflow/requirements/windows-requirements.md#visual-studio).
|
||||
|
||||
Once you have all the required dependencies, it is a straightforward process. Windows knows how to cross-build behind curtains, so all you have to do is specify which architecture you want to build for:
|
||||
|
||||
|
|
|
@ -35,8 +35,7 @@ Install [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/). The
|
|||
* It's recommended to use **Workloads** installation approach. The following are the minimum requirements:
|
||||
* **.NET Desktop Development** with all default components,
|
||||
* **Desktop Development with C++** with all default components.
|
||||
* To build for Arm32 or Arm64, make sure that you have the right architecture-specific compilers installed. In the **Individual components** window, in the **Compilers, build tools, and runtimes** section:
|
||||
* For Arm32, check the box for _MSVC v143* VS 2022 C++ ARM build tools (Latest)_.
|
||||
* To build for Arm64, make sure that you have the right architecture-specific compilers installed. In the **Individual components** window, in the **Compilers, build tools, and runtimes** section:
|
||||
* For Arm64, check the box for _MSVC v143* VS 2022 C++ ARM64 build tools (Latest)_.
|
||||
* To build the tests, you will need some additional components:
|
||||
* **C++/CLI support for v142 build tools (Latest)**.
|
||||
|
|
|
@ -267,19 +267,6 @@
|
|||
Category="clr" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="(('$(ClrRuntimeBuildSubsets)' != '' and '$(PrimaryRuntimeFlavor)' == 'CoreCLR' and '$(TargetsMobile)' != 'true') or $(_subset.Contains('+clr.crossarchtools+'))) and $([MSBuild]::IsOsPlatform(Windows)) and '$(TargetArchitecture)' == 'arm' and '$(BuildArchitecture)' == 'x64'">
|
||||
<ProjectToBuild
|
||||
Include="$(CoreClrProjectRoot)runtime.proj"
|
||||
AdditionalProperties="%(AdditionalProperties);
|
||||
ClrCrossComponentsSubset=true;
|
||||
HostArchitecture=x86;
|
||||
PgoInstrument=false;
|
||||
NoPgoOptimize=true;
|
||||
CrossBuild=false;
|
||||
CMakeArgs=$(CMakeArgs) -DCLR_CROSS_COMPONENTS_BUILD=1"
|
||||
Category="clr" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="$(_subset.Contains('+clr.paltestlist+'))">
|
||||
<ProjectToBuild Include="$(CoreClrProjectRoot)pal/tests/palsuite/producepaltestlist.proj" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -72,7 +72,6 @@ jobs:
|
|||
IntermediateArtifacts/MonoRuntimePacks/Shipping/Microsoft.NET.Runtime.WebAssembly.Sdk*.nupkg
|
||||
IntermediateArtifacts/MonoRuntimePacks/Shipping/Microsoft.NET.Runtime.WebAssembly.Wasi*.nupkg
|
||||
IntermediateArtifacts/MonoRuntimePacks/Shipping/Microsoft.NET.Runtime.WebAssembly.Templates*.nupkg
|
||||
IntermediateArtifacts/windows_arm/Shipping/Microsoft.NETCore.App.Runtime.win-arm*.nupkg
|
||||
IntermediateArtifacts/windows_arm64/Shipping/Microsoft.NETCore.App.Runtime.win-arm64*.nupkg
|
||||
IntermediateArtifacts/windows_x64/Shipping/Microsoft.NETCore.App.Runtime.win-x64*.nupkg
|
||||
IntermediateArtifacts/windows_x86/Shipping/Microsoft.NETCore.App.Runtime.win-x86*.nupkg
|
||||
|
|
|
@ -50,29 +50,6 @@
|
|||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "msvc_x86" ]
|
||||
},
|
||||
{
|
||||
"name": "windows.arm.Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${env.artifactsObj}\\${name}",
|
||||
"installRoot": "${env.artifactsBin}\\${name}",
|
||||
"cmakeCommandArgs": "-DCLR_CMAKE_HOST_ARCH=arm",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "msvc_arm" ]
|
||||
},
|
||||
{
|
||||
"name": "windows.arm.Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Release",
|
||||
"buildRoot": "${env.artifactsObj}\\${name}",
|
||||
"installRoot": "${env.artifactsBin}\\${name}",
|
||||
"cmakeCommandArgs": "-DCLR_CMAKE_HOST_ARCH=arm",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "msvc_arm" ],
|
||||
"variables": []
|
||||
},
|
||||
{
|
||||
"name": "windows.arm64.Debug",
|
||||
"generator": "Ninja",
|
||||
|
@ -98,4 +75,4 @@
|
|||
"variables": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,6 @@ set __BuildAll=
|
|||
|
||||
set __TargetArchX64=0
|
||||
set __TargetArchX86=0
|
||||
set __TargetArchArm=0
|
||||
set __TargetArchArm64=0
|
||||
|
||||
set __BuildTypeDebug=0
|
||||
|
@ -87,7 +86,6 @@ if /i "%1" == "--help" goto Usage
|
|||
if /i "%1" == "-all" (set __BuildAll=1&shift&goto Arg_Loop)
|
||||
if /i "%1" == "-x64" (set __TargetArchX64=1&shift&goto Arg_Loop)
|
||||
if /i "%1" == "-x86" (set __TargetArchX86=1&shift&goto Arg_Loop)
|
||||
if /i "%1" == "-arm" (set __TargetArchArm=1&shift&goto Arg_Loop)
|
||||
if /i "%1" == "-arm64" (set __TargetArchArm64=1&shift&goto Arg_Loop)
|
||||
|
||||
if /i "%1" == "-debug" (set __BuildTypeDebug=1&shift&goto Arg_Loop)
|
||||
|
@ -101,7 +99,6 @@ REM don't add more, use the - syntax instead
|
|||
if /i "%1" == "all" (set __BuildAll=1&shift&goto Arg_Loop)
|
||||
if /i "%1" == "x64" (set __TargetArchX64=1&shift&goto Arg_Loop)
|
||||
if /i "%1" == "x86" (set __TargetArchX86=1&shift&goto Arg_Loop)
|
||||
if /i "%1" == "arm" (set __TargetArchArm=1&shift&goto Arg_Loop)
|
||||
if /i "%1" == "arm64" (set __TargetArchArm64=1&shift&goto Arg_Loop)
|
||||
|
||||
if /i "%1" == "debug" (set __BuildTypeDebug=1&shift&goto Arg_Loop)
|
||||
|
@ -165,7 +162,7 @@ if defined VCINSTALLDIR (
|
|||
|
||||
if defined __BuildAll goto BuildAll
|
||||
|
||||
set /A __TotalSpecifiedTargetArch=__TargetArchX64 + __TargetArchX86 + __TargetArchArm + __TargetArchArm64
|
||||
set /A __TotalSpecifiedTargetArch=__TargetArchX64 + __TargetArchX86 + __TargetArchArm64
|
||||
if %__TotalSpecifiedTargetArch% GTR 1 (
|
||||
echo Error: more than one build architecture specified, but "all" not specified.
|
||||
goto Usage
|
||||
|
@ -176,7 +173,6 @@ if "%__ProcessorArch%"=="" set __ProcessorArch=%PROCESSOR_ARCHITECTURE%
|
|||
|
||||
if %__TargetArchX64%==1 set __TargetArch=x64
|
||||
if %__TargetArchX86%==1 set __TargetArch=x86
|
||||
if %__TargetArchArm%==1 set __TargetArch=arm
|
||||
if %__TargetArchArm64%==1 set __TargetArch=arm64
|
||||
if "%__HostArch%" == "" set __HostArch=%__TargetArch%
|
||||
|
||||
|
@ -191,10 +187,6 @@ if %__BuildTypeChecked%==1 set __BuildType=Checked
|
|||
if %__BuildTypeRelease%==1 set __BuildType=Release
|
||||
|
||||
if %__EnforcePgo%==1 (
|
||||
if %__TargetArchArm%==1 (
|
||||
echo NOTICE: enforcepgo does nothing on arm architecture
|
||||
set __EnforcePgo=0
|
||||
)
|
||||
if %__TargetArchArm64%==1 (
|
||||
echo NOTICE: enforcepgo does nothing on arm64 architecture
|
||||
set __EnforcePgo=0
|
||||
|
@ -451,7 +443,7 @@ REM ============================================================================
|
|||
|
||||
set __TargetArchList=
|
||||
|
||||
set /A __TotalSpecifiedTargetArch=__TargetArchX64 + __TargetArchX86 + __TargetArchArm + __TargetArchArm64
|
||||
set /A __TotalSpecifiedTargetArch=__TargetArchX64 + __TargetArchX86 + __TargetArchArm64
|
||||
if %__TotalSpecifiedTargetArch% EQU 0 (
|
||||
REM Nothing specified means we want to build all architectures.
|
||||
set __TargetArchList=x64 x86 arm arm64
|
||||
|
@ -461,7 +453,6 @@ REM Otherwise, add all the specified architectures to the list.
|
|||
|
||||
if %__TargetArchX64%==1 set __TargetArchList=%__TargetArchList% x64
|
||||
if %__TargetArchX86%==1 set __TargetArchList=%__TargetArchList% x86
|
||||
if %__TargetArchArm%==1 set __TargetArchList=%__TargetArchList% arm
|
||||
if %__TargetArchArm64%==1 set __TargetArchList=%__TargetArchList% arm64
|
||||
|
||||
set __BuildTypeList=
|
||||
|
@ -545,7 +536,7 @@ echo All arguments are optional. The options are:
|
|||
echo.
|
||||
echo.-? -h -help --help: view this message.
|
||||
echo -all: Builds all configurations and platforms.
|
||||
echo Build architecture: one of -x64, -x86, -arm, -arm64 ^(default: -x64^).
|
||||
echo Build architecture: one of -x64, -x86, -arm64 ^(default: -x64^).
|
||||
echo Build type: one of -Debug, -Checked, -Release ^(default: -Debug^).
|
||||
echo -component ^<name^> : specify this option one or more times to limit components built to those specified.
|
||||
echo Allowed ^<name^>: hosts jit alljits runtime paltests iltools nativeaot spmi
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
; Licensed to the .NET Foundation under one or more agreements.
|
||||
; The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#include "ksarm.h"
|
||||
|
||||
;; Arguments
|
||||
;; input: (in R0) the address of the ULONGLONG to be converted to a double
|
||||
;; output: the double corresponding to the ULONGLONG input value
|
||||
|
||||
LEAF_ENTRY FPFillR8
|
||||
vldr D0, [R0]
|
||||
bx lr
|
||||
LEAF_END
|
||||
|
||||
|
||||
;; Must be at very end of file
|
||||
END
|
|
@ -1,89 +0,0 @@
|
|||
; Licensed to the .NET Foundation under one or more agreements.
|
||||
; The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#include "ksarm.h"
|
||||
#include "asmconstants.h"
|
||||
|
||||
IMPORT FuncEvalHijackWorker
|
||||
IMPORT FuncEvalHijackPersonalityRoutine
|
||||
IMPORT ExceptionHijackWorker
|
||||
IMPORT ExceptionHijackPersonalityRoutine
|
||||
EXPORT ExceptionHijackEnd
|
||||
|
||||
MACRO
|
||||
CHECK_STACK_ALIGNMENT
|
||||
|
||||
#ifdef _DEBUG
|
||||
push {r0}
|
||||
add r0, sp, #4
|
||||
tst r0, #7
|
||||
pop {r0}
|
||||
beq %0
|
||||
EMIT_BREAKPOINT
|
||||
0
|
||||
#endif
|
||||
MEND
|
||||
|
||||
TEXTAREA
|
||||
|
||||
;
|
||||
; hijacking stub used to perform a func-eval, see Debugger::FuncEvalSetup() for use.
|
||||
;
|
||||
; on entry:
|
||||
; r0 : pointer to DebuggerEval object
|
||||
;
|
||||
|
||||
NESTED_ENTRY FuncEvalHijack,,FuncEvalHijackPersonalityRoutine
|
||||
|
||||
; NOTE: FuncEvalHijackPersonalityRoutine is dependent on the stack layout so if
|
||||
; you change the prolog you will also need to update the personality routine.
|
||||
|
||||
; push arg to the stack so our personality routine can find it
|
||||
; push lr to get good stacktrace in debugger
|
||||
PROLOG_PUSH {r0,lr}
|
||||
|
||||
CHECK_STACK_ALIGNMENT
|
||||
|
||||
; FuncEvalHijackWorker returns the address we should jump to.
|
||||
bl FuncEvalHijackWorker
|
||||
|
||||
; effective NOP to terminate unwind
|
||||
mov r2, r2
|
||||
|
||||
EPILOG_STACK_FREE 8
|
||||
EPILOG_BRANCH_REG r0
|
||||
|
||||
NESTED_END FuncEvalHijack
|
||||
|
||||
;
|
||||
; This is the general purpose hijacking stub. DacDbiInterfaceImpl::Hijack() will
|
||||
; set the registers with the appropriate parameters from out-of-process.
|
||||
;
|
||||
; on entry:
|
||||
; r0 : pointer to CONTEXT
|
||||
; r1 : pointer to EXCEPTION_RECORD
|
||||
; r2 : EHijackReason
|
||||
; r3 : void* pdata
|
||||
;
|
||||
|
||||
NESTED_ENTRY ExceptionHijack,,ExceptionHijackPersonalityRoutine
|
||||
|
||||
CHECK_STACK_ALIGNMENT
|
||||
|
||||
; make the call
|
||||
bl ExceptionHijackWorker
|
||||
|
||||
; effective NOP to terminate unwind
|
||||
mov r3, r3
|
||||
|
||||
; *** should never get here ***
|
||||
EMIT_BREAKPOINT
|
||||
|
||||
; exported label so the debugger knows where the end of this function is
|
||||
ExceptionHijackEnd
|
||||
NESTED_END
|
||||
|
||||
|
||||
; must be at end of file
|
||||
END
|
||||
|
|
@ -187,8 +187,6 @@ if(CLR_CMAKE_TARGET_WIN32)
|
|||
set(CLRDEBUGINFO_RESOURCE_NAME CLRDEBUGINFOWINDOWSX86)
|
||||
elseif(CLR_CMAKE_TARGET_ARCH_ARM64)
|
||||
set(CLRDEBUGINFO_RESOURCE_NAME CLRDEBUGINFOWINDOWSARM64)
|
||||
elseif(CLR_CMAKE_TARGET_ARCH_ARM)
|
||||
set(CLRDEBUGINFO_RESOURCE_NAME CLRDEBUGINFOWINDOWSARM)
|
||||
endif(CLR_CMAKE_TARGET_ARCH_AMD64)
|
||||
|
||||
add_custom_target(
|
||||
|
|
|
@ -123,7 +123,7 @@ static PTR_VOID GetUnwindDataBlob(TADDR moduleBase, PTR_RUNTIME_FUNCTION pRuntim
|
|||
|
||||
return pUnwindInfo;
|
||||
|
||||
#elif defined(TARGET_ARM) || defined(TARGET_ARM64)
|
||||
#elif defined(TARGET_ARM64)
|
||||
|
||||
// if this function uses packed unwind data then at least one of the two least significant bits
|
||||
// will be non-zero. if this is the case then there will be no xdata record to enumerate.
|
||||
|
@ -133,15 +133,9 @@ static PTR_VOID GetUnwindDataBlob(TADDR moduleBase, PTR_RUNTIME_FUNCTION pRuntim
|
|||
PTR_UInt32 xdata = dac_cast<PTR_UInt32>(pRuntimeFunction->UnwindData + moduleBase);
|
||||
int size = 4;
|
||||
|
||||
#if defined(TARGET_ARM)
|
||||
// See https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
|
||||
int unwindWords = xdata[0] >> 28;
|
||||
int epilogScopes = (xdata[0] >> 23) & 0x1f;
|
||||
#else
|
||||
// See https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
|
||||
int unwindWords = xdata[0] >> 27;
|
||||
int epilogScopes = (xdata[0] >> 22) & 0x1f;
|
||||
#endif
|
||||
|
||||
if (unwindWords == 0 && epilogScopes == 0)
|
||||
{
|
||||
|
@ -191,10 +185,6 @@ static int LookupUnwindInfoForMethod(uint32_t relativePc,
|
|||
int low,
|
||||
int high)
|
||||
{
|
||||
#ifdef TARGET_ARM
|
||||
relativePc |= THUMB_CODE;
|
||||
#endif
|
||||
|
||||
// Binary search the RUNTIME_FUNCTION table
|
||||
// Use linear search once we get down to a small number of elements
|
||||
// to avoid Binary search overhead.
|
||||
|
@ -504,7 +494,7 @@ uintptr_t CoffNativeCodeManager::GetConservativeUpperBoundForOutgoingArgs(Method
|
|||
upperBound = dac_cast<TADDR>(pRegisterSet->GetFP() - ((PTR_UNWIND_INFO) pUnwindDataBlob)->FrameOffset);
|
||||
}
|
||||
|
||||
#elif defined(TARGET_ARM) || defined(TARGET_ARM64)
|
||||
#elif defined(TARGET_ARM64)
|
||||
// Unwind the current method context to get the caller's stack pointer
|
||||
// and use it as the upper bound for the callee
|
||||
SIZE_T EstablisherFrame;
|
||||
|
@ -733,9 +723,9 @@ bool CoffNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn
|
|||
|
||||
// Decode the GC info for the current method to determine its return type
|
||||
GcInfoDecoderFlags flags = DECODE_RETURN_KIND;
|
||||
#if defined(TARGET_ARM) || defined(TARGET_ARM64)
|
||||
#if defined(TARGET_ARM64)
|
||||
flags = (GcInfoDecoderFlags)(flags | DECODE_HAS_TAILCALLS);
|
||||
#endif // TARGET_ARM || TARGET_ARM64
|
||||
#endif // TARGET_ARM64
|
||||
GcInfoDecoder decoder(GCInfoToken(p), flags);
|
||||
|
||||
*pRetValueKind = GetGcRefKind(decoder.GetReturnKind());
|
||||
|
|
|
@ -9,11 +9,6 @@ struct T_RUNTIME_FUNCTION {
|
|||
uint32_t EndAddress;
|
||||
uint32_t UnwindInfoAddress;
|
||||
};
|
||||
#elif defined(TARGET_ARM)
|
||||
struct T_RUNTIME_FUNCTION {
|
||||
uint32_t BeginAddress;
|
||||
uint32_t UnwindData;
|
||||
};
|
||||
#elif defined(TARGET_ARM64)
|
||||
struct T_RUNTIME_FUNCTION {
|
||||
uint32_t BeginAddress;
|
||||
|
|
|
@ -673,19 +673,6 @@ elseif(CLR_CMAKE_TARGET_ARCH_I386)
|
|||
${ARCH_SOURCES_DIR}/thunktemplates.asm
|
||||
)
|
||||
|
||||
set(VM_HEADERS_WKS_ARCH_ASM
|
||||
${ARCH_SOURCES_DIR}/asmconstants.h
|
||||
)
|
||||
elseif(CLR_CMAKE_TARGET_ARCH_ARM)
|
||||
set(VM_SOURCES_WKS_ARCH_ASM
|
||||
${ARCH_SOURCES_DIR}/asmhelpers.asm
|
||||
${ARCH_SOURCES_DIR}/CrtHelpers.asm
|
||||
${ARCH_SOURCES_DIR}/ehhelpers.asm
|
||||
${ARCH_SOURCES_DIR}/patchedcode.asm
|
||||
${ARCH_SOURCES_DIR}/PInvokeStubs.asm
|
||||
${ARCH_SOURCES_DIR}/thunktemplates.asm
|
||||
)
|
||||
|
||||
set(VM_HEADERS_WKS_ARCH_ASM
|
||||
${ARCH_SOURCES_DIR}/asmconstants.h
|
||||
)
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
; Licensed to the .NET Foundation under one or more agreements.
|
||||
; The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
; ***********************************************************************
|
||||
; File: CrtHelpers.asm
|
||||
;
|
||||
; ***********************************************************************
|
||||
|
||||
#include "ksarm.h"
|
||||
|
||||
#include "asmconstants.h"
|
||||
|
||||
#include "asmmacros.h"
|
||||
|
||||
TEXTAREA
|
||||
|
||||
; JIT_MemSet/JIT_MemCpy
|
||||
;
|
||||
; It is IMPORANT that the exception handling code is able to find these guys
|
||||
; on the stack, but to keep them from being tailcalled by VC++ we need to turn
|
||||
; off optimization and it ends up being a wasteful implementation.
|
||||
;
|
||||
; Hence these assembly helpers.
|
||||
;
|
||||
;EXTERN_C void __stdcall JIT_MemSet(void* _dest, int c, size_t count)
|
||||
LEAF_ENTRY JIT_MemSet
|
||||
|
||||
;
|
||||
; The memset function sets the first count bytes of
|
||||
; dest to the character c (r1).
|
||||
;
|
||||
; Doesn't return a value
|
||||
;
|
||||
|
||||
subs r2, r2, #4
|
||||
blt ByteSet
|
||||
|
||||
ands r1, r1, #&FF
|
||||
orr r1, r1, r1, lsl #8
|
||||
CheckAlign ; 2-3 cycles
|
||||
ands r3, r0, #3 ; Check alignment and fix if possible
|
||||
bne Align
|
||||
|
||||
BlockSet ; 6-7 cycles
|
||||
orr r1, r1, r1, lsl #16
|
||||
subs r2, r2, #12
|
||||
mov r3, r1
|
||||
blt BlkSet8
|
||||
|
||||
BlkSet16 ; 7 cycles/16 bytes
|
||||
stm r0!, {r1, r3}
|
||||
subs r2, r2, #16
|
||||
stm r0!, {r1, r3}
|
||||
bge BlkSet16
|
||||
|
||||
BlkSet8 ; 4 cycles/8 bytes
|
||||
adds r2, r2, #8
|
||||
blt BlkSet4
|
||||
stm r0!, {r1, r3}
|
||||
sub r2, r2, #8
|
||||
|
||||
BlkSet4
|
||||
adds r2, r2, #4 ; 4 cycles/4 bytes
|
||||
blt ByteSet
|
||||
str r1, [r0], #4
|
||||
b MaybeExit
|
||||
|
||||
ByteSet
|
||||
adds r2, r2, #4
|
||||
MaybeExit
|
||||
beq ExitMemSet
|
||||
|
||||
strb r1, [r0] ; 5 cycles/1-3bytes
|
||||
cmp r2, #2
|
||||
blt ExitMemSet
|
||||
strb r1, [r0, #1]
|
||||
strbgt r1, [r0, #2]
|
||||
|
||||
ExitMemSet
|
||||
|
||||
bx lr
|
||||
|
||||
Align ; 8 cycles/1-3 bytes
|
||||
tst r0, #1 ; Check byte alignment
|
||||
beq AlignHalf
|
||||
subs r2, r2, #1
|
||||
strb r1, [r0], #1
|
||||
AlignHalf
|
||||
tst r0, #2 ; Check Half-word alignment
|
||||
beq BlockSet
|
||||
subs r2, r2, #2
|
||||
strh r1, [r0], #2
|
||||
b BlockSet
|
||||
|
||||
LEAF_END_MARKED JIT_MemSet
|
||||
|
||||
|
||||
;EXTERN_C void __stdcall JIT_MemCpy(void* _dest, const void *_src, size_t count)
|
||||
LEAF_ENTRY JIT_MemCpy
|
||||
;
|
||||
; It only requires 4 byte alignment
|
||||
; and doesn't return a value
|
||||
|
||||
cmp r2, #0 ; quick check for 0 length
|
||||
beq ExitMemCpy ; if zero, exit
|
||||
|
||||
tst r0, #3 ; skip directly to aligned if already aligned
|
||||
beq DestAligned ; if 0, we're already aligned; go large
|
||||
|
||||
ByteLoop1
|
||||
subs r2, r2, #1 ; decrement byte counter
|
||||
ldrb r3, [r1], #1 ; copy one byte
|
||||
strb r3, [r0], #1
|
||||
beq ExitMemCpy ; if the byte counter hits 0, exit early
|
||||
tst r0, #3 ; are we aligned now?
|
||||
bne ByteLoop1 ; nope, keep going
|
||||
|
||||
DestAligned
|
||||
subs r2, r2, #8 ; byte counter -= 8
|
||||
blt AlignedFinished ; if that puts us negative, skip the big copy
|
||||
|
||||
tst r1, #3 ; is the 4-byte source aligned?
|
||||
addne r2, r2, #8 ; if not, fix the byte counter (+= 8)
|
||||
bne ByteLoop2 ; and do all the rest with bytes
|
||||
|
||||
QwordLoop
|
||||
subs r2, r2, #8 ; decrement byte counter by 8
|
||||
ldm r1!, {r3,r12} ; copy one qword
|
||||
stm r0!, {r3,r12} ;
|
||||
bge QwordLoop ; loop until the byte counter goes negative
|
||||
|
||||
AlignedFinished
|
||||
adds r2, r2, #4 ; add 4 to recover a potential >= 4-byte tail
|
||||
blt AlignedFinished2
|
||||
ldr r3, [r1], #4
|
||||
str r3, [r0], #4
|
||||
b MaybeExitMemCpy
|
||||
AlignedFinished2
|
||||
adds r2, r2, #4 ; add 4 more to the byte counter to recover
|
||||
|
||||
MaybeExitMemCpy
|
||||
beq ExitMemCpy ; the remaining count
|
||||
|
||||
ByteLoop2
|
||||
subs r2, r2, #1 ; decrement the counter
|
||||
ldrb r3, [r1], #1 ; copy one byte
|
||||
strb r3, [r0], #1
|
||||
bne ByteLoop2 ; loop until the counter hits 0
|
||||
|
||||
ExitMemCpy
|
||||
bx lr
|
||||
|
||||
LEAF_END_MARKED JIT_MemCpy
|
||||
|
||||
END
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
; Licensed to the .NET Foundation under one or more agreements.
|
||||
; The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#include "ksarm.h"
|
||||
|
||||
#include "asmconstants.h"
|
||||
|
||||
#include "asmmacros.h"
|
||||
|
||||
|
||||
IMPORT VarargPInvokeStubWorker
|
||||
IMPORT GenericPInvokeCalliStubWorker
|
||||
IMPORT JIT_PInvokeEndRarePath
|
||||
|
||||
IMPORT s_gsCookie
|
||||
IMPORT g_TrapReturningThreads
|
||||
|
||||
SETALIAS InlinedCallFrame_vftable, ??_7InlinedCallFrame@@6B@
|
||||
IMPORT $InlinedCallFrame_vftable
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; Macro to generate PInvoke Stubs.
|
||||
; $__PInvokeStubFuncName : function which calls the actual stub obtained from VASigCookie
|
||||
; $__PInvokeGenStubFuncName : function which generates the IL stubs for PInvoke
|
||||
;
|
||||
; Params :-
|
||||
; $FuncPrefix : prefix of the function name for the stub
|
||||
; Eg. VarargPinvoke, GenericPInvokeCalli
|
||||
; $VASigCookieReg : register which contains the VASigCookie
|
||||
; $SaveFPArgs : "Yes" or "No" . For varidic functions FP Args are not present in FP regs
|
||||
; So need not save FP Args registers for vararg Pinvoke
|
||||
MACRO
|
||||
|
||||
PINVOKE_STUB $FuncPrefix,$VASigCookieReg,$SaveFPArgs
|
||||
|
||||
GBLS __PInvokeStubFuncName
|
||||
GBLS __PInvokeGenStubFuncName
|
||||
GBLS __PInvokeStubWorkerName
|
||||
|
||||
IF "$FuncPrefix" == "GenericPInvokeCalli"
|
||||
__PInvokeStubFuncName SETS "$FuncPrefix":CC:"Helper"
|
||||
ELSE
|
||||
__PInvokeStubFuncName SETS "$FuncPrefix":CC:"Stub"
|
||||
ENDIF
|
||||
__PInvokeGenStubFuncName SETS "$FuncPrefix":CC:"GenILStub"
|
||||
__PInvokeStubWorkerName SETS "$FuncPrefix":CC:"StubWorker"
|
||||
|
||||
IF "$VASigCookieReg" == "r1"
|
||||
__PInvokeStubFuncName SETS "$__PInvokeStubFuncName":CC:"_RetBuffArg"
|
||||
__PInvokeGenStubFuncName SETS "$__PInvokeGenStubFuncName":CC:"_RetBuffArg"
|
||||
ENDIF
|
||||
|
||||
NESTED_ENTRY $__PInvokeStubFuncName
|
||||
|
||||
; save reg value before using the reg
|
||||
PROLOG_PUSH {$VASigCookieReg}
|
||||
|
||||
; get the stub
|
||||
ldr $VASigCookieReg, [$VASigCookieReg,#VASigCookie__pNDirectILStub]
|
||||
|
||||
; if null goto stub generation
|
||||
cbz $VASigCookieReg, %0
|
||||
|
||||
EPILOG_STACK_FREE 4
|
||||
|
||||
EPILOG_BRANCH_REG $VASigCookieReg
|
||||
|
||||
0
|
||||
|
||||
EPILOG_POP {$VASigCookieReg}
|
||||
EPILOG_BRANCH $__PInvokeGenStubFuncName
|
||||
|
||||
NESTED_END
|
||||
|
||||
|
||||
NESTED_ENTRY $__PInvokeGenStubFuncName
|
||||
|
||||
PROLOG_WITH_TRANSITION_BLOCK 0, $SaveFPArgs
|
||||
|
||||
; r2 = UnmanagedTarget\ MethodDesc
|
||||
mov r2, r12
|
||||
|
||||
; r1 = VaSigCookie
|
||||
IF "$VASigCookieReg" != "r1"
|
||||
mov r1, $VASigCookieReg
|
||||
ENDIF
|
||||
|
||||
; r0 = pTransitionBlock
|
||||
add r0, sp, #__PWTB_TransitionBlock
|
||||
|
||||
; save hidden arg
|
||||
mov r4, r12
|
||||
|
||||
bl $__PInvokeStubWorkerName
|
||||
|
||||
; restore hidden arg (method desc or unmanaged target)
|
||||
mov r12, r4
|
||||
|
||||
EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
|
||||
|
||||
EPILOG_BRANCH $__PInvokeStubFuncName
|
||||
|
||||
NESTED_END
|
||||
|
||||
MEND
|
||||
|
||||
|
||||
|
||||
TEXTAREA
|
||||
; ------------------------------------------------------------------
|
||||
; JIT_PInvokeBegin helper
|
||||
;
|
||||
; in:
|
||||
; r0 = InlinedCallFrame*: pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
|
||||
; before actual InlinedCallFrame data)
|
||||
;
|
||||
LEAF_ENTRY JIT_PInvokeBegin
|
||||
|
||||
ldr r1, =s_gsCookie
|
||||
ldr r1, [r1]
|
||||
str r1, [r0]
|
||||
add r0, r0, SIZEOF__GSCookie
|
||||
|
||||
;; r0 = pFrame
|
||||
|
||||
;; set first slot to the value of InlinedCallFrame::`vftable' (checked by runtime code)
|
||||
ldr r1, =$InlinedCallFrame_vftable
|
||||
str r1, [r0]
|
||||
|
||||
mov r1, 0
|
||||
str r1, [r0, #InlinedCallFrame__m_Datum]
|
||||
|
||||
str sp, [r0, #InlinedCallFrame__m_pCallSiteSP]
|
||||
str r11, [r0, #InlinedCallFrame__m_pCalleeSavedFP]
|
||||
str lr, [r0, #InlinedCallFrame__m_pCallerReturnAddress]
|
||||
str r9, [r0, #InlinedCallFrame__m_pSPAfterProlog]
|
||||
|
||||
;; r1 = GetThread(), TRASHES r2
|
||||
INLINE_GETTHREAD r1, r2
|
||||
|
||||
;; pFrame->m_Next = pThread->m_pFrame;
|
||||
ldr r2, [r1, #Thread_m_pFrame]
|
||||
str r2, [r0, #Frame__m_Next]
|
||||
|
||||
;; pThread->m_pFrame = pFrame;
|
||||
str r0, [r1, #Thread_m_pFrame]
|
||||
|
||||
;; pThread->m_fPreemptiveGCDisabled = 0
|
||||
mov r2, 0
|
||||
str r2, [r1, #Thread_m_fPreemptiveGCDisabled]
|
||||
|
||||
bx lr
|
||||
|
||||
LEAF_END
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; JIT_PInvokeEnd helper
|
||||
;
|
||||
; in:
|
||||
; r0 = InlinedCallFrame*
|
||||
;
|
||||
LEAF_ENTRY JIT_PInvokeEnd
|
||||
|
||||
add r0, r0, SIZEOF__GSCookie
|
||||
|
||||
;; r1 = GetThread(), TRASHES r2
|
||||
INLINE_GETTHREAD r1, r2
|
||||
|
||||
;; r0 = pFrame
|
||||
;; r1 = pThread
|
||||
|
||||
;; pThread->m_fPreemptiveGCDisabled = 1
|
||||
mov r2, 1
|
||||
str r2, [r1, #Thread_m_fPreemptiveGCDisabled]
|
||||
|
||||
;; Check return trap
|
||||
ldr r2, =g_TrapReturningThreads
|
||||
ldr r2, [r2]
|
||||
cbnz r2, RarePath
|
||||
|
||||
;; pThread->m_pFrame = pFrame->m_Next
|
||||
ldr r2, [r0, #Frame__m_Next]
|
||||
str r2, [r1, #Thread_m_pFrame]
|
||||
|
||||
bx lr
|
||||
|
||||
RarePath
|
||||
b JIT_PInvokeEndRarePath
|
||||
|
||||
LEAF_END
|
||||
|
||||
INLINE_GETTHREAD_CONSTANT_POOL
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; VarargPInvokeStub & VarargPInvokeGenILStub
|
||||
; There is a separate stub when the method has a hidden return buffer arg.
|
||||
;
|
||||
; in:
|
||||
; r0 = VASigCookie*
|
||||
; r12 = MethodDesc *
|
||||
;
|
||||
PINVOKE_STUB VarargPInvoke, r0, {false}
|
||||
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; GenericPInvokeCalliHelper & GenericPInvokeCalliGenILStub
|
||||
; Helper for generic pinvoke calli instruction
|
||||
;
|
||||
; in:
|
||||
; r4 = VASigCookie*
|
||||
; r12 = Unmanaged target
|
||||
;
|
||||
PINVOKE_STUB GenericPInvokeCalli, r4, {true}
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; VarargPInvokeStub_RetBuffArg & VarargPInvokeGenILStub_RetBuffArg
|
||||
; Vararg PInvoke Stub when the method has a hidden return buffer arg
|
||||
;
|
||||
; in:
|
||||
; r1 = VASigCookie*
|
||||
; r12 = MethodDesc*
|
||||
;
|
||||
PINVOKE_STUB VarargPInvoke, r1, {false}
|
||||
|
||||
|
||||
; Must be at very end of file
|
||||
END
|
File diff suppressed because it is too large
Load diff
|
@ -32,10 +32,6 @@ struct ArgLocDesc;
|
|||
|
||||
extern PCODE GetPreStubEntryPoint();
|
||||
|
||||
#ifndef TARGET_UNIX
|
||||
#define USE_REDIRECT_FOR_GCSTRESS
|
||||
#endif // TARGET_UNIX
|
||||
|
||||
// CPU-dependent functions
|
||||
Stub * GenerateInitPInvokeFrameHelper();
|
||||
|
||||
|
@ -48,10 +44,6 @@ EXTERN_C void checkStack(void);
|
|||
//**********************************************************************
|
||||
|
||||
#define COMMETHOD_PREPAD 12 // # extra bytes to allocate in addition to sizeof(ComCallMethodDesc)
|
||||
#ifdef FEATURE_COMINTEROP
|
||||
#define COMMETHOD_CALL_PRESTUB_SIZE 12
|
||||
#define COMMETHOD_CALL_PRESTUB_ADDRESS_OFFSET 8 // the offset of the call target address inside the prestub
|
||||
#endif // FEATURE_COMINTEROP
|
||||
|
||||
#define STACK_ALIGN_SIZE 4
|
||||
|
||||
|
@ -229,10 +221,6 @@ inline void ClearITState(T_CONTEXT *context) {
|
|||
context->Cpsr = context->Cpsr & 0xf9ff03ff;
|
||||
}
|
||||
|
||||
#ifdef FEATURE_COMINTEROP
|
||||
void emitCOMStubCall (ComCallMethodDesc *pCOMMethodRX, ComCallMethodDesc *pCOMMethodRW, PCODE target);
|
||||
#endif // FEATURE_COMINTEROP
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void emitUnconditionalBranchThumb(LPBYTE pBuffer, int16_t offset)
|
||||
{
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
; Licensed to the .NET Foundation under one or more agreements.
|
||||
; The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#include "ksarm.h"
|
||||
|
||||
#include "asmconstants.h"
|
||||
|
||||
#include "asmmacros.h"
|
||||
|
||||
IMPORT HijackHandler
|
||||
IMPORT ThrowControlForThread
|
||||
|
||||
;
|
||||
; WARNING!! These functions immediately ruin thread unwindability. This is
|
||||
; WARNING!! OK as long as there is a mechanism for saving the thread context
|
||||
; WARNING!! prior to running these functions as well as a mechanism for
|
||||
; WARNING!! restoring the context prior to any stackwalk. This means that
|
||||
; WARNING!! we need to ensure that no GC can occur while the stack is
|
||||
; WARNING!! unwalkable. This further means that we cannot allow any exception
|
||||
; WARNING!! to occur when the stack is unwalkable
|
||||
;
|
||||
|
||||
TEXTAREA
|
||||
|
||||
; GSCookie, scratch area
|
||||
GBLA OFFSET_OF_FRAME
|
||||
|
||||
; GSCookie + alignment padding
|
||||
OFFSET_OF_FRAME SETA 4 + SIZEOF__GSCookie
|
||||
|
||||
MACRO
|
||||
GenerateRedirectedStubWithFrame $STUB, $TARGET
|
||||
|
||||
;
|
||||
; This is the primary function to which execution will be redirected to.
|
||||
;
|
||||
NESTED_ENTRY $STUB
|
||||
|
||||
;
|
||||
; IN: lr: original IP before redirect
|
||||
;
|
||||
|
||||
PROLOG_PUSH {r4,r7,lr}
|
||||
PROLOG_STACK_ALLOC OFFSET_OF_FRAME + SIZEOF__FaultingExceptionFrame
|
||||
|
||||
; At this point, the stack maybe misaligned if the thread abort was asynchronously
|
||||
; triggered in the prolog or epilog of the managed method. For such a case, we must
|
||||
; align the stack before calling into the VM.
|
||||
;
|
||||
; Runtime check for 8-byte alignment.
|
||||
PROLOG_STACK_SAVE r7
|
||||
and r0, r7, #4
|
||||
sub sp, sp, r0
|
||||
|
||||
; Save pointer to FEF for GetFrameFromRedirectedStubStackFrame
|
||||
add r4, sp, #OFFSET_OF_FRAME
|
||||
|
||||
; Prepare to initialize to NULL
|
||||
mov r1,#0
|
||||
str r1, [r4] ; Initialize vtbl (it is not strictly necessary)
|
||||
str r1, [r4, #FaultingExceptionFrame__m_fFilterExecuted] ; Initialize BOOL for personality routine
|
||||
|
||||
mov r0, r4 ; move the ptr to FEF in R0
|
||||
|
||||
; stack must be 8 byte aligned
|
||||
CHECK_STACK_ALIGNMENT
|
||||
|
||||
bl $TARGET
|
||||
|
||||
; Target should not return.
|
||||
EMIT_BREAKPOINT
|
||||
|
||||
NESTED_END $STUB
|
||||
|
||||
MEND
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
;
|
||||
; Helpers for ThreadAbort exceptions
|
||||
;
|
||||
|
||||
NESTED_ENTRY RedirectForThreadAbort2,,HijackHandler
|
||||
PROLOG_PUSH {r0, lr}
|
||||
|
||||
; stack must be 8 byte aligned
|
||||
CHECK_STACK_ALIGNMENT
|
||||
|
||||
; On entry:
|
||||
;
|
||||
; R0 = Address of FaultingExceptionFrame.
|
||||
;
|
||||
; Invoke the helper to setup the FaultingExceptionFrame and raise the exception
|
||||
bl ThrowControlForThread
|
||||
|
||||
; ThrowControlForThread doesn't return.
|
||||
EMIT_BREAKPOINT
|
||||
|
||||
NESTED_END RedirectForThreadAbort2
|
||||
|
||||
GenerateRedirectedStubWithFrame RedirectForThreadAbort, RedirectForThreadAbort2
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
|
||||
; This helper enables us to call into a funclet after applying the non-volatiles
|
||||
NESTED_ENTRY CallEHFunclet
|
||||
|
||||
PROLOG_PUSH {r4-r11, lr}
|
||||
PROLOG_STACK_ALLOC 4
|
||||
|
||||
; On entry:
|
||||
;
|
||||
; R0 = throwable
|
||||
; R1 = PC to invoke
|
||||
; R2 = address of R4 register in CONTEXT record; used to restore the non-volatile registers of CrawlFrame
|
||||
; R3 = address of the location where the SP of funclet's caller (i.e. this helper) should be saved.
|
||||
;
|
||||
; Save the SP of this function
|
||||
str sp, [r3]
|
||||
; apply the non-volatiles corresponding to the CrawlFrame
|
||||
ldm r2, {r4-r11}
|
||||
; Invoke the funclet
|
||||
blx r1
|
||||
|
||||
EPILOG_STACK_FREE 4
|
||||
EPILOG_POP {r4-r11, pc}
|
||||
|
||||
NESTED_END CallEHFunclet
|
||||
|
||||
; This helper enables us to call into a filter funclet by passing it the CallerSP to lookup the
|
||||
; frame pointer for accessing the locals in the parent method.
|
||||
NESTED_ENTRY CallEHFilterFunclet
|
||||
|
||||
PROLOG_PUSH {lr}
|
||||
PROLOG_STACK_ALLOC 4
|
||||
|
||||
; On entry:
|
||||
;
|
||||
; R0 = throwable
|
||||
; R1 = SP of the caller of the method/funclet containing the filter
|
||||
; R2 = PC to invoke
|
||||
; R3 = address of the location where the SP of funclet's caller (i.e. this helper) should be saved.
|
||||
;
|
||||
; Save the SP of this function
|
||||
str sp, [r3]
|
||||
; Invoke the filter funclet
|
||||
blx r2
|
||||
|
||||
EPILOG_STACK_FREE 4
|
||||
EPILOG_POP {pc}
|
||||
|
||||
NESTED_END CallEHFilterFunclet
|
||||
END
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
; Licensed to the .NET Foundation under one or more agreements.
|
||||
; The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#include "ksarm.h"
|
||||
|
||||
#include "asmconstants.h"
|
||||
|
||||
#include "asmmacros.h"
|
||||
|
||||
|
||||
TEXTAREA
|
||||
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; Start of the writeable code region
|
||||
LEAF_ENTRY JIT_PatchedCodeStart
|
||||
bx lr
|
||||
LEAF_END
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; GC write barrier support.
|
||||
;
|
||||
; GC Write barriers are defined in asmhelpers.asm. The following functions are used to define
|
||||
; patchable location where the write-barriers are copied over at runtime
|
||||
|
||||
LEAF_ENTRY JIT_PatchedWriteBarrierStart
|
||||
; Cannot be empty function to prevent LNK1223
|
||||
bx lr
|
||||
LEAF_END
|
||||
|
||||
; These write barriers are overwritten on the fly
|
||||
; See ValidateWriteBarriers on how the sizes of these should be calculated
|
||||
ALIGN 4
|
||||
LEAF_ENTRY JIT_WriteBarrier
|
||||
SPACE (0x84)
|
||||
LEAF_END_MARKED JIT_WriteBarrier
|
||||
|
||||
ALIGN 4
|
||||
LEAF_ENTRY JIT_CheckedWriteBarrier
|
||||
SPACE (0x9C)
|
||||
LEAF_END_MARKED JIT_CheckedWriteBarrier
|
||||
|
||||
ALIGN 4
|
||||
LEAF_ENTRY JIT_ByRefWriteBarrier
|
||||
SPACE (0xA0)
|
||||
LEAF_END_MARKED JIT_ByRefWriteBarrier
|
||||
|
||||
LEAF_ENTRY JIT_PatchedWriteBarrierLast
|
||||
; Cannot be empty function to prevent LNK1223
|
||||
bx lr
|
||||
LEAF_END
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; End of the writeable code region
|
||||
LEAF_ENTRY JIT_PatchedCodeLast
|
||||
bx lr
|
||||
LEAF_END
|
||||
|
||||
|
||||
; Must be at very end of file
|
||||
END
|
|
@ -280,13 +280,8 @@ void StubLinkerCPU::Init(void)
|
|||
// value of the global into a register.
|
||||
struct WriteBarrierDescriptor
|
||||
{
|
||||
#ifdef TARGET_UNIX
|
||||
DWORD m_funcStartOffset; // Offset to the start of the barrier function relative to this struct address
|
||||
DWORD m_funcEndOffset; // Offset to the end of the barrier function relative to this struct address
|
||||
#else // TARGET_UNIX
|
||||
BYTE * m_pFuncStart; // Pointer to the start of the barrier function
|
||||
BYTE * m_pFuncEnd; // Pointer to the end of the barrier function
|
||||
#endif // TARGET_UNIX
|
||||
DWORD m_dw_g_lowest_address_offset; // Offset of the instruction reading g_lowest_address
|
||||
DWORD m_dw_g_highest_address_offset; // Offset of the instruction reading g_highest_address
|
||||
DWORD m_dw_g_ephemeral_low_offset; // Offset of the instruction reading g_ephemeral_low
|
||||
|
@ -440,21 +435,12 @@ void UpdateGCWriteBarriers(bool postGrow = false)
|
|||
// Iterate through the write barrier patch table created in the .clrwb section
|
||||
// (see write barrier asm code)
|
||||
WriteBarrierDescriptor * pDesc = &g_rgWriteBarrierDescriptors;
|
||||
#ifdef TARGET_UNIX
|
||||
while (pDesc->m_funcStartOffset)
|
||||
#else // TARGET_UNIX
|
||||
while (pDesc->m_pFuncStart)
|
||||
#endif // TARGET_UNIX
|
||||
{
|
||||
// If the write barrier is being currently used (as in copied over to the patchable site)
|
||||
// then read the patch location from the table and use the offset to patch the target asm code
|
||||
#ifdef TARGET_UNIX
|
||||
PBYTE to = FindWBMapping((BYTE *)pDesc + pDesc->m_funcStartOffset);
|
||||
size_t barrierSize = pDesc->m_funcEndOffset - pDesc->m_funcStartOffset;
|
||||
#else // TARGET_UNIX
|
||||
PBYTE to = FindWBMapping(pDesc->m_pFuncStart);
|
||||
size_t barrierSize = pDesc->m_pFuncEnd - pDesc->m_pFuncStart;
|
||||
#endif // TARGET_UNIX
|
||||
if(to)
|
||||
{
|
||||
to = (PBYTE)PCODEToPINSTR((PCODE)GetWriteBarrierCodeLocation(to));
|
||||
|
@ -564,9 +550,6 @@ void LazyMachState::unwindLazyState(LazyMachState* baseState,
|
|||
|
||||
do
|
||||
{
|
||||
#ifndef TARGET_UNIX
|
||||
pvControlPc = Thread::VirtualUnwindCallFrame(&ctx, &nonVolRegPtrs);
|
||||
#else // !TARGET_UNIX
|
||||
#ifdef DACCESS_COMPILE
|
||||
HRESULT hr = DacVirtualUnwind(threadId, &ctx, &nonVolRegPtrs);
|
||||
if (FAILED(hr))
|
||||
|
@ -582,7 +565,6 @@ void LazyMachState::unwindLazyState(LazyMachState* baseState,
|
|||
}
|
||||
#endif // DACCESS_COMPILE
|
||||
pvControlPc = GetIP(&ctx);
|
||||
#endif // !TARGET_UNIX
|
||||
if (funCallDepth > 0)
|
||||
{
|
||||
--funCallDepth;
|
||||
|
@ -1141,21 +1123,17 @@ Stub *GenerateInitPInvokeFrameHelper()
|
|||
ThumbReg regScratch = ThumbReg(6);
|
||||
ThumbReg regR9 = ThumbReg(9);
|
||||
|
||||
#ifdef TARGET_UNIX
|
||||
// Erect frame to perform call to GetThread
|
||||
psl->ThumbEmitProlog(1, sizeof(ArgumentRegisters), FALSE); // Save r4 for aligned stack
|
||||
|
||||
// Save argument registers around the GetThread call. Don't bother with using ldm/stm since this inefficient path anyway.
|
||||
for (int reg = 0; reg < 4; reg++)
|
||||
psl->ThumbEmitStoreRegIndirect(ThumbReg(reg), thumbRegSp, offsetof(ArgumentRegisters, r) + sizeof(*ArgumentRegisters::r) * reg);
|
||||
#endif
|
||||
|
||||
psl->ThumbEmitGetThread(regThread);
|
||||
|
||||
#ifdef TARGET_UNIX
|
||||
for (int reg = 0; reg < 4; reg++)
|
||||
psl->ThumbEmitLoadRegIndirect(ThumbReg(reg), thumbRegSp, offsetof(ArgumentRegisters, r) + sizeof(*ArgumentRegisters::r) * reg);
|
||||
#endif
|
||||
|
||||
// mov [regFrame + FrameInfo.offsetOfGSCookie], GetProcessGSCookie()
|
||||
psl->ThumbEmitMovConstant(regScratch, GetProcessGSCookie());
|
||||
|
@ -1180,27 +1158,16 @@ Stub *GenerateInitPInvokeFrameHelper()
|
|||
psl->ThumbEmitMovConstant(regScratch, 0);
|
||||
psl->ThumbEmitStoreRegIndirect(regScratch, regFrame, FrameInfo.offsetOfReturnAddress - negSpace);
|
||||
|
||||
#ifdef TARGET_UNIX
|
||||
DWORD cbSavedRegs = sizeof(ArgumentRegisters) + 2 * 4; // r0-r3, r4, lr
|
||||
psl->ThumbEmitAdd(regScratch, thumbRegSp, cbSavedRegs);
|
||||
psl->ThumbEmitStoreRegIndirect(regScratch, regFrame, FrameInfo.offsetOfCallSiteSP - negSpace);
|
||||
#else
|
||||
// str SP, [regFrame + FrameInfo.offsetOfCallSiteSP]
|
||||
psl->ThumbEmitStoreRegIndirect(thumbRegSp, regFrame, FrameInfo.offsetOfCallSiteSP - negSpace);
|
||||
#endif
|
||||
|
||||
// mov [regThread + offsetof(Thread, m_pFrame)], regFrame
|
||||
psl->ThumbEmitStoreRegIndirect(regFrame, regThread, offsetof(Thread, m_pFrame));
|
||||
|
||||
// leave current Thread in R4
|
||||
|
||||
#ifdef TARGET_UNIX
|
||||
psl->ThumbEmitEpilog();
|
||||
#else
|
||||
// Return. The return address has been restored into LR at this point.
|
||||
// bx lr
|
||||
psl->ThumbEmitJumpRegister(thumbRegLr);
|
||||
#endif
|
||||
|
||||
// A single process-wide stub that will never unload
|
||||
RETURN psl->Link(SystemDomain::GetGlobalLoaderAllocator()->GetStubHeap());
|
||||
|
@ -1208,8 +1175,6 @@ Stub *GenerateInitPInvokeFrameHelper()
|
|||
|
||||
void StubLinkerCPU::ThumbEmitGetThread(ThumbReg dest)
|
||||
{
|
||||
#ifdef TARGET_UNIX
|
||||
|
||||
ThumbEmitMovConstant(ThumbReg(0), (TADDR)GetThreadHelper);
|
||||
|
||||
ThumbEmitCallRegister(ThumbReg(0));
|
||||
|
@ -1218,20 +1183,6 @@ void StubLinkerCPU::ThumbEmitGetThread(ThumbReg dest)
|
|||
{
|
||||
ThumbEmitMovRegReg(dest, ThumbReg(0));
|
||||
}
|
||||
|
||||
#else // TARGET_UNIX
|
||||
|
||||
// mrc p15, 0, dest, c13, c0, 2
|
||||
Emit16(0xee1d);
|
||||
Emit16((WORD)(0x0f50 | (dest << 12)));
|
||||
|
||||
ThumbEmitLoadRegIndirect(dest, dest, offsetof(TEB, ThreadLocalStoragePointer));
|
||||
|
||||
ThumbEmitLoadRegIndirect(dest, dest, sizeof(void *) * _tls_index);
|
||||
|
||||
ThumbEmitLoadRegIndirect(dest, dest, (int)Thread::GetOffsetOfThreadStatic(&gCurrentThreadInfo));
|
||||
|
||||
#endif // TARGET_UNIX
|
||||
}
|
||||
|
||||
|
||||
|
@ -1819,34 +1770,6 @@ VOID ResetCurrentContext()
|
|||
#endif // !DACCESS_COMPILE
|
||||
|
||||
|
||||
#ifdef FEATURE_COMINTEROP
|
||||
void emitCOMStubCall (ComCallMethodDesc *pCOMMethodRX, ComCallMethodDesc *pCOMMethodRW, PCODE target)
|
||||
{
|
||||
WRAPPER_NO_CONTRACT;
|
||||
|
||||
// mov r12, pc
|
||||
// ldr pc, [pc, #0]
|
||||
// dcd 0
|
||||
// dcd target
|
||||
WORD rgCode[] = {
|
||||
0x46fc,
|
||||
0xf8df, 0xf004
|
||||
};
|
||||
|
||||
BYTE *pBufferRX = (BYTE*)pCOMMethodRX - COMMETHOD_CALL_PRESTUB_SIZE;
|
||||
BYTE *pBufferRW = (BYTE*)pCOMMethodRW - COMMETHOD_CALL_PRESTUB_SIZE;
|
||||
|
||||
memcpy(pBufferRW, rgCode, sizeof(rgCode));
|
||||
*((PCODE*)(pBufferRW + sizeof(rgCode) + 2)) = target;
|
||||
|
||||
// Ensure that the updated instructions get actually written
|
||||
ClrFlushInstructionCache(pBufferRX, COMMETHOD_CALL_PRESTUB_SIZE);
|
||||
|
||||
_ASSERTE(IS_ALIGNED(pBufferRX + COMMETHOD_CALL_PRESTUB_ADDRESS_OFFSET, sizeof(void*)) &&
|
||||
*((PCODE*)(pBufferRX + COMMETHOD_CALL_PRESTUB_ADDRESS_OFFSET)) == target);
|
||||
}
|
||||
#endif // FEATURE_COMINTEROP
|
||||
|
||||
void MovRegImm(BYTE* p, int reg, TADDR imm)
|
||||
{
|
||||
LIMITED_METHOD_CONTRACT;
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
; Licensed to the .NET Foundation under one or more agreements.
|
||||
; The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#include "ksarm.h"
|
||||
#include "asmconstants.h"
|
||||
#include "asmmacros.h"
|
||||
|
||||
|
||||
TEXTAREA
|
||||
|
||||
ALIGN 4
|
||||
|
||||
#define DATA_SLOT(stub, field) stub##Code + PAGE_SIZE + stub##Data__##field
|
||||
|
||||
LEAF_ENTRY StubPrecodeCode
|
||||
ldr r12, DATA_SLOT(StubPrecode, MethodDesc)
|
||||
ldr pc, DATA_SLOT(StubPrecode, Target)
|
||||
LEAF_END_MARKED StubPrecodeCode
|
||||
|
||||
ALIGN 4
|
||||
|
||||
LEAF_ENTRY FixupPrecodeCode
|
||||
ldr pc, DATA_SLOT(FixupPrecode, Target)
|
||||
ldr r12, DATA_SLOT(FixupPrecode, MethodDesc)
|
||||
ldr pc, DATA_SLOT(FixupPrecode, PrecodeFixupThunk)
|
||||
LEAF_END_MARKED FixupPrecodeCode
|
||||
|
||||
ALIGN 4
|
||||
|
||||
LEAF_ENTRY CallCountingStubCode
|
||||
push {r0}
|
||||
ldr r12, DATA_SLOT(CallCountingStub, RemainingCallCountCell)
|
||||
ldrh r0, [r12]
|
||||
subs r0, r0, #1
|
||||
strh r0, [r12]
|
||||
pop {r0}
|
||||
beq CountReachedZero
|
||||
ldr pc, DATA_SLOT(CallCountingStub, TargetForMethod)
|
||||
CountReachedZero
|
||||
ldr pc, DATA_SLOT(CallCountingStub, TargetForThresholdReached)
|
||||
LEAF_END_MARKED CallCountingStubCode
|
||||
|
||||
END
|
|
@ -48,7 +48,7 @@ if(CLR_CMAKE_TARGET_WIN32)
|
|||
)
|
||||
endif()
|
||||
|
||||
# Specify non-default Windows libs to be used for Arm/Arm64 builds
|
||||
if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_ARM64))
|
||||
# Specify non-default Windows libs to be used for Arm64 builds
|
||||
if (CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_TARGET_ARCH_ARM64)
|
||||
target_link_libraries(apphost PRIVATE shell32.lib)
|
||||
endif()
|
||||
|
|
|
@ -30,7 +30,6 @@ if /i [%1] == [Checked] (set CMAKE_BUILD_TYPE=Checked&&shift&goto Arg_Loop)
|
|||
|
||||
if /i [%1] == [AnyCPU] (set __BuildArch=x64&&shift&goto Arg_Loop)
|
||||
if /i [%1] == [x86] (set __BuildArch=x86&&shift&goto Arg_Loop)
|
||||
if /i [%1] == [arm] (set __BuildArch=arm&&shift&goto Arg_Loop)
|
||||
if /i [%1] == [x64] (set __BuildArch=x64&&shift&goto Arg_Loop)
|
||||
if /i [%1] == [amd64] (set __BuildArch=x64&&shift&goto Arg_Loop)
|
||||
if /i [%1] == [arm64] (set __BuildArch=arm64&&shift&goto Arg_Loop)
|
||||
|
@ -94,7 +93,6 @@ if not exist "%__IntermediatesDir%" md "%__IntermediatesDir%"
|
|||
|
||||
if /i "%__BuildArch%" == "x64" (set cm_BaseRid=win7)
|
||||
if /i "%__BuildArch%" == "x86" (set cm_BaseRid=win7)
|
||||
if /i "%__BuildArch%" == "arm" (set cm_BaseRid=win8)
|
||||
if /i "%__BuildArch%" == "arm64" (set cm_BaseRid=win10)
|
||||
:: Form the base RID to be used if we are doing a portable build
|
||||
if /i "%__PortableBuild%" == "1" (set cm_BaseRid=win)
|
||||
|
|
|
@ -32,7 +32,7 @@ add_definitions(-DFEATURE_LIBHOST=1)
|
|||
convert_to_absolute_path(SOURCES ${SOURCES})
|
||||
convert_to_absolute_path(ASM_HELPERS_SOURCES ${ASM_HELPERS_SOURCES})
|
||||
|
||||
if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_ARM64))
|
||||
if (CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_TARGET_ARCH_ARM64)
|
||||
preprocess_files(ASM_HELPERS_SOURCES ${ASM_HELPERS_SOURCES})
|
||||
if (CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
compile_asm(TARGET ijwhost ASM_FILES ${ASM_HELPERS_SOURCES} OUTPUT_OBJECTS ASM_HELPERS_SOURCES)
|
||||
|
@ -47,8 +47,8 @@ list(APPEND SOURCES ${ASM_HELPERS_SOURCES})
|
|||
|
||||
include(../lib.cmake)
|
||||
|
||||
# Specify non-default Windows libs to be used for Arm/Arm64 builds
|
||||
if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_ARM64))
|
||||
# Specify non-default Windows libs to be used for Arm64 builds
|
||||
if (CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_TARGET_ARCH_ARM64)
|
||||
target_link_libraries(ijwhost PRIVATE Ole32.lib)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
; Licensed to the .NET Foundation under one or more agreements.
|
||||
; The .NET Foundation licenses this file to you under the MIT license.
|
||||
;
|
||||
|
||||
#include "ksarm.h"
|
||||
|
||||
TEXTAREA
|
||||
|
||||
EXTERN start_runtime_and_get_target_address
|
||||
|
||||
;; Common code called from a bootstrap_thunk to call start_runtime_and_get_target_address and obtain the
|
||||
;; real target address to which to tail call.
|
||||
;;
|
||||
;; On entry:
|
||||
;; r12 : parameter provided by the thunk that points back into the thunk itself
|
||||
;; other argument registers and possibly stack locations set up ready to make the real call
|
||||
;;
|
||||
;; On exit:
|
||||
;; tail calls to the real target method
|
||||
;;
|
||||
CFG_ALIGN
|
||||
NESTED_ENTRY start_runtime_thunk_stub
|
||||
|
||||
PROLOG_PUSH {r0-r3} ; Save general argument registers
|
||||
PROLOG_PUSH {r4,lr} ; Save return address (r4 is saved simply to preserve stack alignment)
|
||||
PROLOG_VPUSH {d0-d7} ; Save floating point argument registers
|
||||
|
||||
mov r0, r12 ; Only argument to start_runtime_and_get_target_address is the hidden thunk parameter
|
||||
bl start_runtime_and_get_target_address
|
||||
|
||||
mov r12, r0 ; Preserve result (real target address)
|
||||
|
||||
EPILOG_VPOP {d0-d7} ; Restore floating point argument registers
|
||||
EPILOG_POP {r4,lr} ; Restore return address
|
||||
EPILOG_POP {r0-r3} ; Restore general argument registers
|
||||
|
||||
EPILOG_BRANCH_REG r12 ; Tail call to real target
|
||||
|
||||
NESTED_END
|
||||
|
||||
END
|
|
@ -1,81 +0,0 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#include "bootstrap_thunk.h"
|
||||
#include "corhdr.h"
|
||||
#include "pal.h"
|
||||
|
||||
//=================================================================================
|
||||
// Get thunk from the address that the thunk code provided
|
||||
bootstrap_thunk *bootstrap_thunk::get_thunk_from_cookie(std::uintptr_t cookie)
|
||||
{
|
||||
|
||||
// Cookie is generated via the first thunk instruction:
|
||||
// mov r12, pc
|
||||
// The pc is returned from the hardware as the pc at the start of the instruction (i.e. the thunk address)
|
||||
// + 4. So we can recover the thunk address simply by subtracting 4 from the cookie.
|
||||
return (bootstrap_thunk *)(cookie - 4);
|
||||
}
|
||||
|
||||
//=================================================================================
|
||||
// Get thunk from the thunk code entry point address
|
||||
bootstrap_thunk *bootstrap_thunk::get_thunk_from_entrypoint(std::uintptr_t entryAddr)
|
||||
{
|
||||
// The entry point is at the start of the thunk but the code address will have the low-order bit set to
|
||||
// indicate Thumb code and we need to mask that out.
|
||||
return (bootstrap_thunk *)(entryAddr & ~1);
|
||||
}
|
||||
|
||||
//=================================================================================
|
||||
// Returns the slot address of the vtable entry for this thunk
|
||||
std::uintptr_t *bootstrap_thunk::get_slot_address()
|
||||
{
|
||||
return m_slot;
|
||||
}
|
||||
|
||||
//=================================================================================
|
||||
// Returns the pal::dll_t for this thunk's module
|
||||
pal::dll_t bootstrap_thunk::get_dll_handle()
|
||||
{
|
||||
return m_dll;
|
||||
}
|
||||
|
||||
//=================================================================================
|
||||
// Returns the token of this thunk
|
||||
std::uint32_t bootstrap_thunk::get_token()
|
||||
{
|
||||
return m_token;
|
||||
}
|
||||
|
||||
//=================================================================================
|
||||
std::uintptr_t bootstrap_thunk::get_entrypoint()
|
||||
{
|
||||
// Set the low-order bit of the address returned to indicate to the hardware that it's Thumb code.
|
||||
return (std::uintptr_t)this | 1;
|
||||
}
|
||||
|
||||
//=================================================================================
|
||||
// Initializes the thunk to point to the bootstrap helper that will load the
|
||||
// runtime and perform the real thunk initialization.
|
||||
//
|
||||
void bootstrap_thunk::initialize(std::uintptr_t pThunkInitFcn,
|
||||
pal::dll_t dll,
|
||||
std::uint32_t token,
|
||||
std::uintptr_t *pSlot)
|
||||
{
|
||||
|
||||
// Initialize code section of the thunk:
|
||||
WORD rgCode[] = {
|
||||
0x46fc, // mov r12, pc
|
||||
0xf8df, 0xf004, // ldr pc, [pc, #4]
|
||||
0x0000 // padding for 4-byte alignment of target address that follows
|
||||
};
|
||||
BYTE *pCode = (BYTE*)this;
|
||||
memcpy(pCode, rgCode, sizeof(rgCode));
|
||||
pCode += sizeof(rgCode);
|
||||
*(std::uintptr_t*)pCode = pThunkInitFcn;
|
||||
|
||||
m_dll = dll;
|
||||
m_slot = pSlot;
|
||||
m_token = token;
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#ifndef IJW_BOOTSTRAP_THUNK_H
|
||||
#define IJW_BOOTSTRAP_THUNK_H
|
||||
|
||||
#if !defined(TARGET_ARM)
|
||||
#error "This file should only be included on arm builds."
|
||||
#endif
|
||||
|
||||
#include "pal.h"
|
||||
#include "corhdr.h"
|
||||
|
||||
extern "C" void start_runtime_thunk_stub();
|
||||
|
||||
#include <pshpack1.h>
|
||||
//=================================================================================
|
||||
class bootstrap_thunk
|
||||
{
|
||||
private:
|
||||
WORD m_rgCode[4];
|
||||
std::uintptr_t m_pBootstrapCode;
|
||||
|
||||
pal::dll_t m_dll; // pal::dll_t of this module
|
||||
std::uintptr_t* m_slot; // VTable slot for this thunk
|
||||
std::uint32_t m_token; // Token for this thunk
|
||||
|
||||
public:
|
||||
// Get thunk from the address that the thunk code provided
|
||||
static bootstrap_thunk *get_thunk_from_cookie(std::uintptr_t cookie);
|
||||
|
||||
// Get thunk from the thunk code entry point address
|
||||
static bootstrap_thunk *get_thunk_from_entrypoint(std::uintptr_t entryAddr);
|
||||
|
||||
// Initializes the thunk to point to pThunkInitFcn that will load the
|
||||
// runtime and perform the real thunk initialization.
|
||||
void initialize(std::uintptr_t pThunkInitFcn,
|
||||
pal::dll_t dll,
|
||||
std::uint32_t token,
|
||||
std::uintptr_t *pSlot);
|
||||
|
||||
// Returns the slot address of the vtable entry for this thunk
|
||||
std::uintptr_t *get_slot_address();
|
||||
|
||||
// Returns the pal::dll_t for this thunk's module
|
||||
pal::dll_t get_dll_handle();
|
||||
|
||||
// Returns the token of this thunk
|
||||
std::uint32_t get_token();
|
||||
|
||||
std::uintptr_t get_entrypoint();
|
||||
};
|
||||
#include <poppack.h>
|
||||
|
||||
#endif
|
|
@ -70,7 +70,6 @@ if /i "%1" == "--" (set processedArgs=!processedArgs! %1&s
|
|||
@REM The following arguments do not support '/', '-', or '--' prefixes
|
||||
if /i "%1" == "x64" (set __BuildArch=x64&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
|
||||
if /i "%1" == "x86" (set __BuildArch=x86&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
|
||||
if /i "%1" == "arm" (set __BuildArch=arm&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
|
||||
if /i "%1" == "arm64" (set __BuildArch=arm64&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
|
||||
|
||||
if /i "%1" == "debug" (set __BuildType=Debug&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
|
||||
|
@ -371,7 +370,7 @@ echo All arguments are optional and case-insensitive, and the '-' prefix is opti
|
|||
echo.
|
||||
echo.-? -h --help: View this message.
|
||||
echo.
|
||||
echo Build architecture: one of "x64", "x86", "arm", "arm64" ^(default: x64^).
|
||||
echo Build architecture: one of "x64", "x86", "arm64" ^(default: x64^).
|
||||
echo Build type: one of "Debug", "Checked", "Release" ^(default: Debug^).
|
||||
echo.
|
||||
echo -Rebuild: Clean up all test artifacts prior to building tests.
|
||||
|
|
|
@ -294,235 +294,6 @@
|
|||
</ExcludeList>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Windows arm32 specific excludes -->
|
||||
<ItemGroup Condition="'$(XunitTestBinBase)' != '' and ('$(TargetArchitecture)' == 'arm' or '$(AltJitArch)' == 'arm') and '$(TargetsWindows)' == 'true' and '$(RuntimeFlavor)' == 'coreclr'">
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/Convert/out_of_range_fp_to_int_conversions/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/49184</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NETClients/Primitives/NETClientPrimitives/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/11360</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NETClients/Primitives/NETClientPrimitivesInALC/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/11360</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NativeClients/Primitives/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/11360</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NativeClients/Dispatch/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/11360</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NETClients/Lifetime/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/11360</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NativeClients/Licensing/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/11360</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NativeClients/DefaultInterfaces/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/11360</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NETClients/IDispatch/NETClientIDispatch/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/11360</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NETClients/Aggregation/NETClientAggregation/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/11360</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NETClients/Licensing/NETClientLicense/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/11360</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NETClients/ConsumeNETServer/ConsumeNETServer/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/11360</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XUnitTestBinBase)/JIT/Directed/callconv/ThisCall/ThisCallTest/*">
|
||||
<Issue>Native member function calling conventions not supported on Windows ARM32.</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XUnitTestBinBase)/JIT/Directed/callconv/StdCallMemberFunction/StdCallMemberFunctionTest/*">
|
||||
<Issue>Native member function calling conventions not supported on Windows ARM32.</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XUnitTestBinBase)/JIT/Directed/callconv/PlatformDefaultMemberFunction/PlatformDefaultMemberFunctionTest/*">
|
||||
<Issue>Native member function calling conventions not supported on Windows ARM32.</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XUnitTestBinBase)/JIT/Directed/callconv/CdeclMemberFunction/CdeclMemberFunctionTest/*">
|
||||
<Issue>Native member function calling conventions not supported on Windows ARM32.</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M13-RTM/b88793/b88793/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M12-Beta2/b37646/b37646/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/PREFIX/unaligned/1/arglist_Target_ARM_unaligned_1/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b41391/b41391/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i00/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i70/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i32/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i51/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b32374/b32374/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/Interop/PInvoke/Varargs/VarargsTest/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/PREFIX/volatile/1/arglist_Target_ARM_volatile/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b28901/b28901/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i82/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i80/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/gc/misc/funclet/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b30864/b30864/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b30838/b30838/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical/refany/seq_il_r/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i61/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i60/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i31/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-EJIT/V1-M12-Beta2/b26323/b26323/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b26324/b26324a/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b26324/b26324b/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i50/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i62/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b36472/b36472/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i72/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b37598/b37598/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b46867/b46867/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V2.0-Beta2/b409748/b409748/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i30/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b16423/b16423/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/PREFIX/unaligned/2/arglist_Target_ARM_unaligned_2/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical/refany/seq_il_d/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical/Coverage/arglist_pos/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b35784/b35784/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M12-Beta2/b31746/b31746/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i12/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i52/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i81/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i11/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M12-Beta2/b41852/b41852/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i02/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i01/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i71/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M12-Beta2/b31745/b31745/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V1-M13-RTM/b91248/b91248/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/JitBlue/Runtime_56953/Runtime_56953/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/67870</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/JitBlue/Runtime_57606/Runtime_57606/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/PREFIX/unaligned/4/arglist_Target_ARM_unaligned_4/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i10/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/12979</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/regress/vsw/373472/**">
|
||||
<Issue>Allocates large contiguous array that is not consistently available on 32-bit platforms</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/Regressions/coreclr/GitHub_45929/test45929/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/60152</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Stress/ABI/pinvokes_d/**">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/66745</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/Stress/ABI/pinvokes_do/**">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/66745</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/profiler/elt/slowpatheltenter/**">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/84750</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/profiler/elt/slowpatheltleave/**">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/84750</Issue>
|
||||
</ExcludeList>
|
||||
<ExcludeList Include="$(XunitTestBinBase)/tracing/eventpipe/eventsourceerror/eventsourceerror/*">
|
||||
<Issue>https://github.com/dotnet/runtime/issues/81241</Issue>
|
||||
</ExcludeList>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Windows arm64 specific excludes -->
|
||||
<ItemGroup Condition="'$(XunitTestBinBase)' != '' and ('$(TargetArchitecture)' == 'arm64' or '$(AltJitArch)' == 'arm64') and '$(TargetsWindows)' == 'true' and '$(RuntimeFlavor)' == 'coreclr'">
|
||||
<ExcludeList Include="$(XunitTestBinBase)/JIT/opt/Tailcall/TailcallVerifyWithPrefix/*">
|
||||
|
|
|
@ -45,7 +45,6 @@ if /i "%1" == "-help" goto Usage
|
|||
|
||||
if /i "%1" == "x64" (set __BuildArch=x64&shift&goto Arg_Loop)
|
||||
if /i "%1" == "x86" (set __BuildArch=x86&shift&goto Arg_Loop)
|
||||
if /i "%1" == "arm" (set __BuildArch=arm&shift&goto Arg_Loop)
|
||||
if /i "%1" == "arm64" (set __BuildArch=arm64&shift&goto Arg_Loop)
|
||||
|
||||
if /i "%1" == "debug" (set __BuildType=Debug&shift&goto Arg_Loop)
|
||||
|
@ -200,7 +199,7 @@ echo.
|
|||
echo where:
|
||||
echo.
|
||||
echo./? -? /h -h /help -help - View this message.
|
||||
echo ^<build_architecture^> - Specifies build architecture: x64, x86, arm, or arm64 ^(default: x64^).
|
||||
echo ^<build_architecture^> - Specifies build architecture: x64, x86, or arm64 ^(default: x64^).
|
||||
echo ^<build_type^> - Specifies build type: Debug, Release, or Checked ^(default: Debug^).
|
||||
echo TestEnv ^<test_env_script^> - Run a custom script before every test to set custom test environment settings.
|
||||
echo sequential - Run tests sequentially ^(no parallelism^).
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue